@blogic-cz/agent-tools 1.4.0 → 1.4.2
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 +16 -2
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/types.d.ts +2 -0
- package/dist/config/types.d.ts.map +1 -1
- package/dist/credential-guard/index.d.ts.map +1 -1
- package/dist/gh-tool/branch.d.ts +2 -2
- package/dist/gh-tool/branch.d.ts.map +1 -1
- package/dist/gh-tool/gist.d.ts +6 -6
- package/dist/gh-tool/gist.d.ts.map +1 -1
- package/dist/gh-tool/issue/commands.d.ts +8 -8
- package/dist/gh-tool/issue/commands.d.ts.map +1 -1
- package/dist/gh-tool/issue/core.d.ts +8 -9
- package/dist/gh-tool/issue/core.d.ts.map +1 -1
- package/dist/gh-tool/issue/triage.d.ts +5 -5
- package/dist/gh-tool/issue/triage.d.ts.map +1 -1
- package/dist/gh-tool/pr/commands.d.ts +36 -36
- package/dist/gh-tool/pr/commands.d.ts.map +1 -1
- package/dist/gh-tool/pr/core.d.ts +13 -13
- package/dist/gh-tool/pr/core.d.ts.map +1 -1
- package/dist/gh-tool/pr/review.d.ts +14 -15
- package/dist/gh-tool/pr/review.d.ts.map +1 -1
- package/dist/gh-tool/pr/stack-read.d.ts +1 -1
- package/dist/gh-tool/pr/stack-read.d.ts.map +1 -1
- package/dist/gh-tool/pr/stack.d.ts +2 -2
- package/dist/gh-tool/pr/stack.d.ts.map +1 -1
- package/dist/gh-tool/release.d.ts +6 -6
- package/dist/gh-tool/release.d.ts.map +1 -1
- package/dist/gh-tool/repo.d.ts +3 -4
- package/dist/gh-tool/repo.d.ts.map +1 -1
- package/dist/gh-tool/service.d.ts +2 -2
- package/dist/gh-tool/service.d.ts.map +1 -1
- package/dist/gh-tool/workflow.d.ts +13 -13
- package/dist/gh-tool/workflow.d.ts.map +1 -1
- package/dist/observability-tool/trace.d.ts.map +1 -1
- package/package.json +1 -1
- package/schemas/agent-tools.schema.json +8 -0
- package/src/config/loader.ts +1 -0
- package/src/config/types.ts +2 -0
- package/src/credential-guard/claude-hook.ts +8 -2
- package/src/credential-guard/index.ts +212 -3
- package/src/gh-tool/pr/core.ts +56 -2
- package/src/gh-tool/service.ts +2 -2
- package/src/observability-tool/trace.ts +5 -1
package/dist/gh-tool/repo.d.ts
CHANGED
|
@@ -1,21 +1,20 @@
|
|
|
1
1
|
import { Command } from "effect/unstable/cli";
|
|
2
2
|
import { Option } from "effect";
|
|
3
|
-
import { GitHubCommandError } from "./errors";
|
|
4
3
|
import { GitHubService } from "./service";
|
|
5
4
|
export declare const repoInfoCommand: Command.Command<"info", {
|
|
6
5
|
readonly format: "json" | "toon";
|
|
7
6
|
readonly repo: Option.Option<string>;
|
|
8
|
-
}, {},
|
|
7
|
+
}, {}, import("./service").GhError, GitHubService>;
|
|
9
8
|
export declare const repoListCommand: Command.Command<"list", {
|
|
10
9
|
readonly format: "json" | "toon";
|
|
11
10
|
readonly limit: number;
|
|
12
11
|
readonly org: string;
|
|
13
12
|
readonly visibility: Option.Option<"public" | "all" | "private">;
|
|
14
|
-
}, {},
|
|
13
|
+
}, {}, import("./service").GhError, GitHubService>;
|
|
15
14
|
export declare const repoSearchCodeCommand: Command.Command<"search-code", {
|
|
16
15
|
readonly format: "json" | "toon";
|
|
17
16
|
readonly limit: number;
|
|
18
17
|
readonly org: string;
|
|
19
18
|
readonly query: string;
|
|
20
|
-
}, {},
|
|
19
|
+
}, {}, import("./service").GhError, GitHubService>;
|
|
21
20
|
//# sourceMappingURL=repo.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repo.d.ts","sourceRoot":"","sources":["../../src/gh-tool/repo.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAQ,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAU,MAAM,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"repo.d.ts","sourceRoot":"","sources":["../../src/gh-tool/repo.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAQ,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAU,MAAM,EAAE,MAAM,QAAQ,CAAC;AAIxC,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AA2F1C,eAAO,MAAM,eAAe;;;kDAcqE,CAAC;AAElG,eAAO,MAAM,eAAe;;;;;kDAyB3B,CAAC;AAEF,eAAO,MAAM,qBAAqB;;;;;kDAoB6C,CAAC"}
|
|
@@ -5,12 +5,12 @@ import type { RepoInfo } from "./types";
|
|
|
5
5
|
import { GitHubAuthError, GitHubCommandError, GitHubNotFoundError } from "./errors";
|
|
6
6
|
import type { GitHubApiRequest, GitHubApiResponse } from "./api";
|
|
7
7
|
import { ConfigService } from "#config";
|
|
8
|
-
type GhResult = {
|
|
8
|
+
export type GhResult = {
|
|
9
9
|
stdout: string;
|
|
10
10
|
stderr: string;
|
|
11
11
|
exitCode: number;
|
|
12
12
|
};
|
|
13
|
-
type GhError = GitHubCommandError | GitHubAuthError | GitHubNotFoundError;
|
|
13
|
+
export type GhError = GitHubCommandError | GitHubAuthError | GitHubNotFoundError;
|
|
14
14
|
declare const GitHubService_base: Context.ServiceClass<GitHubService, "@agent-tools/GitHubService", {
|
|
15
15
|
readonly runGh: (args: string[]) => Effect.Effect<GhResult, GhError>;
|
|
16
16
|
readonly runGhJson: <T>(args: string[]) => Effect.Effect<T, GhError>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/gh-tool/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC5E,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAU,MAAM,QAAQ,CAAC;AAExD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAChD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAGxC,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAGpF,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAC;AACjE,OAAO,EAAE,aAAa,EAA4C,MAAM,SAAS,CAAC;AA2DlF,
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/gh-tool/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC5E,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAU,MAAM,QAAQ,CAAC;AAExD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAChD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAGxC,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAGpF,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAC;AACjE,OAAO,EAAE,aAAa,EAA4C,MAAM,SAAS,CAAC;AA2DlF,MAAM,MAAM,QAAQ,GAAG;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG,kBAAkB,GAAG,eAAe,GAAG,mBAAmB,CAAC;;oBAK7D,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC;wBAChD,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC;yBAC/C,CACnB,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC,KAC9C,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC;yBACf,CAAC,CAAC,EACrB,IAAI,EAAE,gBAAgB,KACnB,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC;4BACzB,MAAM,MAAM,CAAC,MAAM,CAAC,gBAAgB,GAAG,SAAS,EAAE,KAAK,CAAC;0BAC1D,MAAM,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC;6BACnC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAC/B,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,KAC3B,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,kBAAkB,EAAE,CAAC,CAAC;;AAjBpD,qBAAa,aAAc,SAAQ,kBAmBF;IAC/B,MAAM,CAAC,QAAQ,CAAC,KAAK,6FAsRnB;CACH"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Command } from "effect/unstable/cli";
|
|
2
2
|
import { Effect, Option } from "effect";
|
|
3
|
-
import {
|
|
3
|
+
import { GitHubNotFoundError } from "./errors";
|
|
4
4
|
import { GitHubService } from "./service";
|
|
5
5
|
import type { LogDiagnosis } from "./types";
|
|
6
6
|
export type LogEntry = {
|
|
@@ -18,7 +18,7 @@ export declare const dispatchWorkflow: (opts: {
|
|
|
18
18
|
ref: string;
|
|
19
19
|
repo: string | null;
|
|
20
20
|
fields: readonly string[];
|
|
21
|
-
},
|
|
21
|
+
}, import("./service").GhError, GitHubService>;
|
|
22
22
|
export type DispatchedRun = {
|
|
23
23
|
databaseId: number;
|
|
24
24
|
headSha: string;
|
|
@@ -90,7 +90,7 @@ export declare const fetchJobLogs: (opts: {
|
|
|
90
90
|
formatted: string;
|
|
91
91
|
diagnosis?: undefined;
|
|
92
92
|
entries?: undefined;
|
|
93
|
-
},
|
|
93
|
+
}, import("./service").GhError, GitHubService>;
|
|
94
94
|
export declare const workflowListCommand: Command.Command<"list", {
|
|
95
95
|
readonly branch: Option.Option<string>;
|
|
96
96
|
readonly format: "json" | "toon";
|
|
@@ -98,48 +98,48 @@ export declare const workflowListCommand: Command.Command<"list", {
|
|
|
98
98
|
readonly repo: Option.Option<string>;
|
|
99
99
|
readonly status: Option.Option<"success" | "completed" | "skipped" | "failure" | "queued" | "in_progress" | "action_required" | "cancelled" | "neutral" | "stale" | "timed_out" | "waiting">;
|
|
100
100
|
readonly workflow: Option.Option<string>;
|
|
101
|
-
}, {},
|
|
101
|
+
}, {}, import("./service").GhError, GitHubService>;
|
|
102
102
|
export declare const workflowViewCommand: Command.Command<"view", {
|
|
103
103
|
readonly format: "json" | "toon";
|
|
104
104
|
readonly repo: Option.Option<string>;
|
|
105
105
|
readonly run: number;
|
|
106
|
-
}, {},
|
|
106
|
+
}, {}, import("./service").GhError, GitHubService>;
|
|
107
107
|
export declare const workflowJobsCommand: Command.Command<"jobs", {
|
|
108
108
|
readonly format: "json" | "toon";
|
|
109
109
|
readonly repo: Option.Option<string>;
|
|
110
110
|
readonly run: number;
|
|
111
|
-
}, {},
|
|
111
|
+
}, {}, import("./service").GhError, GitHubService>;
|
|
112
112
|
export declare const workflowLogsCommand: Command.Command<"logs", {
|
|
113
113
|
readonly failedOnly: boolean;
|
|
114
114
|
readonly format: "json" | "toon";
|
|
115
115
|
readonly repo: Option.Option<string>;
|
|
116
116
|
readonly run: number;
|
|
117
|
-
}, {},
|
|
117
|
+
}, {}, import("./service").GhError, GitHubService>;
|
|
118
118
|
export declare const workflowRerunCommand: Command.Command<"rerun", {
|
|
119
119
|
readonly failedOnly: boolean;
|
|
120
120
|
readonly format: "json" | "toon";
|
|
121
121
|
readonly repo: Option.Option<string>;
|
|
122
122
|
readonly run: number;
|
|
123
|
-
}, {},
|
|
123
|
+
}, {}, import("./service").GhError, GitHubService>;
|
|
124
124
|
export declare const workflowCancelCommand: Command.Command<"cancel", {
|
|
125
125
|
readonly format: "json" | "toon";
|
|
126
126
|
readonly repo: Option.Option<string>;
|
|
127
127
|
readonly run: number;
|
|
128
|
-
}, {},
|
|
128
|
+
}, {}, import("./service").GhError, GitHubService>;
|
|
129
129
|
export declare const workflowRunCommand: Command.Command<"run", {
|
|
130
130
|
readonly field: readonly string[];
|
|
131
131
|
readonly format: "json" | "toon";
|
|
132
132
|
readonly ref: string;
|
|
133
133
|
readonly repo: Option.Option<string>;
|
|
134
134
|
readonly workflow: string;
|
|
135
|
-
}, {},
|
|
135
|
+
}, {}, import("./service").GhError, GitHubService>;
|
|
136
136
|
export declare const workflowWatchCommand: Command.Command<"watch", {
|
|
137
137
|
readonly format: "json" | "toon";
|
|
138
138
|
readonly frames: boolean;
|
|
139
139
|
readonly repo: Option.Option<string>;
|
|
140
140
|
readonly run: number;
|
|
141
141
|
readonly timeout: number;
|
|
142
|
-
}, {},
|
|
142
|
+
}, {}, import("./service").GhError, GitHubService>;
|
|
143
143
|
export declare const workflowJobLogsCommand: Command.Command<"job-logs", {
|
|
144
144
|
readonly diagnose: boolean;
|
|
145
145
|
readonly failedStepsOnly: boolean;
|
|
@@ -147,11 +147,11 @@ export declare const workflowJobLogsCommand: Command.Command<"job-logs", {
|
|
|
147
147
|
readonly job: string;
|
|
148
148
|
readonly repo: Option.Option<string>;
|
|
149
149
|
readonly run: number;
|
|
150
|
-
}, {},
|
|
150
|
+
}, {}, import("./service").GhError, GitHubService>;
|
|
151
151
|
export declare const workflowAnnotationsCommand: Command.Command<"annotations", {
|
|
152
152
|
readonly format: "json" | "toon";
|
|
153
153
|
readonly job: Option.Option<string>;
|
|
154
154
|
readonly repo: Option.Option<string>;
|
|
155
155
|
readonly run: number;
|
|
156
|
-
}, {},
|
|
156
|
+
}, {}, import("./service").GhError, GitHubService>;
|
|
157
157
|
//# sourceMappingURL=workflow.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workflow.d.ts","sourceRoot":"","sources":["../../src/gh-tool/workflow.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAe,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAY,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAIlD,OAAO,
|
|
1
|
+
{"version":3,"file":"workflow.d.ts","sourceRoot":"","sources":["../../src/gh-tool/workflow.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAe,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAY,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAIlD,OAAO,EAAsB,mBAAmB,EAAE,MAAM,UAAU,CAAC;AACnE,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,KAAK,EAAsC,YAAY,EAAE,MAAM,SAAS,CAAC;AAwChF,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAqKF,eAAO,MAAM,gBAAgB;cACjB,MAAM;SACX,MAAM;YACH,aAAa,CAAC,MAAM,CAAC;UACvB,MAAM,GAAG,IAAI;;;;;;;8CAsBnB,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAKF,eAAO,MAAM,kBAAkB;cACnB,MAAM;SACX,MAAM;UACL,MAAM,GAAG,IAAI;6GAyBnB,CAAC;AAKH,eAAO,MAAM,qBAAqB;cACtB,MAAM;SACX,MAAM;UACL,MAAM,GAAG,IAAI;iBACN,WAAW,CAAC,MAAM,CAAC;kHAShC,CAAC;AAMH,eAAO,MAAM,gBAAgB,GAC3B,OAAO,MAAM,EACb,YAAY;IACV,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,IAAI,EAAE,aAAa,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;CAClF,EACD,aAAa,MAAM,GAAG,IAAI,EAC1B,QAAQ,OAAO,EACf,gBAAgB,MAAM;;;;;;;;;;CAiBtB,CAAC;AAmHH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAOjD;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,EAAE,CAsBvD;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,QAAQ,EAAE,GAAG,MAAM,CAa5D;AAgBD,eAAO,MAAM,kBAAkB,GAAI,SAAS,SAAS,QAAQ,EAAE,KAAG,YA0CjE,CAAC;AA0DF,eAAO,MAAM,YAAY;WAChB,MAAM;SACR,MAAM;YACH,MAAM,GAAG,IAAI;sBACH,SAAS,MAAM,EAAE,GAAG,IAAI;qBACzB,OAAO;eACb,OAAO;YACV,MAAM;UACR,MAAM,GAAG,IAAI;;;;;;;;;;;;;;;;;;;;;;8CA8DnB,CAAC;AAMH,eAAO,MAAM,mBAAmB;;;;;;;kDA8C/B,CAAC;AAEF,eAAO,MAAM,mBAAmB;;;;kDAaqD,CAAC;AAEtF,eAAO,MAAM,mBAAmB;;;;kDAa+C,CAAC;AAEhF,eAAO,MAAM,mBAAmB;;;;;kDAsB2D,CAAC;AAE5F,eAAO,MAAM,oBAAoB;;;;;kDAiBoD,CAAC;AAEtF,eAAO,MAAM,qBAAqB;;;;kDAamC,CAAC;AAEtE,eAAO,MAAM,kBAAkB;;;;;;kDAgD6C,CAAC;AAE7E,eAAO,MAAM,oBAAoB;;;;;;kDA4BiE,CAAC;AAEnG,eAAO,MAAM,sBAAsB;;;;;;;kDAwClC,CAAC;AAEF,eAAO,MAAM,0BAA0B;;;;;kDAyBtC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trace.d.ts","sourceRoot":"","sources":["../../src/observability-tool/trace.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAe,MAAM,QAAQ,CAAC;AAC7C,OAAO,EAAY,OAAO,EAAQ,MAAM,qBAAqB,CAAC;AAK9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAWlD,OAAO,KAAK,EAEV,sBAAsB,EAItB,YAAY,EAEZ,mBAAmB,EAEnB,cAAc,EAEf,MAAM,SAAS,CAAC;AAuVjB,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,mBAAmB,GAAG,cAAc,EAAE,CAsBnF;AAED,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,sBAAsB,EAC9B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,YAAY,EACpB,KAAK,EAAE,MAAM,GACZ,MAAM,CAAC,MAAM,CAAC,mBAAmB,EAAE,sBAAsB,CAAC,CA4C5D;
|
|
1
|
+
{"version":3,"file":"trace.d.ts","sourceRoot":"","sources":["../../src/observability-tool/trace.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAe,MAAM,QAAQ,CAAC;AAC7C,OAAO,EAAY,OAAO,EAAQ,MAAM,qBAAqB,CAAC;AAK9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAWlD,OAAO,KAAK,EAEV,sBAAsB,EAItB,YAAY,EAEZ,mBAAmB,EAEnB,cAAc,EAEf,MAAM,SAAS,CAAC;AAuVjB,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,mBAAmB,GAAG,cAAc,EAAE,CAsBnF;AAED,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,sBAAsB,EAC9B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,YAAY,EACpB,KAAK,EAAE,MAAM,GACZ,MAAM,CAAC,MAAM,CAAC,mBAAmB,EAAE,sBAAsB,CAAC,CA4C5D;AAoPD,eAAO,MAAM,YAAY,iFAGxB,CAAC"}
|
package/package.json
CHANGED
|
@@ -463,6 +463,14 @@
|
|
|
463
463
|
"type": "object",
|
|
464
464
|
"additionalProperties": false,
|
|
465
465
|
"properties": {
|
|
466
|
+
"allowedEnvironmentVariables": {
|
|
467
|
+
"description": "Exact, case-sensitive environment names approved for static printenv reads. Empty by default.",
|
|
468
|
+
"type": "array",
|
|
469
|
+
"items": {
|
|
470
|
+
"type": "string",
|
|
471
|
+
"pattern": "^[A-Za-z_][A-Za-z0-9_]*$"
|
|
472
|
+
}
|
|
473
|
+
},
|
|
466
474
|
"additionalBlockedPaths": {
|
|
467
475
|
"description": "Additional blocked file path patterns.",
|
|
468
476
|
"type": "array",
|
package/src/config/loader.ts
CHANGED
|
@@ -11,6 +11,7 @@ const CliToolOverrideSchema = Schema.Struct({
|
|
|
11
11
|
});
|
|
12
12
|
|
|
13
13
|
const CredentialGuardConfigSchema = Schema.Struct({
|
|
14
|
+
allowedEnvironmentVariables: Schema.optionalKey(Schema.Array(Schema.String)),
|
|
14
15
|
additionalBlockedPaths: Schema.optionalKey(Schema.Array(Schema.String)),
|
|
15
16
|
additionalAllowedPaths: Schema.optionalKey(Schema.Array(Schema.String)),
|
|
16
17
|
additionalBlockedCliTools: Schema.optionalKey(Schema.Array(CliToolOverrideSchema)),
|
package/src/config/types.ts
CHANGED
|
@@ -185,6 +185,8 @@ export type CliToolOverride = {
|
|
|
185
185
|
|
|
186
186
|
/** Credential guard config - merged with built-in defaults */
|
|
187
187
|
export type CredentialGuardConfig = {
|
|
188
|
+
/** Exact, case-sensitive names approved for static printenv reads. Empty by default. */
|
|
189
|
+
allowedEnvironmentVariables?: string[];
|
|
188
190
|
additionalBlockedPaths?: string[];
|
|
189
191
|
additionalAllowedPaths?: string[];
|
|
190
192
|
additionalBlockedCliTools?: CliToolOverride[];
|
|
@@ -10,7 +10,9 @@
|
|
|
10
10
|
* "command": "bun node_modules/@blogic-cz/agent-tools/src/credential-guard/claude-hook.ts" }] }] } }
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import {
|
|
13
|
+
import { loadConfig } from "#config/loader";
|
|
14
|
+
|
|
15
|
+
import { createCredentialGuard } from "./index";
|
|
14
16
|
|
|
15
17
|
const stdin = await Bun.stdin.text();
|
|
16
18
|
|
|
@@ -20,7 +22,11 @@ try {
|
|
|
20
22
|
tool_input?: Record<string, unknown>;
|
|
21
23
|
} = JSON.parse(stdin);
|
|
22
24
|
|
|
23
|
-
|
|
25
|
+
const config = await loadConfig();
|
|
26
|
+
createCredentialGuard(config?.credentialGuard).handleToolExecuteBefore(
|
|
27
|
+
{ tool: data.tool_name },
|
|
28
|
+
{ args: data.tool_input ?? {} },
|
|
29
|
+
);
|
|
24
30
|
} catch (error: unknown) {
|
|
25
31
|
const message = error instanceof Error ? error.message : String(error);
|
|
26
32
|
process.stderr.write(message);
|
|
@@ -143,8 +143,6 @@ const SECRET_PATTERNS = [
|
|
|
143
143
|
* Dangerous bash patterns that might expose secrets.
|
|
144
144
|
*/
|
|
145
145
|
const DEFAULT_DANGEROUS_BASH_PATTERNS: RegExp[] = [
|
|
146
|
-
/printenv/i,
|
|
147
|
-
/(?:^|&&|\||;)\s*env(?:\s|$)/i,
|
|
148
146
|
/\bcat\s+\S*\.env/i,
|
|
149
147
|
/\bcat\s+\S*\.pem/i,
|
|
150
148
|
/\bcat\s+\S*\.key/i,
|
|
@@ -245,6 +243,201 @@ function escapeRegex(s: string): string {
|
|
|
245
243
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
246
244
|
}
|
|
247
245
|
|
|
246
|
+
/** Static shell words only. Never expand variables or execute a command. */
|
|
247
|
+
function parseStaticShellCommands(
|
|
248
|
+
command: string,
|
|
249
|
+
): { pipelines: string[][][] } | "brace-expansion" | undefined {
|
|
250
|
+
const pipelines: string[][][] = [];
|
|
251
|
+
let commands: string[][] = [];
|
|
252
|
+
let argv: string[] = [];
|
|
253
|
+
let word = "";
|
|
254
|
+
let started = false;
|
|
255
|
+
let quote: "'" | '"' | undefined;
|
|
256
|
+
|
|
257
|
+
const finishWord = () => {
|
|
258
|
+
if (started) argv.push(word);
|
|
259
|
+
word = "";
|
|
260
|
+
started = false;
|
|
261
|
+
};
|
|
262
|
+
const finishCommand = () => {
|
|
263
|
+
finishWord();
|
|
264
|
+
if (argv.length) commands.push(argv);
|
|
265
|
+
argv = [];
|
|
266
|
+
};
|
|
267
|
+
const finishPipeline = () => {
|
|
268
|
+
finishCommand();
|
|
269
|
+
if (commands.length) pipelines.push(commands);
|
|
270
|
+
commands = [];
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
for (let i = 0; i < command.length; i++) {
|
|
274
|
+
const char = command.charAt(i);
|
|
275
|
+
if (quote === "'") {
|
|
276
|
+
if (char === quote) quote = undefined;
|
|
277
|
+
else word += char;
|
|
278
|
+
} else if (char === "\\") {
|
|
279
|
+
const next = command[++i];
|
|
280
|
+
if (next === undefined || next === "\n" || next === "\r") return undefined;
|
|
281
|
+
if (quote === '"' && !/[\\$`"]/.test(next)) word += "\\";
|
|
282
|
+
word += next;
|
|
283
|
+
started = true;
|
|
284
|
+
} else if (char === "$" || char === "`") {
|
|
285
|
+
return undefined;
|
|
286
|
+
} else if (quote === '"') {
|
|
287
|
+
if (char === quote) quote = undefined;
|
|
288
|
+
else word += char;
|
|
289
|
+
} else if (char === "'" || char === '"') {
|
|
290
|
+
quote = char;
|
|
291
|
+
started = true;
|
|
292
|
+
} else if (char === "{" && /^\{[^{}]*(?:,|\.\.)[^{}]*\}/.test(command.slice(i))) {
|
|
293
|
+
return "brace-expansion";
|
|
294
|
+
} else if (/[<>()]/.test(char) || (char === "#" && !started)) {
|
|
295
|
+
return undefined;
|
|
296
|
+
} else if (char === "|" && command[i - 1] !== "|" && command[i + 1] !== "|") {
|
|
297
|
+
finishCommand();
|
|
298
|
+
if (command[i + 1] === "&") i++;
|
|
299
|
+
} else if (/[;&|\r\n]/.test(char)) {
|
|
300
|
+
finishPipeline();
|
|
301
|
+
} else if (/\s/.test(char)) {
|
|
302
|
+
finishWord();
|
|
303
|
+
} else {
|
|
304
|
+
word += char;
|
|
305
|
+
started = true;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
if (quote) return undefined;
|
|
310
|
+
finishPipeline();
|
|
311
|
+
return { pipelines };
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function mentionsEnvironmentRead(text: string): boolean {
|
|
315
|
+
return /printenv|\benv\b/i.test(text.replace(/['"\\]/g, ""));
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
function hasBraceExpansion(text: string): boolean {
|
|
319
|
+
return /\{[^{}]*(?:,|\.\.)[^{}]*\}/.test(text);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function unwrapStaticCommand(words: string[]): string[] {
|
|
323
|
+
const argv = [...words];
|
|
324
|
+
const executable = () => argv[0]?.split("/").at(-1);
|
|
325
|
+
while (executable() === "rtk" || executable() === "command") {
|
|
326
|
+
const wrapper = executable();
|
|
327
|
+
argv.shift();
|
|
328
|
+
if (wrapper === "rtk" && argv[0] === "proxy") argv.shift();
|
|
329
|
+
if (wrapper === "command" && argv[0] === "--") argv.shift();
|
|
330
|
+
}
|
|
331
|
+
return argv;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
function isAllowedEnvironmentRead(argv: string[], allowedNames: Set<string>): boolean {
|
|
335
|
+
if (argv[0]?.split("/").at(-1) !== "printenv") return false;
|
|
336
|
+
const args = argv.slice(1);
|
|
337
|
+
if (args[0] === "--") args.shift();
|
|
338
|
+
return args.length > 0 && args.every((name) => allowedNames.has(name));
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
function hasExecutionOption(args: string[], longOptions: string[], shortOption?: string): boolean {
|
|
342
|
+
return args.some((arg) => {
|
|
343
|
+
const flag = arg.split("=", 1)[0] ?? "";
|
|
344
|
+
if (flag.startsWith("--") && flag.length > 2) {
|
|
345
|
+
// Git supports long-option abbreviations. Refuse ambiguous prefixes too.
|
|
346
|
+
return longOptions.some((option) => option.startsWith(flag.slice(2)));
|
|
347
|
+
}
|
|
348
|
+
return shortOption !== undefined && /^-[^-]/.test(flag) && flag.includes(shortOption);
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
function isPassiveTextCommand(argv: string[]): boolean {
|
|
353
|
+
const name = argv[0]?.split("/").at(-1) ?? "";
|
|
354
|
+
const args = argv.slice(1);
|
|
355
|
+
// These commands consume literal text. Execution options are not exceptions.
|
|
356
|
+
if (["echo", "printf", "grep", "head"].includes(name)) {
|
|
357
|
+
return true;
|
|
358
|
+
}
|
|
359
|
+
if (name === "rg") return !hasExecutionOption(args, ["pre", "hostname-bin"]);
|
|
360
|
+
return (
|
|
361
|
+
name === "git" &&
|
|
362
|
+
args[0] === "grep" &&
|
|
363
|
+
!hasExecutionOption(args, ["open-files-in-pager", "textconv"], "O")
|
|
364
|
+
);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
function hasStaticEnvironmentRead(argv: string[], allowedNames: Set<string>): boolean {
|
|
368
|
+
const name = argv[0]?.split("/").at(-1);
|
|
369
|
+
if (name === "printenv") return !isAllowedEnvironmentRead(argv, allowedNames);
|
|
370
|
+
if (name === "env") return true;
|
|
371
|
+
if (isPassiveTextCommand(argv)) return false;
|
|
372
|
+
if (
|
|
373
|
+
argv.some((arg) =>
|
|
374
|
+
["sh", "bash", "zsh", "dash", "ksh", "fish", "csh", "tcsh", "eval"].includes(
|
|
375
|
+
arg.split("/").at(-1) ?? "",
|
|
376
|
+
),
|
|
377
|
+
) &&
|
|
378
|
+
hasBraceExpansion(argv.slice(1).join(" "))
|
|
379
|
+
) {
|
|
380
|
+
return true;
|
|
381
|
+
}
|
|
382
|
+
return mentionsEnvironmentRead(argv.join(" "));
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
function hasEnvironmentRead(command: string, allowedNames: Set<string>): boolean {
|
|
386
|
+
if (isLiteralTextWrite(command)) return false;
|
|
387
|
+
// ponytail: complex shell syntax stays conservative; use a shell AST if more exceptions are needed.
|
|
388
|
+
const parsed = parseStaticShellCommands(command);
|
|
389
|
+
if (parsed === "brace-expansion") return true;
|
|
390
|
+
if (!parsed) return mentionsEnvironmentRead(command) || hasBraceExpansion(command);
|
|
391
|
+
const pipelines = parsed.pipelines.map((commands) => commands.map(unwrapStaticCommand));
|
|
392
|
+
const unwrapped = pipelines.flat();
|
|
393
|
+
if (unwrapped.some((argv) => hasStaticEnvironmentRead(argv, allowedNames))) return true;
|
|
394
|
+
|
|
395
|
+
// A literal producer can feed executable text to a shell, xargs, or an unknown consumer.
|
|
396
|
+
return pipelines.some(
|
|
397
|
+
(pipeline) =>
|
|
398
|
+
pipeline.length > 1 &&
|
|
399
|
+
pipeline.some(
|
|
400
|
+
(argv) =>
|
|
401
|
+
isAllowedEnvironmentRead(argv, allowedNames) ||
|
|
402
|
+
(isPassiveTextCommand(argv) &&
|
|
403
|
+
(mentionsEnvironmentRead(argv.join(" ")) || hasBraceExpansion(argv.join(" ")))),
|
|
404
|
+
) &&
|
|
405
|
+
pipeline.some(
|
|
406
|
+
(argv) => !isPassiveTextCommand(argv) && !isAllowedEnvironmentRead(argv, allowedNames),
|
|
407
|
+
),
|
|
408
|
+
);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/** A single literal writer cannot execute its body or feed another command. */
|
|
412
|
+
function isLiteralTextWrite(command: string): boolean {
|
|
413
|
+
const lines = command.trimEnd().split(/\r?\n/);
|
|
414
|
+
const heredoc = /^(.*?)<<(-?)[ \t]*(['"]?)([A-Za-z_][A-Za-z0-9_]*)\3[ \t]*$/.exec(lines[0] ?? "");
|
|
415
|
+
let header = command;
|
|
416
|
+
let writers = ["echo", "printf"];
|
|
417
|
+
if (heredoc) {
|
|
418
|
+
const [, prefix, stripTabs, quote, delimiter] = heredoc;
|
|
419
|
+
const end = lines.findIndex(
|
|
420
|
+
(line, index) => index > 0 && (stripTabs ? line.replace(/^\t+/, "") : line) === delimiter,
|
|
421
|
+
);
|
|
422
|
+
// Only the first delimiter closes the body. No following commands are exceptions.
|
|
423
|
+
if (end < 0 || end !== lines.length - 1) return false;
|
|
424
|
+
const body = lines.slice(1, end).join("\n");
|
|
425
|
+
if (!quote && /[$`\\]/.test(body)) return false;
|
|
426
|
+
header = prefix ?? "";
|
|
427
|
+
writers = ["cat", "tee"];
|
|
428
|
+
} else if (!command.includes(">")) {
|
|
429
|
+
return false;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// Output redirection does not execute text. Other unsupported syntax still fails parsing.
|
|
433
|
+
const parsed = parseStaticShellCommands(header.replace(/>/g, " "));
|
|
434
|
+
if (!parsed || parsed === "brace-expansion" || parsed.pipelines.length !== 1) return false;
|
|
435
|
+
const pipeline = parsed.pipelines[0];
|
|
436
|
+
if (pipeline?.length !== 1) return false;
|
|
437
|
+
const argv = unwrapStaticCommand(pipeline[0] ?? []);
|
|
438
|
+
return writers.includes(argv[0]?.split("/").at(-1) ?? "");
|
|
439
|
+
}
|
|
440
|
+
|
|
248
441
|
/** Extract file path from hook arguments. */
|
|
249
442
|
export function extractFilePath(args: Record<string, unknown>): string {
|
|
250
443
|
return (args.filePath as string) || (args.file_path as string) || (args.path as string) || "";
|
|
@@ -271,6 +464,19 @@ export function extractCommand(args: Record<string, unknown>): string {
|
|
|
271
464
|
* @returns Object with all guard functions bound to the merged pattern sets.
|
|
272
465
|
*/
|
|
273
466
|
export function createCredentialGuard(config?: CredentialGuardConfig): CredentialGuard {
|
|
467
|
+
const names = config?.allowedEnvironmentVariables;
|
|
468
|
+
if (
|
|
469
|
+
names !== undefined &&
|
|
470
|
+
(!Array.isArray(names) || names.some((name) => typeof name !== "string"))
|
|
471
|
+
) {
|
|
472
|
+
throw new Error("allowedEnvironmentVariables must be an array of strings");
|
|
473
|
+
}
|
|
474
|
+
const allowedEnvironmentVariables = new Set(names ?? []);
|
|
475
|
+
for (const name of allowedEnvironmentVariables) {
|
|
476
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) {
|
|
477
|
+
throw new Error(`Invalid allowed environment variable name: ${JSON.stringify(name)}`);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
274
480
|
const blockedPathPatterns = [
|
|
275
481
|
...DEFAULT_BLOCKED_PATH_PATTERNS,
|
|
276
482
|
...(config?.additionalBlockedPaths ?? []).map((p) => new RegExp(p)),
|
|
@@ -332,7 +538,10 @@ export function createCredentialGuard(config?: CredentialGuardConfig): Credentia
|
|
|
332
538
|
}
|
|
333
539
|
|
|
334
540
|
function isDangerousBashCommand(command: string): boolean {
|
|
335
|
-
return
|
|
541
|
+
return (
|
|
542
|
+
dangerousBashPatterns.some((pattern) => pattern.test(command)) ||
|
|
543
|
+
hasEnvironmentRead(command, allowedEnvironmentVariables)
|
|
544
|
+
);
|
|
336
545
|
}
|
|
337
546
|
|
|
338
547
|
function isGhCommandAllowed(command: string): boolean {
|
package/src/gh-tool/pr/core.ts
CHANGED
|
@@ -19,6 +19,7 @@ import type {
|
|
|
19
19
|
import type { GitHubAuthError, GitHubNotFoundError } from "#gh/errors";
|
|
20
20
|
import { GitHubCommandError, GitHubMergeError } from "#gh/errors";
|
|
21
21
|
import { GitHubService } from "#gh/service";
|
|
22
|
+
import type { GhResult } from "#gh/service";
|
|
22
23
|
import { logText } from "#shared";
|
|
23
24
|
|
|
24
25
|
import type { ButStatusJson, PRViewJsonResult } from "./helpers";
|
|
@@ -201,6 +202,13 @@ const fetchWorkflowRunFailureContext = Effect.fn("pr.fetchWorkflowRunFailureCont
|
|
|
201
202
|
// `gh pr checks` exits 1 on an *empty* result ("no checks reported on the 'x' branch"). Zero checks
|
|
202
203
|
// is an ordinary state, so map it to [] and keep the zero-check paths downstream reachable.
|
|
203
204
|
export const NO_CHECKS_REPORTED_RE = /no checks reported/i;
|
|
205
|
+
// `gh` reports "no checks reported" both for the seconds after a push, before its checks
|
|
206
|
+
// register, and forever for a PR that has none — the message cannot tell them apart. So the
|
|
207
|
+
// wait for registration gets its own short budget: long enough to cover the race (measured
|
|
208
|
+
// at roughly 40s on blogic-cz/agent-tools#134), short enough that a check-less PR is not held
|
|
209
|
+
// for the caller's whole --timeout.
|
|
210
|
+
const CHECK_REGISTRATION_POLL_SECONDS = 5;
|
|
211
|
+
const CHECK_REGISTRATION_GRACE_SECONDS = 60;
|
|
204
212
|
|
|
205
213
|
export const fetchCheckResults = Effect.fn("pr.fetchCheckResults")(function* (pr: number | null) {
|
|
206
214
|
const gh = yield* GitHubService;
|
|
@@ -1244,7 +1252,45 @@ export const fetchChecks = Effect.fn("pr.fetchChecks")(function* (
|
|
|
1244
1252
|
// Block for the caller's requested --timeout (no artificial cap — blocking isn't the problem;
|
|
1245
1253
|
// --timeout is validated >= 1s at the CLI boundary). On timeout return a snapshot, never
|
|
1246
1254
|
// nothing — that was the actual token-wasting bug.
|
|
1247
|
-
|
|
1255
|
+
// A push registers its checks a moment after the ref lands, and `gh pr checks --watch`
|
|
1256
|
+
// exits non-zero in that window. A watch was asked to wait, so keep waiting: the outer
|
|
1257
|
+
// timeout still bounds it, and a PR that genuinely has no checks returns an empty
|
|
1258
|
+
// snapshot at that deadline rather than an error.
|
|
1259
|
+
let watchResult: GhResult | null = null;
|
|
1260
|
+
let registered = false;
|
|
1261
|
+
let graceExpired = false;
|
|
1262
|
+
const watchThroughRegistration = Effect.gen(function* () {
|
|
1263
|
+
const graceStart = yield* Clock.currentTimeMillis;
|
|
1264
|
+
const graceDeadlineMs =
|
|
1265
|
+
Number(graceStart) + Math.min(CHECK_REGISTRATION_GRACE_SECONDS, timeoutSeconds) * 1000;
|
|
1266
|
+
yield* Effect.whileLoop({
|
|
1267
|
+
while: () => !registered && !graceExpired,
|
|
1268
|
+
body: () =>
|
|
1269
|
+
gh.runGh(watchArgs).pipe(
|
|
1270
|
+
Effect.flatMap((result) => {
|
|
1271
|
+
watchResult = result;
|
|
1272
|
+
registered = true;
|
|
1273
|
+
return Effect.void;
|
|
1274
|
+
}),
|
|
1275
|
+
Effect.catchTag("GitHubCommandError", (error) =>
|
|
1276
|
+
NO_CHECKS_REPORTED_RE.test(error.stderr) || NO_CHECKS_REPORTED_RE.test(error.message)
|
|
1277
|
+
? Effect.gen(function* () {
|
|
1278
|
+
const now = yield* Clock.currentTimeMillis;
|
|
1279
|
+
if (Number(now) >= graceDeadlineMs) {
|
|
1280
|
+
graceExpired = true;
|
|
1281
|
+
return;
|
|
1282
|
+
}
|
|
1283
|
+
yield* Effect.sleep(Duration.seconds(CHECK_REGISTRATION_POLL_SECONDS));
|
|
1284
|
+
})
|
|
1285
|
+
: Effect.fail(error),
|
|
1286
|
+
),
|
|
1287
|
+
),
|
|
1288
|
+
step: () => undefined,
|
|
1289
|
+
});
|
|
1290
|
+
return watchResult;
|
|
1291
|
+
});
|
|
1292
|
+
|
|
1293
|
+
const watchOutcome = yield* watchThroughRegistration.pipe(
|
|
1248
1294
|
Effect.timeoutOrElse({
|
|
1249
1295
|
duration: timeoutSeconds * 1000,
|
|
1250
1296
|
orElse: () => Effect.succeed(null),
|
|
@@ -1252,7 +1298,15 @@ export const fetchChecks = Effect.fn("pr.fetchChecks")(function* (
|
|
|
1252
1298
|
);
|
|
1253
1299
|
|
|
1254
1300
|
const results = yield* fetchCheckResults(pr);
|
|
1255
|
-
if (!quiet &&
|
|
1301
|
+
if (!quiet && graceExpired) {
|
|
1302
|
+
const prRef = pr === null ? "<number>" : String(pr);
|
|
1303
|
+
yield* Console.warn(
|
|
1304
|
+
`ℹ️ No checks registered within ${CHECK_REGISTRATION_GRACE_SECONDS}s of watching; ` +
|
|
1305
|
+
`returning the current snapshot. If this PR should have checks, the push event was ` +
|
|
1306
|
+
`likely dropped, and re-watching will find nothing again — dispatch them on the PR ` +
|
|
1307
|
+
`head instead:\n agent-tools-gh pr trigger-checks --pr ${prRef} --workflow <file.yml>`,
|
|
1308
|
+
);
|
|
1309
|
+
} else if (!quiet && watchOutcome === null && results.some((c) => c.bucket === "pending")) {
|
|
1256
1310
|
const pending = results.filter((c) => c.bucket === "pending").length;
|
|
1257
1311
|
yield* Console.warn(
|
|
1258
1312
|
`ℹ️ Watch timed out after ${timeoutSeconds}s; ${pending} check(s) still pending (snapshot returned). ` +
|
package/src/gh-tool/service.ts
CHANGED
|
@@ -68,13 +68,13 @@ const isSafeRetryRead = (args: readonly string[]): boolean => {
|
|
|
68
68
|
return args.some((a) => READ_VERBS.has(a));
|
|
69
69
|
};
|
|
70
70
|
|
|
71
|
-
type GhResult = {
|
|
71
|
+
export type GhResult = {
|
|
72
72
|
stdout: string;
|
|
73
73
|
stderr: string;
|
|
74
74
|
exitCode: number;
|
|
75
75
|
};
|
|
76
76
|
|
|
77
|
-
type GhError = GitHubCommandError | GitHubAuthError | GitHubNotFoundError;
|
|
77
|
+
export type GhError = GitHubCommandError | GitHubAuthError | GitHubNotFoundError;
|
|
78
78
|
|
|
79
79
|
export class GitHubService extends Context.Service<
|
|
80
80
|
GitHubService,
|
|
@@ -614,7 +614,11 @@ const findCommand = Command.make(
|
|
|
614
614
|
profile: profileOption,
|
|
615
615
|
},
|
|
616
616
|
({ id, format, env, profile }) => handleTraceGet(id, format, env, profile),
|
|
617
|
-
).pipe(
|
|
617
|
+
).pipe(
|
|
618
|
+
Command.withDescription(
|
|
619
|
+
"Alias for 'trace get' — resolves an id, and is not the TraceQL search; that is 'trace search'",
|
|
620
|
+
),
|
|
621
|
+
);
|
|
618
622
|
|
|
619
623
|
const searchCommand = Command.make(
|
|
620
624
|
"search",
|