@corelayer-ai/cli 0.5.1 → 0.5.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 +17 -0
- package/dist/commands/anomalies.js +76 -0
- package/dist/commands/api-keys.js +1 -6
- package/dist/commands/config.js +3 -2
- package/dist/commands/integrations.js +3 -8
- package/dist/commands/issues.js +182 -193
- package/dist/commands/login.js +1 -6
- package/dist/commands/logout.js +21 -3
- package/dist/commands/preflight.js +65 -34
- package/dist/commands/schedules.js +51 -0
- package/dist/index.js +13 -3
- package/dist/lib/api-client.js +9 -0
- package/dist/lib/args.js +4 -0
- package/package.json +4 -2
- package/skill/SKILL.md +298 -108
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
2
|
import { CorelayerClient } from "../lib/api-client.js";
|
|
3
|
-
import {
|
|
3
|
+
import { readFlag } from "../lib/args.js";
|
|
4
|
+
import { resolveApiUrl, resolveToken } from "../lib/config.js";
|
|
4
5
|
import { fail, printJson } from "../lib/output.js";
|
|
5
6
|
const MAX_DIFF_CHARS = 12_000;
|
|
6
7
|
function printHelp() {
|
|
7
|
-
process.stdout
|
|
8
|
+
process.stdout
|
|
9
|
+
.write(`corelayer preflight - Check a change against org memory before you push
|
|
8
10
|
|
|
9
11
|
Surfaces failure modes and things to double-check that your org has hit before for
|
|
10
12
|
changes like this one. Run inside a git repo with no arguments and it derives the PR
|
|
@@ -28,15 +30,9 @@ EXAMPLES:
|
|
|
28
30
|
corelayer preflight --description "Add Redis cache to the payments worker" --repo payments-api
|
|
29
31
|
`);
|
|
30
32
|
}
|
|
31
|
-
function readFlag(args, flag) {
|
|
32
|
-
const index = args.indexOf(flag);
|
|
33
|
-
if (index === -1)
|
|
34
|
-
return undefined;
|
|
35
|
-
return args[index + 1];
|
|
36
|
-
}
|
|
37
33
|
function git(args) {
|
|
38
34
|
try {
|
|
39
|
-
return
|
|
35
|
+
return execFileSync("git", args, {
|
|
40
36
|
encoding: "utf8",
|
|
41
37
|
stdio: ["ignore", "pipe", "ignore"],
|
|
42
38
|
}).trim();
|
|
@@ -46,18 +42,23 @@ function git(args) {
|
|
|
46
42
|
}
|
|
47
43
|
}
|
|
48
44
|
function detectRepo() {
|
|
49
|
-
const url = git("config --get remote.origin.url");
|
|
45
|
+
const url = git(["config", "--get", "remote.origin.url"]);
|
|
50
46
|
if (!url)
|
|
51
47
|
return undefined;
|
|
52
48
|
const match = url.replace(/\.git$/, "").match(/([^/:]+)$/);
|
|
53
49
|
return match ? match[1] : undefined;
|
|
54
50
|
}
|
|
55
51
|
function detectBase() {
|
|
56
|
-
const head = git("rev-parse --abbrev-ref origin/HEAD");
|
|
52
|
+
const head = git(["rev-parse", "--abbrev-ref", "origin/HEAD"]);
|
|
57
53
|
if (head && head.startsWith("origin/"))
|
|
58
|
-
return head
|
|
54
|
+
return head;
|
|
59
55
|
for (const candidate of ["main", "master"]) {
|
|
60
|
-
if (git(
|
|
56
|
+
if (git([
|
|
57
|
+
"rev-parse",
|
|
58
|
+
"--verify",
|
|
59
|
+
"--end-of-options",
|
|
60
|
+
`${candidate}^{commit}`,
|
|
61
|
+
]))
|
|
61
62
|
return candidate;
|
|
62
63
|
}
|
|
63
64
|
return "main";
|
|
@@ -81,15 +82,28 @@ function printChecks(checks, noColor) {
|
|
|
81
82
|
process.stdout.write(` ${severityColor(check.severity, noColor)} · "${check.title}" · ${where}${seen}\n`);
|
|
82
83
|
});
|
|
83
84
|
}
|
|
84
|
-
|
|
85
|
-
if (args.includes("--help") || args.includes("-h")) {
|
|
86
|
-
printHelp();
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
85
|
+
function buildPreflightContext(args) {
|
|
89
86
|
const base = readFlag(args, "--base") || detectBase();
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
87
|
+
const baseCommit = git([
|
|
88
|
+
"rev-parse",
|
|
89
|
+
"--verify",
|
|
90
|
+
"--end-of-options",
|
|
91
|
+
`${base}^{commit}`,
|
|
92
|
+
]);
|
|
93
|
+
const commits = baseCommit
|
|
94
|
+
? git(["log", "--pretty=format:%s%n%b", `${baseCommit}..HEAD`, "--"]) || ""
|
|
95
|
+
: "";
|
|
96
|
+
const files = baseCommit
|
|
97
|
+
? git([
|
|
98
|
+
"diff",
|
|
99
|
+
"--no-ext-diff",
|
|
100
|
+
"--no-textconv",
|
|
101
|
+
"--name-only",
|
|
102
|
+
`${baseCommit}...HEAD`,
|
|
103
|
+
"--",
|
|
104
|
+
]) || ""
|
|
105
|
+
: "";
|
|
106
|
+
const branch = git(["rev-parse", "--abbrev-ref", "HEAD"]);
|
|
93
107
|
const repo = readFlag(args, "--repo") || detectRepo();
|
|
94
108
|
const title = readFlag(args, "--title") || commits.split("\n")[0]?.trim() || branch;
|
|
95
109
|
let description = readFlag(args, "--description");
|
|
@@ -101,11 +115,37 @@ export async function runPreflight(args, ctx) {
|
|
|
101
115
|
parts.push(`Changed files:\n${files.trim()}`);
|
|
102
116
|
description = parts.join("\n\n");
|
|
103
117
|
}
|
|
104
|
-
if (args.includes("--diff")) {
|
|
105
|
-
const diff = git(
|
|
118
|
+
if (args.includes("--diff") && baseCommit) {
|
|
119
|
+
const diff = git([
|
|
120
|
+
"diff",
|
|
121
|
+
"--no-ext-diff",
|
|
122
|
+
"--no-textconv",
|
|
123
|
+
`${baseCommit}...HEAD`,
|
|
124
|
+
"--",
|
|
125
|
+
]);
|
|
106
126
|
if (diff)
|
|
107
127
|
description += `\n\nDiff:\n${diff.slice(0, MAX_DIFF_CHARS)}`;
|
|
108
128
|
}
|
|
129
|
+
return { base, description, repo, title };
|
|
130
|
+
}
|
|
131
|
+
function printPreflightResult(result, ctx) {
|
|
132
|
+
if (result.checks.length === 0) {
|
|
133
|
+
if (!ctx.quiet) {
|
|
134
|
+
process.stdout.write("✓ Preflight: nothing in org memory to double-check for this change.\n");
|
|
135
|
+
}
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
if (!ctx.quiet) {
|
|
139
|
+
process.stdout.write(`Preflight — ${result.checks.length} thing(s) to double-check before you push:\n\n`);
|
|
140
|
+
}
|
|
141
|
+
printChecks(result.checks, ctx.noColor);
|
|
142
|
+
}
|
|
143
|
+
export async function runPreflight(args, ctx) {
|
|
144
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
145
|
+
printHelp();
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
const { base, description, repo, title } = buildPreflightContext(args);
|
|
109
149
|
if (!description.trim()) {
|
|
110
150
|
fail(`No PR context found. Run inside a git repo with commits ahead of "${base}", or pass --description.`);
|
|
111
151
|
}
|
|
@@ -124,14 +164,5 @@ export async function runPreflight(args, ctx) {
|
|
|
124
164
|
printJson(result);
|
|
125
165
|
return;
|
|
126
166
|
}
|
|
127
|
-
|
|
128
|
-
if (!ctx.quiet) {
|
|
129
|
-
process.stdout.write("✓ Preflight: nothing in org memory to double-check for this change.\n");
|
|
130
|
-
}
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
if (!ctx.quiet) {
|
|
134
|
-
process.stdout.write(`Preflight — ${result.checks.length} thing(s) to double-check before you push:\n\n`);
|
|
135
|
-
}
|
|
136
|
-
printChecks(result.checks, ctx.noColor);
|
|
167
|
+
printPreflightResult(result, ctx);
|
|
137
168
|
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { CorelayerClient } from "../lib/api-client.js";
|
|
3
|
+
import { readFlag } from "../lib/args.js";
|
|
4
|
+
import { resolveApiUrl, resolveToken } from "../lib/config.js";
|
|
5
|
+
import { fail, printJson } from "../lib/output.js";
|
|
6
|
+
export async function runSchedules(args, ctx) {
|
|
7
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
8
|
+
process.stdout.write(`corelayer schedules - Manage native scheduled tasks\n\nUSAGE:\n corelayer schedules list --group <id>\n corelayer schedules create --group <id> --file schedule.json\n corelayer schedules update <id> --group <id> --file patch.json\n corelayer schedules pause|resume|delete|runs <id> --group <id>\n\nCREATE FILE:\n {"label":"Daily review","prompt":"Review open issues","schedule_kind":"cron","schedule_expr":"0 9 * * 1-5","timezone":"America/New_York","is_enabled":true}\n\nRun output is saved in Monitoring > Schedules. Jobs are scoped to the selected group.\n`);
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
const action = args[0], group = readFlag(args, "--group"), id = args[1];
|
|
12
|
+
if (!group || group.startsWith("--"))
|
|
13
|
+
fail("Provide --group <id>.");
|
|
14
|
+
if (!["list", "create", "update", "pause", "resume", "delete", "runs"].includes(action))
|
|
15
|
+
fail("Run corelayer schedules --help for usage.");
|
|
16
|
+
if (!["list", "create"].includes(action) && (!id || id.startsWith("--")))
|
|
17
|
+
fail("Provide a schedule id.");
|
|
18
|
+
const token = resolveToken();
|
|
19
|
+
if (!token)
|
|
20
|
+
fail("Not authenticated. Run corelayer login.");
|
|
21
|
+
const client = new CorelayerClient(resolveApiUrl(ctx.apiUrlOverride), token);
|
|
22
|
+
const query = `?groupId=${encodeURIComponent(group)}`, target = `/${encodeURIComponent(id ?? "")}`;
|
|
23
|
+
const body = readScheduleBody(action, args);
|
|
24
|
+
const result = action === "list"
|
|
25
|
+
? await client.scheduleRequest("GET", query)
|
|
26
|
+
: action === "runs"
|
|
27
|
+
? await client.scheduleRequest("GET", `${target}/runs${query}`)
|
|
28
|
+
: action === "delete"
|
|
29
|
+
? await client.scheduleRequest("DELETE", `${target}${query}`)
|
|
30
|
+
: await client.scheduleRequest(action === "create" ? "POST" : "PATCH", action === "create" ? "" : target, {
|
|
31
|
+
...body,
|
|
32
|
+
groupId: group,
|
|
33
|
+
...(action === "pause" || action === "resume"
|
|
34
|
+
? { is_enabled: action === "resume" }
|
|
35
|
+
: {}),
|
|
36
|
+
});
|
|
37
|
+
printJson(result);
|
|
38
|
+
}
|
|
39
|
+
function readScheduleBody(action, args) {
|
|
40
|
+
let body = {};
|
|
41
|
+
if (action === "create" || action === "update") {
|
|
42
|
+
const file = readFlag(args, "--file");
|
|
43
|
+
if (!file || file.startsWith("--"))
|
|
44
|
+
fail("Provide --file <JSON file>.");
|
|
45
|
+
const parsed = JSON.parse(readFileSync(file, "utf8"));
|
|
46
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
47
|
+
fail("The file must contain a JSON object.");
|
|
48
|
+
body = parsed;
|
|
49
|
+
}
|
|
50
|
+
return body;
|
|
51
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { runApiKeys } from "./commands/api-keys.js";
|
|
3
2
|
import { createRequire } from "node:module";
|
|
3
|
+
import { runAnomalies } from "./commands/anomalies.js";
|
|
4
|
+
import { runApiKeys } from "./commands/api-keys.js";
|
|
4
5
|
import { runConfig } from "./commands/config.js";
|
|
5
6
|
import { runGroups } from "./commands/groups.js";
|
|
7
|
+
import { runInstallSkill, runUninstallSkill, } from "./commands/install-skill.js";
|
|
6
8
|
import { runIntegrations } from "./commands/integrations.js";
|
|
7
9
|
import { runIssues } from "./commands/issues.js";
|
|
8
|
-
import { runInstallSkill, runUninstallSkill, } from "./commands/install-skill.js";
|
|
9
10
|
import { runLogin } from "./commands/login.js";
|
|
10
11
|
import { runLogout } from "./commands/logout.js";
|
|
11
12
|
import { runPreflight } from "./commands/preflight.js";
|
|
13
|
+
import { runSchedules } from "./commands/schedules.js";
|
|
12
14
|
const require = createRequire(import.meta.url);
|
|
13
15
|
const { version } = require("../package.json");
|
|
14
16
|
function printHelp() {
|
|
@@ -24,6 +26,8 @@ COMMANDS:
|
|
|
24
26
|
api-keys Create Corelayer API keys
|
|
25
27
|
groups List and inspect groups
|
|
26
28
|
issues List, inspect, and manage issues
|
|
29
|
+
schedules Create and manage native scheduled tasks
|
|
30
|
+
anomalies List and inspect configured anomaly monitors
|
|
27
31
|
preflight Check a change against org memory before you push
|
|
28
32
|
integrations List integrations for a group
|
|
29
33
|
config Read and write local CLI config
|
|
@@ -112,6 +116,12 @@ async function main() {
|
|
|
112
116
|
case "issues":
|
|
113
117
|
await runIssues(rest, ctx);
|
|
114
118
|
return;
|
|
119
|
+
case "anomalies":
|
|
120
|
+
await runAnomalies(rest, ctx);
|
|
121
|
+
return;
|
|
122
|
+
case "schedules":
|
|
123
|
+
await runSchedules(rest, ctx);
|
|
124
|
+
break;
|
|
115
125
|
case "groups":
|
|
116
126
|
await runGroups(rest, ctx);
|
|
117
127
|
return;
|
|
@@ -139,7 +149,7 @@ async function main() {
|
|
|
139
149
|
process.exit(1);
|
|
140
150
|
}
|
|
141
151
|
}
|
|
142
|
-
main().catch(error => {
|
|
152
|
+
main().catch((error) => {
|
|
143
153
|
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
144
154
|
process.exit(1);
|
|
145
155
|
});
|
package/dist/lib/api-client.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AnomalyApiClient } from "@corelayer-ai/sdk";
|
|
1
2
|
async function parseError(res) {
|
|
2
3
|
let body = null;
|
|
3
4
|
try {
|
|
@@ -18,9 +19,11 @@ async function parseError(res) {
|
|
|
18
19
|
export class CorelayerClient {
|
|
19
20
|
baseUrl;
|
|
20
21
|
token;
|
|
22
|
+
anomalies;
|
|
21
23
|
constructor(baseUrl, token) {
|
|
22
24
|
this.baseUrl = baseUrl;
|
|
23
25
|
this.token = token;
|
|
26
|
+
this.anomalies = new AnomalyApiClient((method, path) => this.request(method, path));
|
|
24
27
|
}
|
|
25
28
|
async request(method, path, body) {
|
|
26
29
|
const controller = new AbortController();
|
|
@@ -61,6 +64,9 @@ export class CorelayerClient {
|
|
|
61
64
|
}
|
|
62
65
|
return this.request("GET", `/api/v1/issues?${params.toString()}`);
|
|
63
66
|
}
|
|
67
|
+
async scheduleRequest(method, suffix, body) {
|
|
68
|
+
return this.request(method, `/api/v1/schedules${suffix}`, body);
|
|
69
|
+
}
|
|
64
70
|
async getIssue(issueId) {
|
|
65
71
|
return this.request("GET", `/api/v1/issues/${issueId}`);
|
|
66
72
|
}
|
|
@@ -134,6 +140,9 @@ export class CorelayerClient {
|
|
|
134
140
|
rawKey: data.rawKey,
|
|
135
141
|
};
|
|
136
142
|
}
|
|
143
|
+
async logout() {
|
|
144
|
+
await this.request("POST", "/api/v1/cli/logout");
|
|
145
|
+
}
|
|
137
146
|
async listIntegrations(groupId) {
|
|
138
147
|
const params = new URLSearchParams();
|
|
139
148
|
if (groupId) {
|
package/dist/lib/args.js
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@corelayer-ai/cli",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.2",
|
|
4
4
|
"description": "Corelayer CLI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -18,7 +18,9 @@
|
|
|
18
18
|
"dev": "tsx src/index.ts",
|
|
19
19
|
"prepublishOnly": "npm run build"
|
|
20
20
|
},
|
|
21
|
-
"dependencies": {
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@corelayer-ai/sdk": "^0.2.1"
|
|
23
|
+
},
|
|
22
24
|
"devDependencies": {
|
|
23
25
|
"@types/node": "^20.17.57",
|
|
24
26
|
"tsx": "^4.22.4",
|