@blogic-cz/agent-tools 0.14.26 → 0.14.27

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.14.26",
3
+ "version": "0.14.27",
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",
@@ -13,6 +13,18 @@ import {
13
13
  reopenIssue,
14
14
  viewIssue,
15
15
  } from "./core";
16
+ import { GitHubService } from "#gh/service";
17
+
18
+ const repoOption = Flag.string("repo").pipe(
19
+ Flag.withDescription("Target repository profile name or owner/name"),
20
+ Flag.optional,
21
+ );
22
+
23
+ const withRepo = <A, E, R>(repo: Option.Option<string>, effect: Effect.Effect<A, E, R>) =>
24
+ Effect.gen(function* () {
25
+ const gh = yield* GitHubService;
26
+ return yield* gh.withRepoTarget(Option.getOrNull(repo), effect);
27
+ });
16
28
 
17
29
  export const issueListCommand = Command.make(
18
30
  "list",
@@ -26,20 +38,24 @@ export const issueListCommand = Command.make(
26
38
  Flag.withDescription("Maximum number of issues to return"),
27
39
  Flag.withDefault(30),
28
40
  ),
41
+ repo: repoOption,
29
42
  state: Flag.choice("state", ["open", "closed", "all"]).pipe(
30
43
  Flag.withDescription("Filter by state: open, closed, all"),
31
44
  Flag.withDefault("open"),
32
45
  ),
33
46
  },
34
- ({ format, labels, limit, state }) =>
35
- Effect.gen(function* () {
36
- const issues = yield* listIssues({
37
- labels: Option.getOrNull(labels),
38
- limit,
39
- state,
40
- });
41
- yield* logFormatted(issues, format);
42
- }),
47
+ ({ format, labels, limit, repo, state }) =>
48
+ withRepo(
49
+ repo,
50
+ Effect.gen(function* () {
51
+ const issues = yield* listIssues({
52
+ labels: Option.getOrNull(labels),
53
+ limit,
54
+ state,
55
+ });
56
+ yield* logFormatted(issues, format);
57
+ }),
58
+ ),
43
59
  ).pipe(Command.withDescription("List issues (default: open, use --state to filter)"));
44
60
 
45
61
  export const issueViewCommand = Command.make(
@@ -47,12 +63,16 @@ export const issueViewCommand = Command.make(
47
63
  {
48
64
  format: formatOption,
49
65
  issue: Flag.integer("issue").pipe(Flag.withDescription("Issue number")),
66
+ repo: repoOption,
50
67
  },
51
- ({ format, issue }) =>
52
- Effect.gen(function* () {
53
- const info = yield* viewIssue(issue);
54
- yield* logFormatted(info, format);
55
- }),
68
+ ({ format, issue, repo }) =>
69
+ withRepo(
70
+ repo,
71
+ Effect.gen(function* () {
72
+ const info = yield* viewIssue(issue);
73
+ yield* logFormatted(info, format);
74
+ }),
75
+ ),
56
76
  ).pipe(Command.withDescription("View issue details"));
57
77
 
58
78
  export const issueCommentsCommand = Command.make(
@@ -68,21 +88,25 @@ export const issueCommentsCommand = Command.make(
68
88
  ),
69
89
  format: formatOption,
70
90
  issue: Flag.integer("issue").pipe(Flag.withDescription("Issue number")),
91
+ repo: repoOption,
71
92
  since: Flag.string("since").pipe(
72
93
  Flag.withDescription("ISO timestamp to filter comments created after"),
73
94
  Flag.optional,
74
95
  ),
75
96
  },
76
- ({ author, bodyContains, format, issue, since }) =>
77
- Effect.gen(function* () {
78
- const comments = yield* fetchIssueComments(
79
- issue,
80
- Option.getOrNull(since),
81
- Option.getOrNull(author),
82
- Option.getOrNull(bodyContains),
83
- );
84
- yield* logFormatted(comments, format);
85
- }),
97
+ ({ author, bodyContains, format, issue, repo, since }) =>
98
+ withRepo(
99
+ repo,
100
+ Effect.gen(function* () {
101
+ const comments = yield* fetchIssueComments(
102
+ issue,
103
+ Option.getOrNull(since),
104
+ Option.getOrNull(author),
105
+ Option.getOrNull(bodyContains),
106
+ );
107
+ yield* logFormatted(comments, format);
108
+ }),
109
+ ),
86
110
  ).pipe(Command.withDescription("Fetch issue discussion comments"));
87
111
 
88
112
  export const issueCloseCommand = Command.make(
@@ -98,29 +122,33 @@ export const issueCloseCommand = Command.make(
98
122
  ),
99
123
  format: formatOption,
100
124
  issue: Flag.integer("issue").pipe(Flag.withDescription("Issue number to close")),
125
+ repo: repoOption,
101
126
  reason: Flag.choice("reason", ["completed", "not planned"]).pipe(
102
127
  Flag.withDescription("Close reason: completed, not planned"),
103
128
  Flag.withDefault("completed"),
104
129
  ),
105
130
  },
