@blogic-cz/agent-tools 0.15.4 → 0.15.5

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blogic-cz/agent-tools",
3
- "version": "0.15.4",
3
+ "version": "0.15.5",
4
4
  "description": "CLI tools for AI coding agent workflows — GitHub, database, Kubernetes, Azure DevOps, logs, sessions, and audit",
5
5
  "keywords": [
6
6
  "agent",
@@ -10,6 +10,7 @@ import {
10
10
  issueCloseCommand,
11
11
  issueCommentCommand,
12
12
  issueCommentsCommand,
13
+ issueCreateCommand,
13
14
  issueEditCommand,
14
15
  issueListCommand,
15
16
  issueReopenCommand,
@@ -109,7 +110,7 @@ const prCommand = Command.make("pr", {}).pipe(
109
110
 
110
111
  const issueCommand = Command.make("issue", {}).pipe(
111
112
  Command.withDescription(
112
- "Issue operations (list, view, comments, triage, snapshot-batch, close, reopen, comment, edit)",
113
+ "Issue operations (list, view, comments, triage, snapshot-batch, create, close, reopen, comment, edit)",
113
114
  ),
114
115
  Command.withSubcommands([
115
116
  issueListCommand,
@@ -117,6 +118,7 @@ const issueCommand = Command.make("issue", {}).pipe(
117
118
  issueCommentsCommand,
118
119
  issueTriageCommand,
119
120
  issueSnapshotBatchCommand,
121
+ issueCreateCommand,
120
122
  issueCloseCommand,
121
123
  issueReopenCommand,
122
124
  issueCommentCommand,
@@ -2,11 +2,16 @@ import { Command, Flag } from "effect/unstable/cli";
2
2
  import { Effect, Option } from "effect";
3
3
 
4
4
  import { formatOption, logFormatted } from "#shared";
5
- import { resolveOptionalTextInput, resolveRequiredTextInput } from "#gh/text-input";
5
+ import {
6
+ resolveDefaultTextInput,
7
+ resolveOptionalTextInput,
8
+ resolveRequiredTextInput,
9
+ } from "#gh/text-input";
6
10
 
7
11
  import {
8
12
  closeIssue,
9
13
  commentOnIssue,
14
+ createIssue,
10
15
  editIssue,
11
16
  fetchIssueComments,
12
17
  listIssues,
@@ -192,6 +197,57 @@ export const issueReopenCommand = Command.make(
192
197
  ),
193
198
  ).pipe(Command.withDescription("Reopen a closed issue"));
194
199
 
200
+ export const issueCreateCommand = Command.make(
201
+ "create",
202
+ {
203
+ assignee: Flag.string("assignee").pipe(
204
+ Flag.withDescription("Assignee login (comma-separated for multiple)"),
205
+ Flag.optional,
206
+ ),
207
+ body: Flag.string("body").pipe(Flag.withDescription("Issue body"), Flag.optional),
208
+ bodyFile: Flag.string("body-file").pipe(
209
+ Flag.withDescription("Read issue body from a file path or '-' for stdin"),
210
+ Flag.optional,
211
+ ),
212
+ bodyStdin: Flag.boolean("body-stdin").pipe(
213
+ Flag.withDescription("Read issue body from stdin"),
214
+ Flag.withDefault(false),
215
+ ),
216
+ format: formatOption,
217
+ labels: Flag.string("labels").pipe(
218
+ Flag.withDescription("Labels to apply (comma-separated)"),
219
+ Flag.optional,
220
+ ),
221
+ repo: repoOption,
222
+ title: Flag.string("title").pipe(Flag.withDescription("Issue title")),
223
+ },
224
+ ({ assignee, body, bodyFile, bodyStdin, format, labels, repo, title }) =>
225
+ withRepo(
226
+ repo,
227
+ Effect.gen(function* () {
228
+ const resolvedBody = yield* resolveDefaultTextInput({
229
+ command: "gh-tool issue create",
230
+ value: Option.getOrNull(body),
231
+ fileValue: Option.getOrNull(bodyFile),
232
+ stdin: bodyStdin,
233
+ valueFlag: "--body",
234
+ fileFlag: "--body-file",
235
+ stdinFlag: "--body-stdin",
236
+ label: "body",
237
+ defaultValue: "",
238
+ });
239
+
240
+ const result = yield* createIssue({
241
+ assignee: Option.getOrNull(assignee),
242
+ body: resolvedBody,
243
+ labels: Option.getOrNull(labels),
244
+ title,
245
+ });
246
+ yield* logFormatted(result, format);
247
+ }),
248
+ ),
249
+ ).pipe(Command.withDescription("Create a new issue"));
250
+
195
251
  export const issueCommentCommand = Command.make(
196
252
  "comment",
197
253
  {
@@ -257,6 +257,40 @@ export const commentOnIssue = Effect.fn("issue.commentOnIssue")(function* (opts:
257
257
  };
258
258
  });
259
259
 
260
+ export const createIssue = Effect.fn("issue.createIssue")(function* (opts: {
261
+ title: string;
262
+ body: string;
263
+ assignee: string | null;
264
+ labels: string | null;
265
+ }) {
266
+ const gh = yield* GitHubService;
267
+
268
+ const args = ["issue", "create", "--title", opts.title, "--body", opts.body];
269
+
270
+ if (opts.assignee !== null) {
271
+ args.push("--assignee", opts.assignee);
272
+ }
273
+ if (opts.labels !== null) {
274
+ args.push("--label", opts.labels);
275
+ }
276
+
277
+ const result = yield* gh.runGh(args);
278
+
279
+ const urlMatch = result.stdout.match(/\/issues\/(\d+)/);
280
+ if (!urlMatch?.[1]) {
281
+ return yield* Effect.fail(
282
+ new GitHubCommandError({
283
+ command: "gh issue create",
284
+ exitCode: 0,
285
+ stderr: "Issue was created but its number could not be parsed from the output.",
286
+ message: "Issue was created but its number could not be parsed from the output.",
287
+ }),
288
+ );
289
+ }
290
+
291
+ return yield* viewIssue(Number(urlMatch[1]));
292
+ });
293
+
260
294
  export const editIssue = Effect.fn("issue.editIssue")(function* (opts: {
261
295
  issue: number;
262
296
  title: string | null;
@@ -2,6 +2,7 @@ export {
2
2
  issueCloseCommand,
3
3
  issueCommentCommand,
4
4
  issueCommentsCommand,
5
+ issueCreateCommand,
5
6
  issueEditCommand,
6
7
  issueListCommand,
7
8
  issueReopenCommand,