@bdsqqq/lnr-cli 1.5.0 → 2.0.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/package.json +2 -3
- package/src/bench-lnr-overhead.ts +160 -0
- package/src/e2e-mutations.test.ts +378 -0
- package/src/e2e-readonly.test.ts +103 -0
- package/src/generated/doc.ts +270 -0
- package/src/generated/issue.ts +807 -0
- package/src/generated/label.ts +273 -0
- package/src/generated/project.ts +596 -0
- package/src/generated/template.ts +157 -0
- package/src/hand-crafted/issue.ts +27 -0
- package/src/lib/adapters/doc.ts +14 -0
- package/src/lib/adapters/index.ts +4 -0
- package/src/lib/adapters/issue.ts +32 -0
- package/src/lib/adapters/label.ts +20 -0
- package/src/lib/adapters/project.ts +23 -0
- package/src/lib/arktype-config.ts +18 -0
- package/src/lib/command-introspection.ts +97 -0
- package/src/lib/dispatch-effects.test.ts +297 -0
- package/src/lib/error.ts +37 -1
- package/src/lib/operation-spec.test.ts +317 -0
- package/src/lib/operation-spec.ts +11 -0
- package/src/lib/operation-specs.ts +21 -0
- package/src/lib/output.test.ts +3 -1
- package/src/lib/output.ts +1 -296
- package/src/lib/renderers/comments.ts +300 -0
- package/src/lib/renderers/detail.ts +61 -0
- package/src/lib/renderers/index.ts +2 -0
- package/src/router/agent-sessions.ts +253 -0
- package/src/router/auth.ts +6 -5
- package/src/router/config.ts +7 -6
- package/src/router/contract.test.ts +364 -0
- package/src/router/cycles.ts +372 -95
- package/src/router/git-automation-states.ts +355 -0
- package/src/router/git-automation-target-branches.ts +309 -0
- package/src/router/index.ts +26 -8
- package/src/router/initiatives.ts +260 -0
- package/src/router/me.ts +8 -7
- package/src/router/notifications.ts +176 -0
- package/src/router/roadmaps.ts +172 -0
- package/src/router/search.ts +7 -6
- package/src/router/teams.ts +82 -24
- package/src/router/users.ts +126 -0
- package/src/router/views.ts +399 -0
- package/src/router/docs.ts +0 -153
- package/src/router/issues.ts +0 -600
- package/src/router/labels.ts +0 -192
- package/src/router/projects.ts +0 -220
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GENERATED FILE - DO NOT EDIT
|
|
3
|
+
* Regenerate with: bun run packages/codegen/generate-commands.ts
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import "../lib/arktype-config";
|
|
7
|
+
import { type } from "arktype";
|
|
8
|
+
import {
|
|
9
|
+
getClient,
|
|
10
|
+
listDocuments,
|
|
11
|
+
getDocument,
|
|
12
|
+
createDocument,
|
|
13
|
+
updateDocument,
|
|
14
|
+
deleteDocument,
|
|
15
|
+
resolveProjectByName,
|
|
16
|
+
type Document,
|
|
17
|
+
} from "@bdsqqq/lnr-core";
|
|
18
|
+
import { router, procedure } from "../router/trpc";
|
|
19
|
+
import { handleApiError, exitWithError, EXIT_CODES } from "../lib/error";
|
|
20
|
+
import type { OperationSpec } from "../lib/operation-spec";
|
|
21
|
+
import {
|
|
22
|
+
outputJson,
|
|
23
|
+
outputQuiet,
|
|
24
|
+
outputTable,
|
|
25
|
+
getOutputFormat,
|
|
26
|
+
truncate,
|
|
27
|
+
type OutputOptions,
|
|
28
|
+
type TableColumn,
|
|
29
|
+
} from "../lib/output";
|
|
30
|
+
import { outputDetail } from "../lib/renderers/detail";
|
|
31
|
+
import { docToDetail } from "../lib/adapters";
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
export const listDocsInput = type({
|
|
35
|
+
"project?": type("string").describe("filter by project name or id"),
|
|
36
|
+
"json?": type("boolean").describe("output as json"),
|
|
37
|
+
"quiet?": type("boolean").describe("output ids only"),
|
|
38
|
+
"verbose?": type("boolean").describe("show all columns"),
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
export const docInput = type({
|
|
42
|
+
id: type("string").configure({ positional: true }).describe("document id or 'new'"),
|
|
43
|
+
"title?": type("string").describe("document title (required for new)"),
|
|
44
|
+
"content?": type("string").describe("document content"),
|
|
45
|
+
"project?": type("string").describe("project name or id to attach document to"),
|
|
46
|
+
"delete?": type("boolean").describe("delete the document"),
|
|
47
|
+
"json?": type("boolean").describe("output as json"),
|
|
48
|
+
"quiet?": type("boolean").describe("output ids only"),
|
|
49
|
+
"verbose?": type("boolean").describe("show all columns"),
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
type DocInput = typeof docInput.infer;
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
const docColumns: TableColumn<Document>[] = [
|
|
57
|
+
{ header: "ID", value: (d) => d.id, width: 20 },
|
|
58
|
+
{ header: "TITLE", value: (d) => truncate(d.title, 50), width: 50 },
|
|
59
|
+
];
|
|
60
|
+
|
|
61
|
+
export const docOperations = ["create", "read", "update", "delete"] as const;
|
|
62
|
+
type Operation = (typeof docOperations)[number];
|
|
63
|
+
|
|
64
|
+
export const docMutationFlags: readonly (keyof DocInput)[] = [
|
|
65
|
+
"title", "content"
|
|
66
|
+
] as const;
|
|
67
|
+
|
|
68
|
+
export function inferOperation(input: DocInput): Operation {
|
|
69
|
+
if (input.id === "new") return "create";
|
|
70
|
+
if (input.delete) return "delete";
|
|
71
|
+
|
|
72
|
+
for (const flag of docMutationFlags) {
|
|
73
|
+
if (input[flag] !== undefined) return "update";
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return "read";
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export const docOperationSpec: OperationSpec<DocInput, Operation> = {
|
|
80
|
+
command: "doc",
|
|
81
|
+
operations: docOperations,
|
|
82
|
+
mutationFlags: docMutationFlags,
|
|
83
|
+
inferOperation,
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
async function handleListDocs(
|
|
87
|
+
input: typeof listDocsInput.infer
|
|
88
|
+
): Promise<void> {
|
|
89
|
+
try {
|
|
90
|
+
const client = getClient();
|
|
91
|
+
|
|
92
|
+
const outputOpts: OutputOptions = {
|
|
93
|
+
format: input.json ? "json" : input.quiet ? "quiet" : undefined,
|
|
94
|
+
verbose: input.verbose,
|
|
95
|
+
};
|
|
96
|
+
const format = getOutputFormat(outputOpts);
|
|
97
|
+
|
|
98
|
+
let projectId: string | undefined;
|
|
99
|
+
if (input.project) {
|
|
100
|
+
try {
|
|
101
|
+
projectId = await resolveProjectByName(client, input.project);
|
|
102
|
+
} catch {
|
|
103
|
+
projectId = input.project;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const documents = await listDocuments(client, projectId);
|
|
108
|
+
|
|
109
|
+
if (format === "json") {
|
|
110
|
+
outputJson(documents);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (format === "quiet") {
|
|
115
|
+
outputQuiet(documents.map((d) => d.id));
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
outputTable(documents, docColumns, outputOpts);
|
|
120
|
+
} catch (error) {
|
|
121
|
+
handleApiError(error);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async function handleShowDoc(id: string, input: DocInput): Promise<void> {
|
|
126
|
+
try {
|
|
127
|
+
const client = getClient();
|
|
128
|
+
|
|
129
|
+
const outputOpts: OutputOptions = {
|
|
130
|
+
format: input.json ? "json" : input.quiet ? "quiet" : undefined,
|
|
131
|
+
verbose: input.verbose,
|
|
132
|
+
};
|
|
133
|
+
const format = getOutputFormat(outputOpts);
|
|
134
|
+
|
|
135
|
+
const doc = await getDocument(client, id);
|
|
136
|
+
|
|
137
|
+
if (!doc) {
|
|
138
|
+
exitWithError(`document "${id}" not found`, undefined, EXIT_CODES.NOT_FOUND);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (format === "json") {
|
|
142
|
+
outputJson(doc);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (format === "quiet") {
|
|
147
|
+
console.log(doc.id);
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
outputDetail(docToDetail(doc));
|
|
152
|
+
} catch (error) {
|
|
153
|
+
handleApiError(error);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
async function handleUpdateDoc(id: string, input: DocInput): Promise<void> {
|
|
158
|
+
try {
|
|
159
|
+
const client = getClient();
|
|
160
|
+
|
|
161
|
+
const success = await updateDocument(client, id, {
|
|
162
|
+
title: input.title,
|
|
163
|
+
content: input.content,
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
if (!success) {
|
|
167
|
+
exitWithError(`document "${id}" not found`, undefined, EXIT_CODES.NOT_FOUND);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
console.log(`updated document: ${id}`);
|
|
171
|
+
} catch (error) {
|
|
172
|
+
handleApiError(error);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
async function handleCreateDoc(input: DocInput): Promise<void> {
|
|
177
|
+
if (!input.title) {
|
|
178
|
+
exitWithError("--title is required", 'usage: lnr doc new --title "..."');
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
try {
|
|
182
|
+
const client = getClient();
|
|
183
|
+
|
|
184
|
+
const createPayload: {
|
|
185
|
+
title: string;
|
|
186
|
+
content?: string;
|
|
187
|
+
projectId?: string;
|
|
188
|
+
} = {
|
|
189
|
+
title: input.title,
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
if (input.content) createPayload.content = input.content;
|
|
193
|
+
if (input.project) {
|
|
194
|
+
try {
|
|
195
|
+
createPayload.projectId = await resolveProjectByName(client, input.project);
|
|
196
|
+
} catch {
|
|
197
|
+
createPayload.projectId = input.project;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const doc = await createDocument(client, createPayload);
|
|
202
|
+
|
|
203
|
+
if (doc) {
|
|
204
|
+
console.log(`created document: ${doc.title}`);
|
|
205
|
+
} else {
|
|
206
|
+
exitWithError("failed to create document");
|
|
207
|
+
}
|
|
208
|
+
} catch (error) {
|
|
209
|
+
handleApiError(error);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
async function handleDeleteDoc(id: string, _input: DocInput): Promise<void> {
|
|
214
|
+
try {
|
|
215
|
+
const client = getClient();
|
|
216
|
+
|
|
217
|
+
const success = await deleteDocument(client, id);
|
|
218
|
+
|
|
219
|
+
if (!success) {
|
|
220
|
+
exitWithError(`document "${id}" not found`, undefined, EXIT_CODES.NOT_FOUND);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
console.log(`deleted document: ${id}`);
|
|
224
|
+
} catch (error) {
|
|
225
|
+
handleApiError(error);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
export const generatedDocsRouter = router({
|
|
234
|
+
docs: procedure
|
|
235
|
+
.meta({
|
|
236
|
+
description: "list docs",
|
|
237
|
+
|
|
238
|
+
})
|
|
239
|
+
.input(listDocsInput)
|
|
240
|
+
.query(async ({ input }) => {
|
|
241
|
+
await handleListDocs(input);
|
|
242
|
+
}),
|
|
243
|
+
|
|
244
|
+
doc: procedure
|
|
245
|
+
.meta({
|
|
246
|
+
description: "show or update a doc, or create with 'new'",
|
|
247
|
+
})
|
|
248
|
+
.input(docInput)
|
|
249
|
+
.mutation(async ({ input }) => {
|
|
250
|
+
const operation = inferOperation(input);
|
|
251
|
+
|
|
252
|
+
switch (operation) {
|
|
253
|
+
case "create":
|
|
254
|
+
await handleCreateDoc(input);
|
|
255
|
+
break;
|
|
256
|
+
case "delete":
|
|
257
|
+
await handleDeleteDoc(input.id, input);
|
|
258
|
+
break;
|
|
259
|
+
|
|
260
|
+
case "update":
|
|
261
|
+
await handleUpdateDoc(input.id, input);
|
|
262
|
+
break;
|
|
263
|
+
case "read":
|
|
264
|
+
default:
|
|
265
|
+
await handleShowDoc(input.id, input);
|
|
266
|
+
break;
|
|
267
|
+
}
|
|
268
|
+
}),
|
|
269
|
+
|
|
270
|
+
});
|