@blogic-cz/agent-tools 0.5.6 → 0.6.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 +74 -50
- package/package.json +9 -2
- package/src/credential-guard/index.ts +55 -0
- package/src/gh-tool/index.ts +8 -5
- package/src/gh-tool/types.ts +18 -0
- package/src/gh-tool/workflow.ts +90 -0
package/README.md
CHANGED
|
@@ -27,6 +27,25 @@ These tools wrap each CLI with:
|
|
|
27
27
|
bun add -d @blogic-cz/agent-tools
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
+
### Skill installation
|
|
31
|
+
|
|
32
|
+
Install per-tool skills for only the tools your project uses:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npx skills add blogic-cz/agent-tools --path skill/gh-tool
|
|
36
|
+
npx skills add blogic-cz/agent-tools --path skill/db-tool
|
|
37
|
+
npx skills add blogic-cz/agent-tools --path skill/k8s-tool
|
|
38
|
+
npx skills add blogic-cz/agent-tools --path skill/az-tool
|
|
39
|
+
npx skills add blogic-cz/agent-tools --path skill/logs-tool
|
|
40
|
+
npx skills add blogic-cz/agent-tools --path skill/session-tool
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Or install the all-in-one skill that covers every tool:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npx skills add blogic-cz/agent-tools --path skill/agent-tools
|
|
47
|
+
```
|
|
48
|
+
|
|
30
49
|
**Requirements:** [Bun](https://bun.sh/) >=1.0.0
|
|
31
50
|
|
|
32
51
|
### For agents reading this
|
|
@@ -41,8 +60,8 @@ Follow these steps to set up agent-tools in the consumer project.
|
|
|
41
60
|
```
|
|
42
61
|
- **Non-JavaScript project** (no `package.json`): Skip installation — run tools directly with `bunx`:
|
|
43
62
|
```bash
|
|
44
|
-
bunx
|
|
45
|
-
bunx
|
|
63
|
+
bunx gh-tool pr status
|
|
64
|
+
bunx k8s-tool pods --env test
|
|
46
65
|
```
|
|
47
66
|
|
|
48
67
|
**Step 2 — Configure**
|
|
@@ -68,32 +87,54 @@ Set up the credential guard for the agent's platform:
|
|
|
68
87
|
|
|
69
88
|
For each tool the user selected in Step 2:
|
|
70
89
|
|
|
71
|
-
1. Run `
|
|
90
|
+
1. Run `bun <tool-name> --help` to verify it works (e.g. `bun gh-tool --help`)
|
|
72
91
|
2. Summarize the key commands available
|
|
73
92
|
3. Show the user what data they have access to based on their `agent-tools.json5` — e.g. which environments, clusters, namespaces, databases, or profiles are configured and reachable
|
|
74
93
|
|
|
75
94
|
**Step 5 — Skill & Agent Docs**
|
|
76
95
|
|
|
77
|
-
|
|
96
|
+
Install **only the per-tool skills the project needs** (recommended), or the all-in-one skill:
|
|
78
97
|
|
|
79
98
|
```bash
|
|
80
|
-
|
|
99
|
+
# Per-tool skills (recommended) — install only what the project uses
|
|
100
|
+
npx skills add blogic-cz/agent-tools --path skill/gh-tool
|
|
101
|
+
npx skills add blogic-cz/agent-tools --path skill/db-tool
|
|
102
|
+
npx skills add blogic-cz/agent-tools --path skill/k8s-tool
|
|
103
|
+
npx skills add blogic-cz/agent-tools --path skill/az-tool
|
|
104
|
+
npx skills add blogic-cz/agent-tools --path skill/logs-tool
|
|
105
|
+
npx skills add blogic-cz/agent-tools --path skill/session-tool
|
|
106
|
+
|
|
107
|
+
# All-in-one skill (alternative) — all tools in a single skill
|
|
108
|
+
npx skills add blogic-cz/agent-tools --path skill/agent-tools
|
|
81
109
|
```
|
|
82
110
|
|
|
83
|
-
**Do not run
|
|
111
|
+
**Do not run these commands for the user** — they require interactive selection.
|
|
112
|
+
|
|
113
|
+
Available per-tool skills:
|
|
114
|
+
|
|
115
|
+
| Skill | Install when project uses |
|
|
116
|
+
| -------------- | ------------------------------------------ |
|
|
117
|
+
| `gh-tool` | GitHub PRs, issues, workflows, CI checks |
|
|
118
|
+
| `db-tool` | SQL queries, schema introspection |
|
|
119
|
+
| `k8s-tool` | Kubernetes pods, logs, deployments |
|
|
120
|
+
| `az-tool` | Azure DevOps pipelines, builds |
|
|
121
|
+
| `logs-tool` | Application log reading (local and remote) |
|
|
122
|
+
| `session-tool` | OpenCode session history browsing |
|
|
123
|
+
| `agent-tools` | All of the above in a single skill |
|
|
84
124
|
|
|
85
125
|
Then update the project's `AGENTS.md` and/or `CLAUDE.md`:
|
|
86
126
|
|
|
87
|
-
1. Add
|
|
127
|
+
1. Add rows to the skills table for each installed skill (if one exists):
|
|
88
128
|
```markdown
|
|
89
|
-
|
|
|
129
|
+
| GitHub PRs, issues, workflows | `gh-tool` |
|
|
130
|
+
| Database queries, schema | `db-tool` |
|
|
90
131
|
```
|
|
91
132
|
2. Add or update the **Tooling** section:
|
|
92
133
|
|
|
93
134
|
```markdown
|
|
94
135
|
## Tooling
|
|
95
136
|
|
|
96
|
-
For tool wrappers and operational patterns, load `
|
|
137
|
+
For tool wrappers and operational patterns, load the relevant tool skill (`gh-tool`, `db-tool`, etc.).
|
|
97
138
|
```
|
|
98
139
|
|
|
99
140
|
**Step 6 — Custom Tool Scaffold**
|
|
@@ -146,34 +187,17 @@ bun run agent-tools/example-tool/index.ts ping
|
|
|
146
187
|
3. Run tools:
|
|
147
188
|
|
|
148
189
|
```bash
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
190
|
+
bun gh-tool pr status
|
|
191
|
+
bun k8s-tool kubectl --env test --cmd "get pods"
|
|
192
|
+
bun logs-tool list --env local
|
|
193
|
+
bun audit-tool list --limit 20
|
|
153
194
|
```
|
|
154
195
|
|
|
155
196
|
```bash
|
|
156
|
-
|
|
157
|
-
|
|
197
|
+
bun gh-tool pr review-triage # interactive summary of PR feedback
|
|
198
|
+
bun k8s-tool pods --env test # list pods (structured command)
|
|
158
199
|
```
|
|
159
200
|
|
|
160
|
-
Optionally, add script aliases to your `package.json` for shorter invocation:
|
|
161
|
-
|
|
162
|
-
```json
|
|
163
|
-
{
|
|
164
|
-
"scripts": {
|
|
165
|
-
"gh-tool": "agent-tools-gh",
|
|
166
|
-
"audit-tool": "agent-tools-audit",
|
|
167
|
-
"k8s-tool": "agent-tools-k8s",
|
|
168
|
-
"db-tool": "agent-tools-db",
|
|
169
|
-
"logs-tool": "agent-tools-logs",
|
|
170
|
-
"session-tool": "agent-tools-session"
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
Then run via `bun run k8s-tool -- pods --env test` instead of `bunx agent-tools-k8s pods --env test`.
|
|
176
|
-
|
|
177
201
|
4. Hook up the credential guard in your agent config (Claude Code, OpenCode, etc.):
|
|
178
202
|
|
|
179
203
|
```typescript
|
|
@@ -184,19 +208,19 @@ export default { handleToolExecuteBefore };
|
|
|
184
208
|
|
|
185
209
|
## Tools
|
|
186
210
|
|
|
187
|
-
| Binary
|
|
188
|
-
|
|
|
189
|
-
| `
|
|
190
|
-
| `
|
|
191
|
-
| `
|
|
192
|
-
| `
|
|
193
|
-
| `
|
|
194
|
-
| `
|
|
195
|
-
| `
|
|
211
|
+
| Binary | Description |
|
|
212
|
+
| -------------- | ---------------------------------------------------------------------------------------------------------------- |
|
|
213
|
+
| `gh-tool` | GitHub CLI wrapper — PR management, issues, workflows, composite commands (`review-triage`, `reply-and-resolve`) |
|
|
214
|
+
| `audit-tool` | Audit trail browser — inspect recent tool invocations and purge old entries |
|
|
215
|
+
| `db-tool` | Database query tool — SQL execution, schema introspection |
|
|
216
|
+
| `k8s-tool` | Kubernetes tool — kubectl wrapper + structured commands (`pods`, `logs`, `describe`, `exec`, `top`) |
|
|
217
|
+
| `az-tool` | Azure DevOps tool — pipelines, builds, repos |
|
|
218
|
+
| `logs-tool` | Application logs — read local and remote (k8s pod) logs |
|
|
219
|
+
| `session-tool` | OpenCode session browser — list, read, search sessions |
|
|
196
220
|
|
|
197
|
-
All tools support `--help` for full usage documentation.
|
|
221
|
+
All tools support `--help` for full usage documentation. Legacy `agent-tools-*` binary names (e.g. `agent-tools-gh`) still work for backwards compatibility.
|
|
198
222
|
|
|
199
|
-
`
|
|
223
|
+
`audit-tool` reads the same SQLite file the wrappers write to. By default that file lives at `~/.agent-tools/audit.sqlite`, and you can override both path and retention per repo with the global `audit` config section.
|
|
200
224
|
|
|
201
225
|
## Audit Logging
|
|
202
226
|
|
|
@@ -212,19 +236,19 @@ Entries older than `retentionDays` (default: 90) are automatically purged on eac
|
|
|
212
236
|
|
|
213
237
|
```bash
|
|
214
238
|
# Recent 20 entries (default)
|
|
215
|
-
|
|
239
|
+
bun audit-tool list
|
|
216
240
|
|
|
217
241
|
# Last 50 entries, JSON format
|
|
218
|
-
|
|
242
|
+
bun audit-tool list --limit 50 --format json
|
|
219
243
|
|
|
220
244
|
# Filter by tool
|
|
221
|
-
|
|
245
|
+
bun audit-tool list --tool gh
|
|
222
246
|
|
|
223
247
|
# Filter by project directory
|
|
224
|
-
|
|
248
|
+
bun audit-tool list --project /Users/me/my-repo
|
|
225
249
|
|
|
226
250
|
# Purge entries older than 30 days
|
|
227
|
-
|
|
251
|
+
bun audit-tool purge --days 30
|
|
228
252
|
```
|
|
229
253
|
|
|
230
254
|
### Audit Configuration
|
|
@@ -293,8 +317,8 @@ Each tool section supports multiple named profiles. Select with `--profile <name
|
|
|
293
317
|
```
|
|
294
318
|
|
|
295
319
|
```bash
|
|
296
|
-
|
|
297
|
-
|
|
320
|
+
bun az-tool cmd --cmd "pipelines list" # uses "default" profile
|
|
321
|
+
bun az-tool cmd --cmd "pipelines list" --profile legacy # uses "legacy" profile
|
|
298
322
|
```
|
|
299
323
|
|
|
300
324
|
**Profile resolution:** `--profile` flag > auto-select (single profile) > `"default"` key > error.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blogic-cz/agent-tools",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
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",
|
|
@@ -25,7 +25,14 @@
|
|
|
25
25
|
"agent-tools-gh": "./src/gh-tool/index.ts",
|
|
26
26
|
"agent-tools-k8s": "./src/k8s-tool/index.ts",
|
|
27
27
|
"agent-tools-logs": "./src/logs-tool/index.ts",
|
|
28
|
-
"agent-tools-session": "./src/session-tool/index.ts"
|
|
28
|
+
"agent-tools-session": "./src/session-tool/index.ts",
|
|
29
|
+
"audit-tool": "./src/audit-tool/index.ts",
|
|
30
|
+
"az-tool": "./src/az-tool/index.ts",
|
|
31
|
+
"db-tool": "./src/db-tool/index.ts",
|
|
32
|
+
"gh-tool": "./src/gh-tool/index.ts",
|
|
33
|
+
"k8s-tool": "./src/k8s-tool/index.ts",
|
|
34
|
+
"logs-tool": "./src/logs-tool/index.ts",
|
|
35
|
+
"session-tool": "./src/session-tool/index.ts"
|
|
29
36
|
},
|
|
30
37
|
"files": [
|
|
31
38
|
"src/",
|
|
@@ -45,6 +45,7 @@ export type CredentialGuard = {
|
|
|
45
45
|
isDangerousBashCommand: (command: string) => boolean;
|
|
46
46
|
getBlockedCliTool: (command: string) => { name: string; wrapper: string } | null;
|
|
47
47
|
isGhCommandAllowed: (command: string) => boolean;
|
|
48
|
+
detectSleepPolling: (command: string) => string | null;
|
|
48
49
|
};
|
|
49
50
|
|
|
50
51
|
// ============================================================================
|
|
@@ -184,6 +185,34 @@ const DEFAULT_BLOCKED_CLI_TOOLS: BlockedCliTool[] = [
|
|
|
184
185
|
},
|
|
185
186
|
];
|
|
186
187
|
|
|
188
|
+
type PollingDetectionRule = {
|
|
189
|
+
pattern: RegExp;
|
|
190
|
+
suggestion: string;
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
const DEFAULT_POLLING_DETECTION_RULES: PollingDetectionRule[] = [
|
|
194
|
+
{
|
|
195
|
+
pattern: /workflow\s+(?:list|view|jobs|logs|job-logs)\b/,
|
|
196
|
+
suggestion: "bun agent-tools-gh workflow watch --run <ID>",
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
pattern: /pr\s+checks(?![\w-])(?!.*--watch)/,
|
|
200
|
+
suggestion: "bun agent-tools-gh pr checks --pr <N> --watch",
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
pattern: /pr\s+rerun-checks\b/,
|
|
204
|
+
suggestion: "bun agent-tools-gh pr checks --pr <N> --watch (after rerun completes)",
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
pattern: /kubectl\b/,
|
|
208
|
+
suggestion: 'bun agent-tools-k8s kubectl --env <env> --cmd "wait --for=condition=..."',
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
pattern: /\bpipelines?\s+runs?\b/,
|
|
212
|
+
suggestion: "bun agent-tools-az build summary --build-id <ID>",
|
|
213
|
+
},
|
|
214
|
+
];
|
|
215
|
+
|
|
187
216
|
/**
|
|
188
217
|
* Read-only gh subcommands safe on external repos with -R flag.
|
|
189
218
|
*/
|
|
@@ -325,6 +354,17 @@ export function createCredentialGuard(config?: CredentialGuardConfig): Credentia
|
|
|
325
354
|
return ghSegments.every((segment) => isGhCommandAllowed(segment.trim()));
|
|
326
355
|
}
|
|
327
356
|
|
|
357
|
+
function detectSleepPolling(command: string): string | null {
|
|
358
|
+
if (!/\bsleep\s+\d+/.test(command)) return null;
|
|
359
|
+
|
|
360
|
+
for (const { pattern, suggestion } of DEFAULT_POLLING_DETECTION_RULES) {
|
|
361
|
+
if (pattern.test(command)) {
|
|
362
|
+
return suggestion;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
return null;
|
|
366
|
+
}
|
|
367
|
+
|
|
328
368
|
function getBlockedCliTool(command: string): { name: string; wrapper: string } | null {
|
|
329
369
|
for (const { pattern, name, wrapper } of blockedCliTools) {
|
|
330
370
|
if (pattern.test(command)) {
|
|
@@ -390,6 +430,17 @@ export function createCredentialGuard(config?: CredentialGuardConfig): Credentia
|
|
|
390
430
|
);
|
|
391
431
|
}
|
|
392
432
|
|
|
433
|
+
const sleepSuggestion = detectSleepPolling(command);
|
|
434
|
+
if (sleepSuggestion) {
|
|
435
|
+
throw new Error(
|
|
436
|
+
`\u{26A0}\u{FE0F} Sleep-polling detected.\n\n` +
|
|
437
|
+
`Instead of polling with sleep, use the built-in watch command:\n\n` +
|
|
438
|
+
`Use instead: ${sleepSuggestion}\n\n` +
|
|
439
|
+
`Watch commands block until completion — no polling needed.\n\n` +
|
|
440
|
+
`→ Skill "agent-tools"`,
|
|
441
|
+
);
|
|
442
|
+
}
|
|
443
|
+
|
|
393
444
|
const blockedTool = getBlockedCliTool(command);
|
|
394
445
|
if (blockedTool) {
|
|
395
446
|
throw new Error(
|
|
@@ -412,6 +463,7 @@ export function createCredentialGuard(config?: CredentialGuardConfig): Credentia
|
|
|
412
463
|
isDangerousBashCommand,
|
|
413
464
|
getBlockedCliTool,
|
|
414
465
|
isGhCommandAllowed,
|
|
466
|
+
detectSleepPolling,
|
|
415
467
|
};
|
|
416
468
|
}
|
|
417
469
|
|
|
@@ -441,3 +493,6 @@ export const getBlockedCliTool = defaultGuard.getBlockedCliTool;
|
|
|
441
493
|
|
|
442
494
|
/** Check if a gh command is allowed (default guard). */
|
|
443
495
|
export const isGhCommandAllowed = defaultGuard.isGhCommandAllowed;
|
|
496
|
+
|
|
497
|
+
/** Detect sleep-polling with agent-tools wrapper commands (default guard). */
|
|
498
|
+
export const detectSleepPolling = defaultGuard.detectSleepPolling;
|
package/src/gh-tool/index.ts
CHANGED
|
@@ -47,6 +47,7 @@ import {
|
|
|
47
47
|
import { repoInfoCommand, repoListCommand, repoSearchCodeCommand } from "./repo";
|
|
48
48
|
import { GitHubService } from "./service";
|
|
49
49
|
import {
|
|
50
|
+
workflowAnnotationsCommand,
|
|
50
51
|
workflowCancelCommand,
|
|
51
52
|
workflowJobLogsCommand,
|
|
52
53
|
workflowJobsCommand,
|
|
@@ -104,7 +105,7 @@ const repoCommand = Command.make("repo", {}).pipe(
|
|
|
104
105
|
|
|
105
106
|
const workflowCommand = Command.make("workflow", {}).pipe(
|
|
106
107
|
Command.withDescription(
|
|
107
|
-
"GitHub Actions workflow operations (list runs, view, jobs, logs, job-logs, rerun, cancel, watch)",
|
|
108
|
+
"GitHub Actions workflow operations (list runs, view, jobs, logs, job-logs, annotations, rerun, cancel, watch)",
|
|
108
109
|
),
|
|
109
110
|
Command.withSubcommands([
|
|
110
111
|
workflowListCommand,
|
|
@@ -112,6 +113,7 @@ const workflowCommand = Command.make("workflow", {}).pipe(
|
|
|
112
113
|
workflowJobsCommand,
|
|
113
114
|
workflowLogsCommand,
|
|
114
115
|
workflowJobLogsCommand,
|
|
116
|
+
workflowAnnotationsCommand,
|
|
115
117
|
workflowRerunCommand,
|
|
116
118
|
workflowCancelCommand,
|
|
117
119
|
workflowWatchCommand,
|
|
@@ -152,10 +154,11 @@ WORKFLOW FOR AI AGENTS:
|
|
|
152
154
|
12. Use 'workflow view --run N' to inspect a specific run with jobs/steps
|
|
153
155
|
13. Use 'workflow logs --run N' to get logs (failed jobs by default)
|
|
154
156
|
14. Use 'workflow job-logs --run N --job "build-web-app"' to get clean parsed logs for a specific job
|
|
155
|
-
15. Use 'workflow
|
|
156
|
-
16. Use '
|
|
157
|
-
17. Use 'release
|
|
158
|
-
18. Use 'release
|
|
157
|
+
15. Use 'workflow annotations --run N' to list CI annotations (errors, warnings, notices)
|
|
158
|
+
16. Use 'workflow watch --run N' to watch until completion
|
|
159
|
+
17. Use 'release status' to inspect latest release + repository context
|
|
160
|
+
18. Use 'release create --tag vX.Y.Z --generate-notes' to publish a release
|
|
161
|
+
19. Use 'release edit/view/list/delete' to maintain existing releases`,
|
|
159
162
|
),
|
|
160
163
|
Command.withSubcommands([prCommand, issueCommand, repoCommand, workflowCommand, releaseCommand]),
|
|
161
164
|
);
|
package/src/gh-tool/types.ts
CHANGED
|
@@ -96,3 +96,21 @@ export type PRStatusNone = {
|
|
|
96
96
|
};
|
|
97
97
|
|
|
98
98
|
export type PRStatusResult = PRStatusSingle | PRStatusMultiple | PRStatusNone;
|
|
99
|
+
|
|
100
|
+
export type CheckRunAnnotation = {
|
|
101
|
+
path: string;
|
|
102
|
+
start_line: number;
|
|
103
|
+
end_line: number;
|
|
104
|
+
start_column: number | null;
|
|
105
|
+
end_column: number | null;
|
|
106
|
+
annotation_level: "notice" | "warning" | "failure";
|
|
107
|
+
title: string | null;
|
|
108
|
+
message: string;
|
|
109
|
+
raw_details: string | null;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
export type JobAnnotations = {
|
|
113
|
+
jobId: number;
|
|
114
|
+
jobName: string;
|
|
115
|
+
annotations: CheckRunAnnotation[];
|
|
116
|
+
};
|
package/src/gh-tool/workflow.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { Console, Effect, Option } from "effect";
|
|
|
4
4
|
import { formatOption, logFormatted } from "#shared";
|
|
5
5
|
import { GitHubCommandError, GitHubNotFoundError } from "./errors";
|
|
6
6
|
import { GitHubService } from "./service";
|
|
7
|
+
import type { CheckRunAnnotation, JobAnnotations } from "./types";
|
|
7
8
|
|
|
8
9
|
// ---------------------------------------------------------------------------
|
|
9
10
|
// Types
|
|
@@ -235,6 +236,69 @@ const watchRun = Effect.fn("workflow.watchRun")(function* (runId: number, repo:
|
|
|
235
236
|
};
|
|
236
237
|
});
|
|
237
238
|
|
|
239
|
+
const fetchAnnotations = Effect.fn("workflow.fetchAnnotations")(function* (opts: {
|
|
240
|
+
runId: number;
|
|
241
|
+
job: string | null;
|
|
242
|
+
repo: string | null;
|
|
243
|
+
}) {
|
|
244
|
+
const gh = yield* GitHubService;
|
|
245
|
+
|
|
246
|
+
let owner: string;
|
|
247
|
+
let repoName: string;
|
|
248
|
+
if (opts.repo !== null) {
|
|
249
|
+
const parts = opts.repo.split("/");
|
|
250
|
+
if (parts.length !== 2 || !parts[0] || !parts[1]) {
|
|
251
|
+
return yield* new GitHubCommandError({
|
|
252
|
+
message: `Invalid --repo format: "${opts.repo}". Expected "owner/name" (e.g. "blogic-cz/agent-tools").`,
|
|
253
|
+
command: "workflow annotations",
|
|
254
|
+
exitCode: 1,
|
|
255
|
+
stderr: "",
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
owner = parts[0];
|
|
259
|
+
repoName = parts[1];
|
|
260
|
+
} else {
|
|
261
|
+
const info = yield* gh.getRepoInfo();
|
|
262
|
+
owner = info.owner;
|
|
263
|
+
repoName = info.name;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const jobs = yield* listJobs(opts.runId, opts.repo);
|
|
267
|
+
|
|
268
|
+
let targetJobs = jobs;
|
|
269
|
+
if (opts.job !== null) {
|
|
270
|
+
const jobId = yield* resolveJobId(opts.runId, opts.job, opts.repo);
|
|
271
|
+
targetJobs = jobs.filter((j) => j.databaseId === jobId);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const results: JobAnnotations[] = [];
|
|
275
|
+
for (const job of targetJobs) {
|
|
276
|
+
const annotations = yield* gh
|
|
277
|
+
.runGhJson<CheckRunAnnotation[]>([
|
|
278
|
+
"api",
|
|
279
|
+
`repos/${owner}/${repoName}/check-runs/${job.databaseId}/annotations`,
|
|
280
|
+
"--paginate",
|
|
281
|
+
])
|
|
282
|
+
.pipe(
|
|
283
|
+
Effect.catchTag("GitHubCommandError", () => Effect.succeed([] as CheckRunAnnotation[])),
|
|
284
|
+
);
|
|
285
|
+
|
|
286
|
+
if (annotations.length > 0) {
|
|
287
|
+
results.push({
|
|
288
|
+
jobId: job.databaseId,
|
|
289
|
+
jobName: job.name,
|
|
290
|
+
annotations,
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
return {
|
|
296
|
+
runId: opts.runId,
|
|
297
|
+
totalAnnotations: results.reduce((sum, r) => sum + r.annotations.length, 0),
|
|
298
|
+
jobs: results,
|
|
299
|
+
};
|
|
300
|
+
});
|
|
301
|
+
|
|
238
302
|
// ---------------------------------------------------------------------------
|
|
239
303
|
// Log parsing utilities (pure functions)
|
|
240
304
|
// ---------------------------------------------------------------------------
|
|
@@ -605,3 +669,29 @@ export const workflowJobLogsCommand = Command.make(
|
|
|
605
669
|
"Fetch parsed, clean logs for a specific job in a workflow run. Resolves job name to ID, strips timestamps/ANSI, groups by step.",
|
|
606
670
|
),
|
|
607
671
|
);
|
|
672
|
+
|
|
673
|
+
export const workflowAnnotationsCommand = Command.make(
|
|
674
|
+
"annotations",
|
|
675
|
+
{
|
|
676
|
+
format: formatOption,
|
|
677
|
+
job: Flag.string("job").pipe(
|
|
678
|
+
Flag.withDescription("Filter to a specific job name (exact or partial match)"),
|
|
679
|
+
Flag.optional,
|
|
680
|
+
),
|
|
681
|
+
repo: repoOption,
|
|
682
|
+
run: Flag.integer("run").pipe(Flag.withDescription("Workflow run ID")),
|
|
683
|
+
},
|
|
684
|
+
({ format, job, repo, run }) =>
|
|
685
|
+
Effect.gen(function* () {
|
|
686
|
+
const result = yield* fetchAnnotations({
|
|
687
|
+
runId: run,
|
|
688
|
+
job: Option.getOrNull(job),
|
|
689
|
+
repo: Option.getOrNull(repo),
|
|
690
|
+
});
|
|
691
|
+
yield* logFormatted(result, format);
|
|
692
|
+
}),
|
|
693
|
+
).pipe(
|
|
694
|
+
Command.withDescription(
|
|
695
|
+
"List annotations (errors, warnings, notices) from check runs in a workflow run. Shows problem matcher output, test failures, and other CI annotations.",
|
|
696
|
+
),
|
|
697
|
+
);
|