@corelayer-ai/cli 0.2.0 → 0.4.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/dist/commands/config.js +28 -0
- package/dist/commands/groups.js +26 -5
- package/dist/commands/install-skill.js +37 -3
- package/dist/commands/integrations.js +27 -4
- package/dist/commands/issues.js +83 -6
- package/dist/commands/login.js +51 -0
- package/dist/commands/logout.js +15 -1
- package/dist/index.js +28 -16
- package/dist/lib/api-client.js +23 -2
- package/dist/lib/config.js +7 -1
- package/package.json +1 -1
- package/skill/SKILL.md +5 -0
- package/dist/lib/cli-auth.js +0 -31
package/dist/commands/config.js
CHANGED
|
@@ -1,6 +1,34 @@
|
|
|
1
1
|
import { readConfig, updateConfig } from "../lib/config.js";
|
|
2
2
|
import { fail, printJson } from "../lib/output.js";
|
|
3
|
+
function printHelp() {
|
|
4
|
+
process.stdout.write(`corelayer config - Read and write local CLI config
|
|
5
|
+
|
|
6
|
+
USAGE:
|
|
7
|
+
corelayer config <subcommand> [key] [value]
|
|
8
|
+
|
|
9
|
+
SUBCOMMANDS:
|
|
10
|
+
get [key] Print the full config, or one value
|
|
11
|
+
set <key> <value> Set a config value
|
|
12
|
+
|
|
13
|
+
KEYS:
|
|
14
|
+
api-url API server URL
|
|
15
|
+
default-group Default group ID for issues and integrations commands
|
|
16
|
+
|
|
17
|
+
OPTIONS:
|
|
18
|
+
--json Output as JSON (get only)
|
|
19
|
+
-h, --help Print help
|
|
20
|
+
|
|
21
|
+
EXAMPLES:
|
|
22
|
+
corelayer config get
|
|
23
|
+
corelayer config get api-url
|
|
24
|
+
corelayer config set default-group g_123
|
|
25
|
+
`);
|
|
26
|
+
}
|
|
3
27
|
export async function runConfig(args, ctx) {
|
|
28
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
29
|
+
printHelp();
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
4
32
|
const sub = args[0];
|
|
5
33
|
if (sub === "get") {
|
|
6
34
|
const key = args[1];
|
package/dist/commands/groups.js
CHANGED
|
@@ -1,17 +1,38 @@
|
|
|
1
1
|
import { CorelayerClient } from "../lib/api-client.js";
|
|
2
|
-
import {
|
|
2
|
+
import { resolveToken, resolveApiUrl } from "../lib/config.js";
|
|
3
3
|
import { fail, formatDate, printJson, printTable } from "../lib/output.js";
|
|
4
|
+
function printHelp() {
|
|
5
|
+
process.stdout.write(`corelayer groups - List and inspect groups
|
|
6
|
+
|
|
7
|
+
USAGE:
|
|
8
|
+
corelayer groups <subcommand> [options]
|
|
9
|
+
|
|
10
|
+
SUBCOMMANDS:
|
|
11
|
+
list List all groups you have access to
|
|
12
|
+
|
|
13
|
+
OPTIONS:
|
|
14
|
+
--json Output as JSON
|
|
15
|
+
-h, --help Print help
|
|
16
|
+
|
|
17
|
+
EXAMPLES:
|
|
18
|
+
corelayer groups list
|
|
19
|
+
corelayer groups list --json
|
|
20
|
+
`);
|
|
21
|
+
}
|
|
4
22
|
export async function runGroups(args, ctx) {
|
|
23
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
24
|
+
printHelp();
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
5
27
|
const sub = args[0];
|
|
6
28
|
if (sub !== "list") {
|
|
7
29
|
fail("Usage: corelayer groups list");
|
|
8
30
|
}
|
|
9
|
-
const
|
|
10
|
-
const token = config.token;
|
|
31
|
+
const token = resolveToken();
|
|
11
32
|
if (!token) {
|
|
12
|
-
fail("Not
|
|
33
|
+
fail("Not authenticated. Set CORELAYER_API_KEY or run: corelayer login");
|
|
13
34
|
}
|
|
14
|
-
const apiUrl = ctx.apiUrlOverride
|
|
35
|
+
const apiUrl = resolveApiUrl(ctx.apiUrlOverride);
|
|
15
36
|
const client = new CorelayerClient(apiUrl, token);
|
|
16
37
|
const result = await client.listGroups();
|
|
17
38
|
if (ctx.json) {
|
|
@@ -13,7 +13,37 @@ function getSkillSourcePath() {
|
|
|
13
13
|
const packageDir = dirname(distDir);
|
|
14
14
|
return join(packageDir, "skill", "SKILL.md");
|
|
15
15
|
}
|
|
16
|
-
|
|
16
|
+
function printInstallHelp() {
|
|
17
|
+
process.stdout
|
|
18
|
+
.write(`corelayer install-skill - Install the Corelayer agent skill
|
|
19
|
+
|
|
20
|
+
USAGE:
|
|
21
|
+
corelayer install-skill
|
|
22
|
+
|
|
23
|
+
DESCRIPTION:
|
|
24
|
+
Copies the Corelayer skill into ~/.claude/skills/corelayer so coding agents
|
|
25
|
+
can use it. Run 'corelayer uninstall-skill' to remove it.
|
|
26
|
+
|
|
27
|
+
OPTIONS:
|
|
28
|
+
-h, --help Print help
|
|
29
|
+
`);
|
|
30
|
+
}
|
|
31
|
+
function printUninstallHelp() {
|
|
32
|
+
process.stdout
|
|
33
|
+
.write(`corelayer uninstall-skill - Remove the Corelayer agent skill
|
|
34
|
+
|
|
35
|
+
USAGE:
|
|
36
|
+
corelayer uninstall-skill
|
|
37
|
+
|
|
38
|
+
OPTIONS:
|
|
39
|
+
-h, --help Print help
|
|
40
|
+
`);
|
|
41
|
+
}
|
|
42
|
+
export async function runInstallSkill(args, ctx) {
|
|
43
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
44
|
+
printInstallHelp();
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
17
47
|
const source = getSkillSourcePath();
|
|
18
48
|
if (!existsSync(source)) {
|
|
19
49
|
fail("Skill file not found. The CLI package may be incomplete.");
|
|
@@ -23,10 +53,14 @@ export async function runInstallSkill(_args, ctx) {
|
|
|
23
53
|
mkdirSync(targetDir, { recursive: true });
|
|
24
54
|
copyFileSync(source, targetFile);
|
|
25
55
|
if (!ctx.quiet) {
|
|
26
|
-
process.stdout.write(`Corelayer skill installed to ${targetFile}\
|
|
56
|
+
process.stdout.write(`Corelayer skill installed to ${targetFile}\n`);
|
|
27
57
|
}
|
|
28
58
|
}
|
|
29
|
-
export async function runUninstallSkill(
|
|
59
|
+
export async function runUninstallSkill(args, ctx) {
|
|
60
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
61
|
+
printUninstallHelp();
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
30
64
|
const targetDir = getSkillTargetDir();
|
|
31
65
|
const targetFile = join(targetDir, "SKILL.md");
|
|
32
66
|
if (!existsSync(targetFile)) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CorelayerClient } from "../lib/api-client.js";
|
|
2
|
-
import { readConfig } from "../lib/config.js";
|
|
2
|
+
import { readConfig, resolveToken, resolveApiUrl } from "../lib/config.js";
|
|
3
3
|
import { fail, printJson, printTable } from "../lib/output.js";
|
|
4
4
|
function readFlag(args, flag) {
|
|
5
5
|
const index = args.indexOf(flag);
|
|
@@ -7,18 +7,41 @@ function readFlag(args, flag) {
|
|
|
7
7
|
return undefined;
|
|
8
8
|
return args[index + 1];
|
|
9
9
|
}
|
|
10
|
+
function printHelp() {
|
|
11
|
+
process.stdout.write(`corelayer integrations - List integrations for a group
|
|
12
|
+
|
|
13
|
+
USAGE:
|
|
14
|
+
corelayer integrations <subcommand> [options]
|
|
15
|
+
|
|
16
|
+
SUBCOMMANDS:
|
|
17
|
+
list List integrations for a group
|
|
18
|
+
|
|
19
|
+
OPTIONS:
|
|
20
|
+
--group <id> Group ID (or set default-group via 'corelayer config set')
|
|
21
|
+
--json Output as JSON
|
|
22
|
+
-h, --help Print help
|
|
23
|
+
|
|
24
|
+
EXAMPLES:
|
|
25
|
+
corelayer integrations list --group g_123
|
|
26
|
+
corelayer integrations list --json
|
|
27
|
+
`);
|
|
28
|
+
}
|
|
10
29
|
export async function runIntegrations(args, ctx) {
|
|
30
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
31
|
+
printHelp();
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
11
34
|
const sub = args[0];
|
|
12
35
|
if (sub !== "list") {
|
|
13
36
|
fail("Usage: corelayer integrations list [--group <groupId>]");
|
|
14
37
|
}
|
|
15
38
|
const config = readConfig();
|
|
16
|
-
const token =
|
|
39
|
+
const token = resolveToken();
|
|
17
40
|
if (!token) {
|
|
18
|
-
fail("Not
|
|
41
|
+
fail("Not authenticated. Set CORELAYER_API_KEY or run: corelayer login");
|
|
19
42
|
}
|
|
20
43
|
const groupId = readFlag(args, "--group") || config.defaults?.group;
|
|
21
|
-
const apiUrl = ctx.apiUrlOverride
|
|
44
|
+
const apiUrl = resolveApiUrl(ctx.apiUrlOverride);
|
|
22
45
|
const client = new CorelayerClient(apiUrl, token);
|
|
23
46
|
const result = await client.listIntegrations(groupId);
|
|
24
47
|
if (ctx.json) {
|
package/dist/commands/issues.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createInterface } from "node:readline/promises";
|
|
2
2
|
import { stdin as input, stdout as output } from "node:process";
|
|
3
3
|
import { CorelayerClient } from "../lib/api-client.js";
|
|
4
|
-
import { readConfig } from "../lib/config.js";
|
|
4
|
+
import { readConfig, resolveToken, resolveApiUrl } from "../lib/config.js";
|
|
5
5
|
import { fail, formatDate, printJson, printTable } from "../lib/output.js";
|
|
6
6
|
function readFlag(args, flag) {
|
|
7
7
|
const index = args.indexOf(flag);
|
|
@@ -25,7 +25,9 @@ function removeFlags(args) {
|
|
|
25
25
|
arg === "--severity" ||
|
|
26
26
|
arg === "--limit" ||
|
|
27
27
|
arg === "--page" ||
|
|
28
|
-
arg === "--feedback"
|
|
28
|
+
arg === "--feedback" ||
|
|
29
|
+
arg === "--last-seen-before" ||
|
|
30
|
+
arg === "--last-seen-before-or-on") {
|
|
29
31
|
skipNext = true;
|
|
30
32
|
continue;
|
|
31
33
|
}
|
|
@@ -45,14 +47,56 @@ async function confirmDelete() {
|
|
|
45
47
|
rl.close();
|
|
46
48
|
return answer.trim().toLowerCase() === "y";
|
|
47
49
|
}
|
|
50
|
+
function printHelp() {
|
|
51
|
+
process.stdout.write(`corelayer issues - List, inspect, and manage issues
|
|
52
|
+
|
|
53
|
+
USAGE:
|
|
54
|
+
corelayer issues <subcommand> [options]
|
|
55
|
+
|
|
56
|
+
SUBCOMMANDS:
|
|
57
|
+
list List issues in a group
|
|
58
|
+
get <id> Show details for one issue
|
|
59
|
+
summary Summarize issue health for a group
|
|
60
|
+
close <id> Close an issue (write operation)
|
|
61
|
+
bulk-close Close many issues in one request (write operation)
|
|
62
|
+
reopen <id> Reopen a closed issue (write operation)
|
|
63
|
+
delete <id> Delete an issue (write operation)
|
|
64
|
+
|
|
65
|
+
OPTIONS:
|
|
66
|
+
--group <id> Group ID (or set default-group via 'corelayer config set')
|
|
67
|
+
--status <status> Filter by status (list)
|
|
68
|
+
--severity <sev> Filter by severity (list)
|
|
69
|
+
--limit <n> Limit results (list)
|
|
70
|
+
--page <n> Page number (list)
|
|
71
|
+
--feedback <text> Feedback message (close)
|
|
72
|
+
--last-seen-before <date|preset>
|
|
73
|
+
Filter bulk-close to issues seen before a cutoff
|
|
74
|
+
--last-seen-before-or-on <date|preset>
|
|
75
|
+
Filter bulk-close to issues seen on or before a cutoff
|
|
76
|
+
--yes Skip confirmation prompt (delete)
|
|
77
|
+
--json Output as JSON
|
|
78
|
+
-h, --help Print help
|
|
79
|
+
|
|
80
|
+
EXAMPLES:
|
|
81
|
+
corelayer issues list --group g_123 --status Open
|
|
82
|
+
corelayer issues get i_456 --json
|
|
83
|
+
corelayer issues close i_456 --feedback "fixed in deploy 2026-04-07"
|
|
84
|
+
corelayer issues bulk-close --group g_123 --last-seen-before-or-on 14days --feedback "Not seen in two weeks"
|
|
85
|
+
corelayer issues delete i_456 --yes
|
|
86
|
+
`);
|
|
87
|
+
}
|
|
48
88
|
export async function runIssues(args, ctx) {
|
|
89
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
90
|
+
printHelp();
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
49
93
|
const sub = args[0];
|
|
50
94
|
const config = readConfig();
|
|
51
|
-
const token =
|
|
95
|
+
const token = resolveToken();
|
|
52
96
|
if (!token) {
|
|
53
|
-
fail("Not
|
|
97
|
+
fail("Not authenticated. Set CORELAYER_API_KEY or run: corelayer login");
|
|
54
98
|
}
|
|
55
|
-
const apiUrl = ctx.apiUrlOverride
|
|
99
|
+
const apiUrl = resolveApiUrl(ctx.apiUrlOverride);
|
|
56
100
|
const client = new CorelayerClient(apiUrl, token);
|
|
57
101
|
const commandArgs = removeFlags(args.slice(1));
|
|
58
102
|
if (sub === "list") {
|
|
@@ -123,6 +167,39 @@ export async function runIssues(args, ctx) {
|
|
|
123
167
|
}
|
|
124
168
|
return;
|
|
125
169
|
}
|
|
170
|
+
if (sub === "bulk-close") {
|
|
171
|
+
const groupId = readFlag(args, "--group") || config.defaults?.group;
|
|
172
|
+
if (!groupId) {
|
|
173
|
+
fail("groupId is required. Use --group <groupId> or set default-group via corelayer config set default-group <groupId>");
|
|
174
|
+
}
|
|
175
|
+
const lastSeenBefore = readFlag(args, "--last-seen-before");
|
|
176
|
+
const lastSeenBeforeOrOn = readFlag(args, "--last-seen-before-or-on");
|
|
177
|
+
if (!lastSeenBefore && !lastSeenBeforeOrOn) {
|
|
178
|
+
fail('Usage: corelayer issues bulk-close --group <groupId> (--last-seen-before <date|preset> | --last-seen-before-or-on <date|preset>) [--feedback "..."]');
|
|
179
|
+
}
|
|
180
|
+
const feedback = readFlag(args, "--feedback");
|
|
181
|
+
const result = await client.bulkIssueAction({
|
|
182
|
+
action: "close",
|
|
183
|
+
groupId,
|
|
184
|
+
feedback,
|
|
185
|
+
filters: {
|
|
186
|
+
status: readFlag(args, "--status") || "Open",
|
|
187
|
+
severity: readFlag(args, "--severity"),
|
|
188
|
+
lastSeenBefore,
|
|
189
|
+
lastSeenBeforeOrOn,
|
|
190
|
+
},
|
|
191
|
+
});
|
|
192
|
+
if (ctx.json) {
|
|
193
|
+
printJson(result);
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
process.stdout.write(`Bulk close complete. Closed ${result.affected} issues`);
|
|
197
|
+
if (result.skipped > 0) {
|
|
198
|
+
process.stdout.write(`, skipped ${result.skipped}`);
|
|
199
|
+
}
|
|
200
|
+
process.stdout.write(".\n");
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
126
203
|
if (sub === "reopen") {
|
|
127
204
|
const issueId = commandArgs[0];
|
|
128
205
|
if (!issueId) {
|
|
@@ -162,5 +239,5 @@ export async function runIssues(args, ctx) {
|
|
|
162
239
|
printJson(summary);
|
|
163
240
|
return;
|
|
164
241
|
}
|
|
165
|
-
fail("Usage: corelayer issues <list|get|close|reopen|delete|summary> [options]");
|
|
242
|
+
fail("Usage: corelayer issues <list|get|close|bulk-close|reopen|delete|summary> [options]");
|
|
166
243
|
}
|
package/dist/commands/login.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { loginWithBrowser, loginWithCodeDirect } from "../lib/auth.js";
|
|
2
|
+
import { updateConfig } from "../lib/config.js";
|
|
2
3
|
import { fail } from "../lib/output.js";
|
|
3
4
|
function readFlag(args, flag) {
|
|
4
5
|
const index = args.indexOf(flag);
|
|
@@ -6,8 +7,58 @@ function readFlag(args, flag) {
|
|
|
6
7
|
return undefined;
|
|
7
8
|
return args[index + 1];
|
|
8
9
|
}
|
|
10
|
+
function hasFlag(args, flag) {
|
|
11
|
+
return args.includes(flag);
|
|
12
|
+
}
|
|
13
|
+
function printHelp() {
|
|
14
|
+
process.stdout.write(`corelayer login - Authenticate with Corelayer
|
|
15
|
+
|
|
16
|
+
USAGE:
|
|
17
|
+
corelayer login Open browser to authenticate
|
|
18
|
+
corelayer login --code <code> --api-url <url> Complete login with an auth code
|
|
19
|
+
corelayer login --with-token --api-url <url> Save a token piped on stdin
|
|
20
|
+
|
|
21
|
+
OPTIONS:
|
|
22
|
+
--code <code> Auth code from the browser flow (manual login)
|
|
23
|
+
--with-token Read an API key from stdin and save it to config
|
|
24
|
+
--api-url <url> API server URL (required for --code and --with-token)
|
|
25
|
+
-h, --help Print help
|
|
26
|
+
|
|
27
|
+
EXAMPLES:
|
|
28
|
+
corelayer login
|
|
29
|
+
corelayer login --code abc123 --api-url https://api.corelayer.com
|
|
30
|
+
echo $CORELAYER_API_KEY | corelayer login --with-token --api-url https://api.corelayer.com
|
|
31
|
+
`);
|
|
32
|
+
}
|
|
33
|
+
async function readStdin() {
|
|
34
|
+
if (process.stdin.isTTY) {
|
|
35
|
+
fail("No token provided on stdin. Usage: echo $CORELAYER_API_KEY | corelayer login --with-token");
|
|
36
|
+
}
|
|
37
|
+
const chunks = [];
|
|
38
|
+
for await (const chunk of process.stdin) {
|
|
39
|
+
chunks.push(chunk);
|
|
40
|
+
}
|
|
41
|
+
return Buffer.concat(chunks).toString("utf8").trim();
|
|
42
|
+
}
|
|
9
43
|
export async function runLogin(args, ctx) {
|
|
44
|
+
if (hasFlag(args, "--help") || hasFlag(args, "-h")) {
|
|
45
|
+
printHelp();
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
10
48
|
const code = readFlag(args, "--code");
|
|
49
|
+
const withToken = hasFlag(args, "--with-token");
|
|
50
|
+
if (withToken) {
|
|
51
|
+
const token = await readStdin();
|
|
52
|
+
if (!token) {
|
|
53
|
+
fail("Empty token. Usage: echo $CORELAYER_API_KEY | corelayer login --with-token");
|
|
54
|
+
}
|
|
55
|
+
const apiUrl = ctx.apiUrlOverride || "https://api.corelayer.com";
|
|
56
|
+
updateConfig({ token, apiUrl });
|
|
57
|
+
if (!ctx.quiet) {
|
|
58
|
+
process.stdout.write(`Token saved. API URL: ${apiUrl}\n`);
|
|
59
|
+
}
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
11
62
|
let email;
|
|
12
63
|
let orgName;
|
|
13
64
|
if (code) {
|
package/dist/commands/logout.js
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
import { clearToken } from "../lib/config.js";
|
|
2
|
-
|
|
2
|
+
function printHelp() {
|
|
3
|
+
process.stdout.write(`corelayer logout - Sign out and clear local credentials
|
|
4
|
+
|
|
5
|
+
USAGE:
|
|
6
|
+
corelayer logout
|
|
7
|
+
|
|
8
|
+
OPTIONS:
|
|
9
|
+
-h, --help Print help
|
|
10
|
+
`);
|
|
11
|
+
}
|
|
12
|
+
export async function runLogout(args, ctx) {
|
|
13
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
14
|
+
printHelp();
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
3
17
|
clearToken();
|
|
4
18
|
if (!ctx.quiet) {
|
|
5
19
|
process.stdout.write("Logged out.\n");
|
package/dist/index.js
CHANGED
|
@@ -10,24 +10,36 @@ import { runLogout } from "./commands/logout.js";
|
|
|
10
10
|
const require = createRequire(import.meta.url);
|
|
11
11
|
const { version } = require("../package.json");
|
|
12
12
|
function printHelp() {
|
|
13
|
-
process.stdout
|
|
13
|
+
process.stdout
|
|
14
|
+
.write(`Corelayer CLI - Manage groups, issues, and integrations from your terminal
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
corelayer
|
|
17
|
-
corelayer login --code <CODE> --api-url <url> (manual)
|
|
18
|
-
corelayer logout
|
|
19
|
-
corelayer issues <list|get|close|reopen|delete|summary> ...
|
|
20
|
-
corelayer groups list
|
|
21
|
-
corelayer integrations list [--group <groupId>]
|
|
22
|
-
corelayer config <get|set> ...
|
|
23
|
-
corelayer install-skill (install Claude Code skill)
|
|
24
|
-
corelayer uninstall-skill (remove Claude Code skill)
|
|
16
|
+
USAGE:
|
|
17
|
+
corelayer [global options] <command> [command options]
|
|
25
18
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
19
|
+
COMMANDS:
|
|
20
|
+
login Authenticate with Corelayer (opens browser)
|
|
21
|
+
logout Sign out and clear local credentials
|
|
22
|
+
groups List and inspect groups
|
|
23
|
+
issues List, inspect, and manage issues
|
|
24
|
+
integrations List integrations for a group
|
|
25
|
+
config Read and write local CLI config
|
|
26
|
+
install-skill Install the Corelayer agent skill
|
|
27
|
+
uninstall-skill Remove the Corelayer agent skill
|
|
28
|
+
|
|
29
|
+
GLOBAL OPTIONS:
|
|
30
|
+
--json Output as JSON for scripting
|
|
31
|
+
-q, --quiet Suppress non-essential output
|
|
32
|
+
--api-url <url> Override the configured API server
|
|
33
|
+
--no-color Disable colored output
|
|
34
|
+
-h, --help Print help
|
|
35
|
+
-v, --version Print version
|
|
36
|
+
|
|
37
|
+
ENVIRONMENT VARIABLES:
|
|
38
|
+
CORELAYER_API_KEY API key for non-interactive auth (skips login)
|
|
39
|
+
CORELAYER_API_URL Server URL (default: https://api.corelayer.com)
|
|
40
|
+
CORELAYER_AUTH_URL Auth server URL (default: https://app.corelayer.com)
|
|
41
|
+
|
|
42
|
+
Run 'corelayer <command> --help' for more information on a command.
|
|
31
43
|
`);
|
|
32
44
|
}
|
|
33
45
|
function parseGlobalFlags(argv) {
|
package/dist/lib/api-client.js
CHANGED
|
@@ -6,9 +6,14 @@ async function parseError(res) {
|
|
|
6
6
|
catch {
|
|
7
7
|
body = null;
|
|
8
8
|
}
|
|
9
|
-
|
|
9
|
+
const message = body?.error ||
|
|
10
10
|
body?.message ||
|
|
11
|
-
`${res.status} ${res.statusText || "Request failed"}
|
|
11
|
+
`${res.status} ${res.statusText || "Request failed"}`;
|
|
12
|
+
const retryAfter = res.headers.get("retry-after");
|
|
13
|
+
if (res.status === 429 && retryAfter) {
|
|
14
|
+
return `${message}. Retry after ${retryAfter}s.`;
|
|
15
|
+
}
|
|
16
|
+
return message;
|
|
12
17
|
}
|
|
13
18
|
export class CorelayerClient {
|
|
14
19
|
baseUrl;
|
|
@@ -65,6 +70,22 @@ export class CorelayerClient {
|
|
|
65
70
|
feedback,
|
|
66
71
|
});
|
|
67
72
|
}
|
|
73
|
+
async bulkIssueAction(params) {
|
|
74
|
+
const filters = new URLSearchParams();
|
|
75
|
+
for (const [key, value] of Object.entries(params.filters || {})) {
|
|
76
|
+
if (value !== undefined && value !== null && value !== "") {
|
|
77
|
+
filters.set(key, String(value));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return this.request("POST", "/api/v1/issues/bulk", {
|
|
81
|
+
action: params.action,
|
|
82
|
+
groupId: params.groupId,
|
|
83
|
+
issueIds: params.issueIds,
|
|
84
|
+
selectAll: !params.issueIds || params.issueIds.length === 0,
|
|
85
|
+
filters: filters.toString() || undefined,
|
|
86
|
+
feedback: params.feedback,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
68
89
|
async reopenIssue(issueId) {
|
|
69
90
|
await this.request("PATCH", `/api/v1/issues/${issueId}`, {
|
|
70
91
|
status: "Open",
|
package/dist/lib/config.js
CHANGED
|
@@ -4,7 +4,7 @@ import path from "node:path";
|
|
|
4
4
|
const CONFIG_DIR = path.join(os.homedir(), ".corelayer");
|
|
5
5
|
const CONFIG_PATH = path.join(CONFIG_DIR, "config.json");
|
|
6
6
|
function defaultApiUrl() {
|
|
7
|
-
return process.env.CORELAYER_API_URL || "
|
|
7
|
+
return process.env.CORELAYER_API_URL || "https://api.corelayer.com";
|
|
8
8
|
}
|
|
9
9
|
export function getConfigPath() {
|
|
10
10
|
return CONFIG_PATH;
|
|
@@ -52,6 +52,12 @@ export function updateConfig(partial) {
|
|
|
52
52
|
writeConfig(merged);
|
|
53
53
|
return merged;
|
|
54
54
|
}
|
|
55
|
+
export function resolveToken() {
|
|
56
|
+
return process.env.CORELAYER_API_KEY || readConfig().token;
|
|
57
|
+
}
|
|
58
|
+
export function resolveApiUrl(override) {
|
|
59
|
+
return override || readConfig().apiUrl;
|
|
60
|
+
}
|
|
55
61
|
export function clearToken() {
|
|
56
62
|
const current = readConfig();
|
|
57
63
|
delete current.token;
|
package/package.json
CHANGED
package/skill/SKILL.md
CHANGED
|
@@ -47,6 +47,7 @@ Returns: title, status, severity, event count, what happened, root cause, and ne
|
|
|
47
47
|
|
|
48
48
|
```bash
|
|
49
49
|
corelayer issues close <issueId> --feedback "Fixed in PR #123"
|
|
50
|
+
corelayer issues bulk-close --group <groupId> --last-seen-before-or-on 14days --feedback "Not seen in two weeks"
|
|
50
51
|
corelayer issues reopen <issueId>
|
|
51
52
|
corelayer issues delete <issueId> --yes
|
|
52
53
|
```
|
|
@@ -95,6 +96,10 @@ Returns a JSON severity breakdown for the group.
|
|
|
95
96
|
|
|
96
97
|
Close an issue. Optionally provide feedback (e.g., link to the fix).
|
|
97
98
|
|
|
99
|
+
### `corelayer issues bulk-close --group <id> (--last-seen-before <date|preset> | --last-seen-before-or-on <date|preset>) [--feedback "..."]`
|
|
100
|
+
|
|
101
|
+
Close many stale issues in one request. Presets such as `14days` are supported.
|
|
102
|
+
|
|
98
103
|
### `corelayer issues reopen <issueId>`
|
|
99
104
|
|
|
100
105
|
Reopen a previously closed issue.
|
package/dist/lib/cli-auth.js
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import crypto from "node:crypto";
|
|
2
|
-
const MAX_CALLBACK_BODY_BYTES = 8 * 1024;
|
|
3
|
-
export function parseTrustedOrigin(authBaseUrl) {
|
|
4
|
-
const parsed = new URL(authBaseUrl);
|
|
5
|
-
return parsed.origin;
|
|
6
|
-
}
|
|
7
|
-
export function hashCliAuthCode(code) {
|
|
8
|
-
return crypto.createHash("sha256").update(code).digest("hex");
|
|
9
|
-
}
|
|
10
|
-
export async function readJsonBody(req) {
|
|
11
|
-
const chunks = [];
|
|
12
|
-
let total = 0;
|
|
13
|
-
for await (const chunk of req) {
|
|
14
|
-
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
15
|
-
total += buffer.length;
|
|
16
|
-
if (total > MAX_CALLBACK_BODY_BYTES) {
|
|
17
|
-
throw new Error("Callback body is too large");
|
|
18
|
-
}
|
|
19
|
-
chunks.push(buffer);
|
|
20
|
-
}
|
|
21
|
-
const raw = Buffer.concat(chunks).toString("utf8").trim();
|
|
22
|
-
if (!raw) {
|
|
23
|
-
return {};
|
|
24
|
-
}
|
|
25
|
-
try {
|
|
26
|
-
return JSON.parse(raw);
|
|
27
|
-
}
|
|
28
|
-
catch {
|
|
29
|
-
throw new Error("Callback body is not valid JSON");
|
|
30
|
-
}
|
|
31
|
-
}
|