106
- ({ comment, commentFile, format, issue, reason }) =>
107
- Effect.gen(function* () {
108
- const resolvedComment = yield* resolveOptionalTextInput({
109
- command: "gh-tool issue close",
110
- value: Option.getOrNull(comment),
111
- fileValue: Option.getOrNull(commentFile),
112
- valueFlag: "--comment",
113
- fileFlag: "--comment-file",
114
- label: "comment",
115
- });
131
+ ({ comment, commentFile, format, issue, reason, repo }) =>
132
+ withRepo(
133
+ repo,
134
+ Effect.gen(function* () {
135
+ const resolvedComment = yield* resolveOptionalTextInput({
136
+ command: "gh-tool issue close",
137
+ value: Option.getOrNull(comment),
138
+ fileValue: Option.getOrNull(commentFile),
139
+ valueFlag: "--comment",
140
+ fileFlag: "--comment-file",
141
+ label: "comment",
142
+ });
116
143
 
117
- const result = yield* closeIssue({
118
- comment: resolvedComment,
119
- issue,
120
- reason,
121
- });
122
- yield* logFormatted(result, format);
123
- }),
144
+ const result = yield* closeIssue({
145
+ comment: resolvedComment,
146
+ issue,
147
+ reason,
148
+ });
149
+ yield* logFormatted(result, format);
150
+ }),
151
+ ),
124
152
  ).pipe(Command.withDescription("Close an issue with optional comment and reason"));
125
153
 
126
154
  export const issueReopenCommand = Command.make(
@@ -136,24 +164,28 @@ export const issueReopenCommand = Command.make(
136
164
  ),
137
165
  format: formatOption,
138
166
  issue: Flag.integer("issue").pipe(Flag.withDescription("Issue number to reopen")),
167
+ repo: repoOption,
139
168
  },
140
- ({ comment, commentFile, format, issue }) =>
141
- Effect.gen(function* () {
142
- const resolvedComment = yield* resolveOptionalTextInput({
143
- command: "gh-tool issue reopen",
144
- value: Option.getOrNull(comment),
145
- fileValue: Option.getOrNull(commentFile),
146
- valueFlag: "--comment",
147
- fileFlag: "--comment-file",
148
- label: "comment",
149
- });
169
+ ({ comment, commentFile, format, issue, repo }) =>
170
+ withRepo(
171
+ repo,
172
+ Effect.gen(function* () {
173
+ const resolvedComment = yield* resolveOptionalTextInput({
174
+ command: "gh-tool issue reopen",
175
+ value: Option.getOrNull(comment),
176
+ fileValue: Option.getOrNull(commentFile),
177
+ valueFlag: "--comment",
178
+ fileFlag: "--comment-file",
179
+ label: "comment",
180
+ });
150
181
 
151
- const result = yield* reopenIssue({
152
- comment: resolvedComment,
153
- issue,
154
- });
155
- yield* logFormatted(result, format);
156
- }),
182
+ const result = yield* reopenIssue({
183
+ comment: resolvedComment,
184
+ issue,
185
+ });
186
+ yield* logFormatted(result, format);
187
+ }),
188
+ ),
157
189
  ).pipe(Command.withDescription("Reopen a closed issue"));
158
190
 
159
191
  export const issueCommentCommand = Command.make(
@@ -166,21 +198,25 @@ export const issueCommentCommand = Command.make(
166
198
  ),
167
199
  format: formatOption,
168
200
  issue: Flag.integer("issue").pipe(Flag.withDescription("Issue number to comment on")),
201
+ repo: repoOption,
169
202
  },
170
- ({ body, bodyFile, format, issue }) =>
171
- Effect.gen(function* () {
172
- const resolvedBody = yield* resolveRequiredTextInput({
173
- command: "gh-tool issue comment",
174
- value: Option.getOrNull(body),
175
- fileValue: Option.getOrNull(bodyFile),
176
- valueFlag: "--body",
177
- fileFlag: "--body-file",
178
- label: "body",
179
- });
203
+ ({ body, bodyFile, format, issue, repo }) =>
204
+ withRepo(
205
+ repo,
206
+ Effect.gen(function* () {
207
+ const resolvedBody = yield* resolveRequiredTextInput({
208
+ command: "gh-tool issue comment",
209
+ value: Option.getOrNull(body),
210
+ fileValue: Option.getOrNull(bodyFile),
211
+ valueFlag: "--body",
212
+ fileFlag: "--body-file",
213
+ label: "body",
214
+ });
180
215
 
181
- const result = yield* commentOnIssue({ body: resolvedBody, issue });
182
- yield* logFormatted(result, format);
183
- }),
216
+ const result = yield* commentOnIssue({ body: resolvedBody, issue });
217
+ yield* logFormatted(result, format);
218
+ }),
219
+ ),
184
220
  ).pipe(Command.withDescription("Post a comment on an issue"));
