lagora-cli 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +138 -0
- package/dist/help.txt +70 -0
- package/dist/lagora.js +342 -0
- package/dist/report-help.txt +5 -0
- package/dist/scripts/agora_playground_harness.py +263 -0
- package/dist/scripts/announce.js +41 -0
- package/dist/scripts/check-kernel-submission.py +90 -0
- package/dist/scripts/chunk-2EAJVB5D.js +100 -0
- package/dist/scripts/chunk-2KTLCUFI.js +29 -0
- package/dist/scripts/chunk-AZ3EEBVD.js +137 -0
- package/dist/scripts/chunk-NBJMYAOA.js +2128 -0
- package/dist/scripts/chunk-NCJMUBTG.js +125 -0
- package/dist/scripts/chunk-QJPQHKIO.js +23 -0
- package/dist/scripts/chunk-RIR5KGHC.js +33 -0
- package/dist/scripts/chunk-TJZVQYBL.js +8 -0
- package/dist/scripts/chunk-UHJXD4TG.js +18 -0
- package/dist/scripts/chunk-UQ6I6VTY.js +117 -0
- package/dist/scripts/cli-auth.js +348 -0
- package/dist/scripts/cli-config-IA7EOSYD.js +7 -0
- package/dist/scripts/install-skill.js +199 -0
- package/dist/scripts/issue-local-client-DZUXZOKY.js +22 -0
- package/dist/scripts/issue-search.js +1823 -0
- package/dist/scripts/issue.js +386 -0
- package/dist/scripts/keycloak-provision.js +986 -0
- package/dist/scripts/legato-fsim-runner.py +126 -0
- package/dist/scripts/legato-lowering-runner.py +156 -0
- package/dist/scripts/legato_runner_annotations.py +235 -0
- package/dist/scripts/legato_runner_env.py +91 -0
- package/dist/scripts/legato_runner_launchers.py +287 -0
- package/dist/scripts/legato_runner_script_wrapper.py +193 -0
- package/dist/scripts/notifications-EU43SIEV.js +624 -0
- package/dist/scripts/playground.js +408 -0
- package/dist/scripts/report-bundle-sync-3U7QTP4Z.js +215 -0
- package/dist/scripts/report.js +104 -0
- package/dist/scripts/resolve-sdk-package-version.py +151 -0
- package/dist/scripts/sdk-runtime-JE6H2PB2.js +992 -0
- package/dist/scripts/sdk-runtime-kubernetes-job-KOWL4ITV.js +479 -0
- package/dist/scripts/sdk-runtime-smoke.py +168 -0
- package/dist/scripts/sdk.js +256 -0
- package/dist/scripts/site-feedback-CAPE5MPX.js +136 -0
- package/dist/scripts/site-feedback-rate-limit-5BU2WSFE.js +86 -0
- package/dist/scripts/site-feedback.js +117 -0
- package/dist/scripts/storage-234FBH54.js +67 -0
- package/dist/scripts/submit-issue.sh +489 -0
- package/dist/scripts/verification-3QCY66QW.js +772 -0
- package/dist/scripts/verify-issue.js +144 -0
- package/dist/skills/legato-agora-cli/SKILL.md +556 -0
- package/dist/skills/legato-agora-cli/agents/openai.yaml +7 -0
- package/dist/skills/legato-agora-cli/reference/kernel-with-golden.py +84 -0
- package/dist/skills/legato-site-feedback/SKILL.md +49 -0
- package/dist/skills/legato-site-feedback/agents/openai.yaml +7 -0
- package/package.json +16 -0
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
import {
|
|
2
|
+
addBlockerToStore,
|
|
3
|
+
assignIssueInStore,
|
|
4
|
+
checkoutIssueFromStore,
|
|
5
|
+
fetchIssueFromStore,
|
|
6
|
+
saveSuggestionToStore,
|
|
7
|
+
syncBlockerInStore,
|
|
8
|
+
updateIssueDescriptionInStore,
|
|
9
|
+
updateIssueStatusInStore
|
|
10
|
+
} from "./chunk-NCJMUBTG.js";
|
|
11
|
+
import {
|
|
12
|
+
LagoraCliConfigStore,
|
|
13
|
+
apiSession,
|
|
14
|
+
baseApiUrl,
|
|
15
|
+
readJsonFromApi,
|
|
16
|
+
writeJsonToApi
|
|
17
|
+
} from "./chunk-AZ3EEBVD.js";
|
|
18
|
+
import "./chunk-TJZVQYBL.js";
|
|
19
|
+
|
|
20
|
+
// scripts/issue.ts
|
|
21
|
+
import path2 from "node:path";
|
|
22
|
+
|
|
23
|
+
// scripts/issue-api-client.ts
|
|
24
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
25
|
+
import path from "node:path";
|
|
26
|
+
async function fetchIssueFromApi(issueId, session, format) {
|
|
27
|
+
const endpoint = `${baseApiUrl(session.apiUrl)}/api/issues/${encodeURIComponent(issueId)}/bundle`;
|
|
28
|
+
const bundle = await readBundleFromApi(endpoint, session);
|
|
29
|
+
const issueFile = bundle.files.find((file) => file.path === "issue.json");
|
|
30
|
+
if (!issueFile) throw new Error("Issue bundle response is missing issue.json");
|
|
31
|
+
const parsed = JSON.parse(Buffer.from(issueFile.contentBase64, "base64").toString("utf8"));
|
|
32
|
+
if (!isIssueRecord(parsed)) throw new Error("Issue bundle contains an unsupported issue.json shape");
|
|
33
|
+
const { printIssueRecord } = await import("./issue-local-client-DZUXZOKY.js");
|
|
34
|
+
printIssueRecord(parsed, format);
|
|
35
|
+
}
|
|
36
|
+
function isIssueRecord(value) {
|
|
37
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
38
|
+
const issue = Reflect.get(value, "issue");
|
|
39
|
+
return Boolean(issue) && typeof issue === "object" && !Array.isArray(issue) && Array.isArray(Reflect.get(value, "artifacts")) && Array.isArray(Reflect.get(value, "verificationRuns")) && Boolean(Reflect.get(value, "bundle"));
|
|
40
|
+
}
|
|
41
|
+
async function checkoutIssueFromApi(issueId, apiUrl, out, author, session) {
|
|
42
|
+
const targetRoot = path.resolve(out?.trim() || path.join("lagora-issues", issueId));
|
|
43
|
+
const endpoint = `${baseApiUrl(apiUrl)}/api/issues/${encodeURIComponent(issueId)}/bundle`;
|
|
44
|
+
const initialPayload = await readBundleFromApi(endpoint, session);
|
|
45
|
+
const payload = initialPayload.status === "open" ? await markInvestigatingThenReadBundle({ issueId, apiUrl, author, bundleEndpoint: endpoint, session }) : initialPayload;
|
|
46
|
+
await mkdir(targetRoot, { recursive: true });
|
|
47
|
+
for (const file of payload.files) {
|
|
48
|
+
const filePath = safeOutputPath(targetRoot, file.path);
|
|
49
|
+
await mkdir(path.dirname(filePath), { recursive: true });
|
|
50
|
+
await writeFile(filePath, Buffer.from(file.contentBase64, "base64"));
|
|
51
|
+
}
|
|
52
|
+
console.log(`Issue ${payload.issueId} checked out to ${targetRoot}`);
|
|
53
|
+
}
|
|
54
|
+
async function markInvestigatingThenReadBundle(input) {
|
|
55
|
+
await updateStatusFromApi({
|
|
56
|
+
issueId: input.issueId,
|
|
57
|
+
apiUrl: input.apiUrl,
|
|
58
|
+
author: input.author,
|
|
59
|
+
status: "investigating",
|
|
60
|
+
session: input.session
|
|
61
|
+
});
|
|
62
|
+
return await readBundleFromApi(input.bundleEndpoint, input.session);
|
|
63
|
+
}
|
|
64
|
+
async function addCommentFromApi(input) {
|
|
65
|
+
await writeJsonToApi(`${baseApiUrl(input.apiUrl)}/api/issues/${encodeURIComponent(input.issueId)}/comments`, "POST", {
|
|
66
|
+
author: input.author,
|
|
67
|
+
body: input.body,
|
|
68
|
+
kind: input.kind
|
|
69
|
+
}, input.session);
|
|
70
|
+
console.log(`Comment added to ${input.issueId}`);
|
|
71
|
+
}
|
|
72
|
+
async function updateStatusFromApi(input) {
|
|
73
|
+
await writeJsonToApi(`${baseApiUrl(input.apiUrl)}/api/issues/${encodeURIComponent(input.issueId)}/status`, "PATCH", {
|
|
74
|
+
author: input.author,
|
|
75
|
+
status: input.status
|
|
76
|
+
}, input.session);
|
|
77
|
+
console.log(`Status updated: ${input.issueId} -> ${input.status}`);
|
|
78
|
+
}
|
|
79
|
+
async function updateDescriptionFromApi(input) {
|
|
80
|
+
await writeJsonToApi(`${baseApiUrl(input.apiUrl)}/api/issues/${encodeURIComponent(input.issueId)}/description`, "PATCH", {
|
|
81
|
+
author: input.author,
|
|
82
|
+
description: input.description
|
|
83
|
+
}, input.session);
|
|
84
|
+
console.log(`Description updated for ${input.issueId}`);
|
|
85
|
+
}
|
|
86
|
+
async function saveSuggestionFromApi(input) {
|
|
87
|
+
await writeJsonToApi(`${baseApiUrl(input.apiUrl)}/api/issues/${encodeURIComponent(input.issueId)}/suggestions`, "POST", {
|
|
88
|
+
author: input.author,
|
|
89
|
+
filename: input.filename,
|
|
90
|
+
content: input.content,
|
|
91
|
+
baseArtifactId: input.baseArtifactId ?? "",
|
|
92
|
+
suggestionArtifactId: input.suggestionArtifactId ?? ""
|
|
93
|
+
}, input.session);
|
|
94
|
+
console.log(`${input.suggestionArtifactId ? "Suggestion updated" : "Suggestion added"} for ${input.issueId}`);
|
|
95
|
+
}
|
|
96
|
+
async function assignIssueFromApi(input) {
|
|
97
|
+
await writeJsonToApi(`${baseApiUrl(input.apiUrl)}/api/issues/${encodeURIComponent(input.issueId)}/assignee`, "PATCH", {
|
|
98
|
+
author: input.author,
|
|
99
|
+
assignee: input.assignee
|
|
100
|
+
}, input.session);
|
|
101
|
+
console.log(`Assignee updated: ${input.issueId} -> ${input.assignee || "unassigned"}`);
|
|
102
|
+
}
|
|
103
|
+
async function addBlockerFromApi(input) {
|
|
104
|
+
const payload = await writeJsonToApi(`${baseApiUrl(input.apiUrl)}/api/issues/${encodeURIComponent(input.issueId)}/blockers`, "POST", {
|
|
105
|
+
author: input.author,
|
|
106
|
+
repository: input.repository ?? "",
|
|
107
|
+
number: String(input.number)
|
|
108
|
+
}, input.session);
|
|
109
|
+
const blocker = readBlocker(payload);
|
|
110
|
+
console.log(`Blocker linked: ${input.issueId} -> ${blocker.repository}#${blocker.number} (${blocker.status})`);
|
|
111
|
+
}
|
|
112
|
+
async function syncBlockerFromApi(input) {
|
|
113
|
+
const payload = await writeJsonToApi(`${baseApiUrl(input.apiUrl)}/api/issues/${encodeURIComponent(input.issueId)}/blockers`, "PATCH", {
|
|
114
|
+
author: input.author,
|
|
115
|
+
blockerId: input.blockerId
|
|
116
|
+
}, input.session);
|
|
117
|
+
const blocker = readBlocker(payload);
|
|
118
|
+
console.log(`Blocker synced: ${input.issueId} -> ${blocker.repository}#${blocker.number} (${blocker.status})`);
|
|
119
|
+
}
|
|
120
|
+
async function readBundleFromApi(endpoint, session) {
|
|
121
|
+
const payload = await readJsonFromApi(endpoint, session);
|
|
122
|
+
if (!isApiBundle(payload)) {
|
|
123
|
+
throw new Error("Issue bundle response has an unsupported shape");
|
|
124
|
+
}
|
|
125
|
+
return payload;
|
|
126
|
+
}
|
|
127
|
+
function isApiBundle(value) {
|
|
128
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
const issueId = Reflect.get(value, "issueId");
|
|
132
|
+
const title = Reflect.get(value, "title");
|
|
133
|
+
const status = Reflect.get(value, "status");
|
|
134
|
+
const files = Reflect.get(value, "files");
|
|
135
|
+
return typeof issueId === "string" && typeof title === "string" && isIssueStatus(status) && Array.isArray(files) && files.every(isApiBundleFile);
|
|
136
|
+
}
|
|
137
|
+
function isIssueStatus(value) {
|
|
138
|
+
return value === "open" || value === "investigating" || value === "resolved" || value === "deferred" || value === "cancelled";
|
|
139
|
+
}
|
|
140
|
+
function isApiBundleFile(value) {
|
|
141
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
return typeof Reflect.get(value, "path") === "string" && typeof Reflect.get(value, "contentType") === "string" && typeof Reflect.get(value, "contentBase64") === "string";
|
|
145
|
+
}
|
|
146
|
+
function readBlocker(payload) {
|
|
147
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
|
|
148
|
+
throw new Error("Blocker response has an unsupported shape");
|
|
149
|
+
}
|
|
150
|
+
const blocker = Reflect.get(payload, "blocker");
|
|
151
|
+
if (!isIssueBlocker(blocker)) {
|
|
152
|
+
throw new Error("Blocker response has an unsupported shape");
|
|
153
|
+
}
|
|
154
|
+
return blocker;
|
|
155
|
+
}
|
|
156
|
+
function isIssueBlocker(value) {
|
|
157
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
158
|
+
return typeof Reflect.get(value, "id") === "string" && Reflect.get(value, "kind") === "github-pr" && typeof Reflect.get(value, "repository") === "string" && typeof Reflect.get(value, "number") === "number" && typeof Reflect.get(value, "url") === "string" && isBlockerStatus(Reflect.get(value, "status")) && typeof Reflect.get(value, "addedBy") === "string" && typeof Reflect.get(value, "addedAt") === "string";
|
|
159
|
+
}
|
|
160
|
+
function isBlockerStatus(value) {
|
|
161
|
+
return value === "open" || value === "merged" || value === "closed" || value === "unknown";
|
|
162
|
+
}
|
|
163
|
+
function safeOutputPath(root, relativePath) {
|
|
164
|
+
if (path.isAbsolute(relativePath)) {
|
|
165
|
+
throw new Error(`Absolute bundle path is not allowed: ${relativePath}`);
|
|
166
|
+
}
|
|
167
|
+
const target = path.resolve(root, relativePath);
|
|
168
|
+
if (target !== root && !target.startsWith(`${root}${path.sep}`)) {
|
|
169
|
+
throw new Error(`Bundle path escapes output directory: ${relativePath}`);
|
|
170
|
+
}
|
|
171
|
+
return target;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// scripts/issue-api-notifications.ts
|
|
175
|
+
async function listNotificationsFromApi(session) {
|
|
176
|
+
return parseNotificationPayload(await readJsonFromApi(`${baseApiUrl(session.apiUrl)}/api/user/notifications`, session));
|
|
177
|
+
}
|
|
178
|
+
async function markNotificationReadFromApi(session, notificationId) {
|
|
179
|
+
return parseNotificationPayload(await writeJsonToApi(`${baseApiUrl(session.apiUrl)}/api/user/notifications`, "PATCH", { notificationId }, session));
|
|
180
|
+
}
|
|
181
|
+
async function markAllNotificationsReadFromApi(session) {
|
|
182
|
+
return parseNotificationPayload(await writeJsonToApi(`${baseApiUrl(session.apiUrl)}/api/user/notifications`, "PATCH", { markAll: true }, session));
|
|
183
|
+
}
|
|
184
|
+
function formatNotifications(payload) {
|
|
185
|
+
if (payload.notifications.length === 0) return "No notifications.";
|
|
186
|
+
const lines = [`Unread: ${payload.unreadCount}`];
|
|
187
|
+
for (const notification of payload.notifications) {
|
|
188
|
+
const state = notification.readAt ? "read" : "unread";
|
|
189
|
+
lines.push([
|
|
190
|
+
`[${state}] ${notification.id}`,
|
|
191
|
+
`${notification.eventType}: ${notification.title}`,
|
|
192
|
+
notification.body,
|
|
193
|
+
notification.linkUrl ? `link: ${notification.linkUrl}` : "",
|
|
194
|
+
`created: ${notification.createdAt}`
|
|
195
|
+
].filter(Boolean).join("\n "));
|
|
196
|
+
}
|
|
197
|
+
return lines.join("\n\n");
|
|
198
|
+
}
|
|
199
|
+
function parseNotificationPayload(payload) {
|
|
200
|
+
if (!isNotificationPayload(payload)) throw new Error("Notification response has an unsupported shape");
|
|
201
|
+
return payload;
|
|
202
|
+
}
|
|
203
|
+
function isNotificationPayload(value) {
|
|
204
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
205
|
+
const notifications = Reflect.get(value, "notifications");
|
|
206
|
+
const unreadCount = Reflect.get(value, "unreadCount");
|
|
207
|
+
const userId = Reflect.get(value, "userId");
|
|
208
|
+
return typeof userId === "string" && Array.isArray(notifications) && typeof unreadCount === "number" && notifications.every(isNotificationItem);
|
|
209
|
+
}
|
|
210
|
+
function isNotificationItem(value) {
|
|
211
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
212
|
+
return typeof Reflect.get(value, "id") === "string" && typeof Reflect.get(value, "eventType") === "string" && typeof Reflect.get(value, "title") === "string" && typeof Reflect.get(value, "body") === "string" && (Reflect.get(value, "linkUrl") === void 0 || typeof Reflect.get(value, "linkUrl") === "string") && (Reflect.get(value, "readAt") === void 0 || typeof Reflect.get(value, "readAt") === "string") && typeof Reflect.get(value, "createdAt") === "string";
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// scripts/issue.ts
|
|
216
|
+
function parseArgs(argv) {
|
|
217
|
+
const args = { command: argv[0], subcommand: argv[1]?.startsWith("--") ? void 0 : argv[1] };
|
|
218
|
+
const optionStart = args.subcommand ? 2 : 1;
|
|
219
|
+
for (let index = optionStart; index < argv.length; index += 1) {
|
|
220
|
+
const token = argv[index] ?? "";
|
|
221
|
+
const value = argv[index + 1];
|
|
222
|
+
if (!token.startsWith("--")) continue;
|
|
223
|
+
if (token === "--unassign") {
|
|
224
|
+
args.unassign = true;
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
if (!value || value.startsWith("--")) throw new Error(`${token} requires a value`);
|
|
228
|
+
index += 1;
|
|
229
|
+
setOption(args, token, value);
|
|
230
|
+
}
|
|
231
|
+
if (args.unassign && args.command !== "assign") throw new Error("--unassign is only valid with assign");
|
|
232
|
+
return args;
|
|
233
|
+
}
|
|
234
|
+
function setOption(args, token, value) {
|
|
235
|
+
switch (token) {
|
|
236
|
+
case "--issue":
|
|
237
|
+
args.issue = value;
|
|
238
|
+
return;
|
|
239
|
+
case "--author":
|
|
240
|
+
args.author = value;
|
|
241
|
+
return;
|
|
242
|
+
case "--notification":
|
|
243
|
+
args.notification = value;
|
|
244
|
+
return;
|
|
245
|
+
case "--body":
|
|
246
|
+
args.body = value;
|
|
247
|
+
return;
|
|
248
|
+
case "--kind":
|
|
249
|
+
args.kind = value;
|
|
250
|
+
return;
|
|
251
|
+
case "--status":
|
|
252
|
+
args.status = value;
|
|
253
|
+
return;
|
|
254
|
+
case "--assignee":
|
|
255
|
+
args.assignee = value;
|
|
256
|
+
return;
|
|
257
|
+
case "--repo":
|
|
258
|
+
case "--repository":
|
|
259
|
+
args.repository = value;
|
|
260
|
+
return;
|
|
261
|
+
case "--pr":
|
|
262
|
+
case "--number":
|
|
263
|
+
args.number = value;
|
|
264
|
+
return;
|
|
265
|
+
case "--blocker-id":
|
|
266
|
+
args.blockerId = value;
|
|
267
|
+
return;
|
|
268
|
+
case "--file":
|
|
269
|
+
args.file = value;
|
|
270
|
+
return;
|
|
271
|
+
case "--filename":
|
|
272
|
+
args.filename = value;
|
|
273
|
+
return;
|
|
274
|
+
case "--base-artifact":
|
|
275
|
+
args.baseArtifactId = value;
|
|
276
|
+
return;
|
|
277
|
+
case "--suggestion-id":
|
|
278
|
+
args.suggestionArtifactId = value;
|
|
279
|
+
return;
|
|
280
|
+
case "--format":
|
|
281
|
+
args.format = value;
|
|
282
|
+
return;
|
|
283
|
+
case "--out":
|
|
284
|
+
args.out = value;
|
|
285
|
+
return;
|
|
286
|
+
case "--store":
|
|
287
|
+
args.store = value;
|
|
288
|
+
return;
|
|
289
|
+
case "--api-url":
|
|
290
|
+
args.apiUrl = value;
|
|
291
|
+
return;
|
|
292
|
+
default:
|
|
293
|
+
throw new Error(`Unknown option: ${token}`);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
function requireArg(value, name) {
|
|
297
|
+
if (!value?.trim()) throw new Error(`${name} is required`);
|
|
298
|
+
return value.trim();
|
|
299
|
+
}
|
|
300
|
+
function assertCommentKind(kind) {
|
|
301
|
+
if (kind === "analysis" || kind === "solution") return kind;
|
|
302
|
+
return "comment";
|
|
303
|
+
}
|
|
304
|
+
function assertStatus(status) {
|
|
305
|
+
const value = requireArg(status, "--status");
|
|
306
|
+
if (value === "open" || value === "investigating" || value === "resolved" || value === "deferred" || value === "cancelled") return value;
|
|
307
|
+
throw new Error(`Unsupported status: ${value}`);
|
|
308
|
+
}
|
|
309
|
+
function assignmentValue(args) {
|
|
310
|
+
if (args.unassign && args.assignee !== void 0) throw new Error("Use either --assignee <name> or --unassign, not both");
|
|
311
|
+
return args.unassign ? "" : requireArg(args.assignee, "--assignee");
|
|
312
|
+
}
|
|
313
|
+
async function apiContext(args, store) {
|
|
314
|
+
const session = await store.apiSession(args.apiUrl);
|
|
315
|
+
return apiSession(session.apiUrl, { cookie: session.cookie, token: session.token });
|
|
316
|
+
}
|
|
317
|
+
async function notificationCommand(args, store) {
|
|
318
|
+
const session = await apiContext(args, store);
|
|
319
|
+
if (!session.token && !session.cookie) throw new Error("Run `lagora login` first");
|
|
320
|
+
if (args.subcommand === "read") {
|
|
321
|
+
console.log(formatNotifications(await markNotificationReadFromApi(session, requireArg(args.notification, "--notification"))));
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
if (args.subcommand === "read-all") {
|
|
325
|
+
console.log(formatNotifications(await markAllNotificationsReadFromApi(session)));
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
const payload = await listNotificationsFromApi(session);
|
|
329
|
+
console.log(args.format === "json" ? JSON.stringify(payload, null, 2) : formatNotifications(payload));
|
|
330
|
+
}
|
|
331
|
+
async function main() {
|
|
332
|
+
const args = parseArgs(process.argv.slice(2));
|
|
333
|
+
const store = new LagoraCliConfigStore();
|
|
334
|
+
if (args.store?.trim()) process.env.AGORA_ISSUE_STORE = path2.resolve(args.store.trim());
|
|
335
|
+
if (args.command === "login" || args.command === "logout" || args.command === "whoami") {
|
|
336
|
+
throw new Error(`Use \`lagora ${args.command}\` instead`);
|
|
337
|
+
}
|
|
338
|
+
if (args.command === "notifications") return notificationCommand(args, store);
|
|
339
|
+
const issueId = requireArg(args.issue, "--issue");
|
|
340
|
+
const author = await store.author(args.author);
|
|
341
|
+
const storedSession = args.store?.trim() ? void 0 : await store.apiSession(args.apiUrl);
|
|
342
|
+
const session = storedSession ? apiSession(storedSession.apiUrl, { cookie: storedSession.cookie, token: storedSession.token }) : void 0;
|
|
343
|
+
if (args.command === "fetch") return session ? fetchIssueFromApi(issueId, session, args.format) : fetchIssueFromStore(issueId, args.format);
|
|
344
|
+
if (args.command === "checkout") return session ? checkoutIssueFromApi(issueId, session.apiUrl, args.out, author, session) : checkoutIssueFromStore(issueId, args.out, author);
|
|
345
|
+
if (args.command === "comment") return session ? addCommentFromApi({ issueId, apiUrl: session.apiUrl, author, body: requireArg(args.body, "--body"), kind: assertCommentKind(args.kind), session }) : addLocalComment(issueId, author, requireArg(args.body, "--body"), assertCommentKind(args.kind));
|
|
346
|
+
if (args.command === "status") return session ? updateStatusFromApi({ issueId, apiUrl: session.apiUrl, author, status: assertStatus(args.status), session }) : updateIssueStatusInStore(issueId, assertStatus(args.status), author);
|
|
347
|
+
if (args.command === "description") return session ? updateDescriptionFromApi({ issueId, apiUrl: session.apiUrl, author, description: requireArg(args.body, "--body"), session }) : updateIssueDescriptionInStore(issueId, requireArg(args.body, "--body"), author);
|
|
348
|
+
if (args.command === "suggestion") return session ? saveSuggestionFromApi({
|
|
349
|
+
issueId,
|
|
350
|
+
apiUrl: session.apiUrl,
|
|
351
|
+
author,
|
|
352
|
+
filename: args.filename?.trim() || path2.basename(requireArg(args.file, "--file")),
|
|
353
|
+
content: await readSuggestionFile(args.file),
|
|
354
|
+
baseArtifactId: args.baseArtifactId?.trim(),
|
|
355
|
+
suggestionArtifactId: args.suggestionArtifactId?.trim(),
|
|
356
|
+
session
|
|
357
|
+
}) : saveSuggestionToStore({ issueId, file: requireArg(args.file, "--file"), filename: args.filename, baseArtifactId: args.baseArtifactId, suggestionArtifactId: args.suggestionArtifactId, author });
|
|
358
|
+
if (args.command === "assign") {
|
|
359
|
+
const assignee = assignmentValue(args);
|
|
360
|
+
return session ? assignIssueFromApi({ issueId, apiUrl: session.apiUrl, author, assignee, session }) : assignIssueInStore({ issueId, assignee, author });
|
|
361
|
+
}
|
|
362
|
+
if (args.command === "blocker") return blockerCommand(args, issueId, author, session);
|
|
363
|
+
throw new Error("Usage: lagora issue notifications|fetch|checkout|comment|status|suggestion|assign|blocker --issue <id> [--api-url url] [--store path]; assign requires --assignee <name> or --unassign");
|
|
364
|
+
}
|
|
365
|
+
async function addLocalComment(issueId, author, body, kind) {
|
|
366
|
+
const { addComment } = await import("./storage-234FBH54.js");
|
|
367
|
+
await addComment({ issueId, author, body, kind });
|
|
368
|
+
console.log(`Comment added to ${issueId}`);
|
|
369
|
+
}
|
|
370
|
+
async function readSuggestionFile(file) {
|
|
371
|
+
const { readFile } = await import("node:fs/promises");
|
|
372
|
+
return readFile(path2.resolve(requireArg(file, "--file")), "utf8");
|
|
373
|
+
}
|
|
374
|
+
async function blockerCommand(args, issueId, author, session) {
|
|
375
|
+
if (args.subcommand === "sync") {
|
|
376
|
+
const blockerId = requireArg(args.blockerId, "--blocker-id");
|
|
377
|
+
return session ? syncBlockerFromApi({ issueId, apiUrl: session.apiUrl, author, blockerId, session }) : syncBlockerInStore({ issueId, blockerId, author });
|
|
378
|
+
}
|
|
379
|
+
const number = Number.parseInt(requireArg(args.number, "--pr"), 10);
|
|
380
|
+
if (!Number.isInteger(number) || number <= 0) throw new Error(`Unsupported pull request number: ${args.number}`);
|
|
381
|
+
return session ? addBlockerFromApi({ issueId, apiUrl: session.apiUrl, author, repository: args.repository?.trim(), number, session }) : addBlockerToStore({ issueId, repository: args.repository?.trim(), number, author });
|
|
382
|
+
}
|
|
383
|
+
main().catch((error) => {
|
|
384
|
+
console.error(error instanceof Error ? error.message : error);
|
|
385
|
+
process.exit(1);
|
|
386
|
+
});
|