185
221
 
186
222
  export const issueEditCommand = Command.make(
@@ -201,6 +237,7 @@ export const issueEditCommand = Command.make(
201
237
  ),
202
238
  format: formatOption,
203
239
  issue: Flag.integer("issue").pipe(Flag.withDescription("Issue number to edit")),
240
+ repo: repoOption,
204
241
  removeAssignee: Flag.string("remove-assignee").pipe(
205
242
  Flag.withDescription("Remove assignee login (comma-separated for multiple)"),
206
243
  Flag.optional,
@@ -220,27 +257,31 @@ export const issueEditCommand = Command.make(
220
257
  issue,
221
258
  removeAssignee,
222
259
  removeLabels,
260
+ repo,
223
261
  title,
224
262
  }) =>
225
- Effect.gen(function* () {
226
- const resolvedBody = yield* resolveOptionalTextInput({
227
- command: "gh-tool issue edit",
228
- value: Option.getOrNull(body),
229
- fileValue: Option.getOrNull(bodyFile),
230
- valueFlag: "--body",
231
- fileFlag: "--body-file",
232
- label: "body",
233
- });
263
+ withRepo(
264
+ repo,
265
+ Effect.gen(function* () {
266
+ const resolvedBody = yield* resolveOptionalTextInput({
267
+ command: "gh-tool issue edit",
268
+ value: Option.getOrNull(body),
269
+ fileValue: Option.getOrNull(bodyFile),
270
+ valueFlag: "--body",
271
+ fileFlag: "--body-file",
272
+ label: "body",
273
+ });
234
274
 
235
- const result = yield* editIssue({
236
- addAssignee: Option.getOrNull(addAssignee),
237
- addLabels: Option.getOrNull(addLabels),
238
- body: resolvedBody,
239
- issue,
240
- removeAssignee: Option.getOrNull(removeAssignee),
241
- removeLabels: Option.getOrNull(removeLabels),
242
- title: Option.getOrNull(title),
243
- });
244
- yield* logFormatted(result, format);
245
- }),
275
+ const result = yield* editIssue({
276
+ addAssignee: Option.getOrNull(addAssignee),
277
+ addLabels: Option.getOrNull(addLabels),
278
+ body: resolvedBody,
279
+ issue,
280
+ removeAssignee: Option.getOrNull(removeAssignee),
281
+ removeLabels: Option.getOrNull(removeLabels),
282
+ title: Option.getOrNull(title),
283
+ });
284
+ yield* logFormatted(result, format);
285
+ }),
286
+ ),
246
287
  ).pipe(Command.withDescription("Edit issue title, body, labels, or assignees"));
@@ -1,5 +1,5 @@
1
1
  import { Command, Flag } from "effect/unstable/cli";
2
- import { Effect, Schema } from "effect";
2
+ import { Effect, Option, Schema } from "effect";
3
3
 
4
4
  import type { IssueComment } from "#gh/types";
5
5
 
@@ -8,6 +8,17 @@ import { GitHubService } from "#gh/service";
8
8
 
9
9
  import { fetchIssueComments } from "./core";
10
10
 
11
+ const repoOption = Flag.string("repo").pipe(
12
+ Flag.withDescription("Target repository profile name or owner/name"),
13
+ Flag.optional,
14
+ );
15
+
16
+ const withRepo = <A, E, R>(repo: Option.Option<string>, effect: Effect.Effect<A, E, R>) =>
17
+ Effect.gen(function* () {
18
+ const gh = yield* GitHubService;
19
+ return yield* gh.withRepoTarget(Option.getOrNull(repo), effect);
20
+ });
21
+
11
22
  const TriageVerbosity = Schema.Literals(["compact", "full"]);
12
23
  type TriageVerbosity = typeof TriageVerbosity.Type;
13
24
 
@@ -123,16 +134,20 @@ export const issueTriageCommand = Command.make(
123
134
  {
124
135
  format: formatOption,
125
136
  issue: Flag.integer("issue").pipe(Flag.withDescription("Issue number")),
137
+ repo: repoOption,
126
138
  verbosity: Flag.choice("verbosity", ["compact", "full"] as const).pipe(
127
139
  Flag.withDescription("Output detail level: compact or full"),
128
140
  Flag.withDefault("compact"),
129
141
  ),
130
142
  },
131
- ({ format, issue, verbosity }) =>
132
- Effect.gen(function* () {
133
- const result = yield* fetchIssueTriage({ issue, verbosity });
134
- yield* logFormatted(result, format);
135
- }),
143
+ ({ format, issue, repo, verbosity }) =>
144
+ withRepo(
145
+ repo,
146
+ Effect.gen(function* () {
147
+ const result = yield* fetchIssueTriage({ issue, verbosity });
148
+ yield* logFormatted(result, format);
149
+ }),
150
+ ),
136
151
  ).pipe(
137
152
  Command.withDescription("Composite: fetch issue details and discussion comments in one call"),
138
153
  );