@corelayer-ai/cli 0.4.3 → 0.4.5

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.
@@ -1,7 +1,7 @@
1
- import { createInterface } from "node:readline/promises";
2
1
  import { stdin as input, stdout as output } from "node:process";
2
+ import { createInterface } from "node:readline/promises";
3
3
  import { CorelayerClient } from "../lib/api-client.js";
4
- import { readConfig, resolveToken, resolveApiUrl } from "../lib/config.js";
4
+ import { readConfig, resolveApiUrl, resolveToken } 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);
@@ -27,7 +27,9 @@ function removeFlags(args) {
27
27
  arg === "--page" ||
28
28
  arg === "--feedback" ||
29
29
  arg === "--last-seen-before" ||
30
- arg === "--last-seen-before-or-on") {
30
+ arg === "--last-seen-before-or-on" ||
31
+ arg === "--since" ||
32
+ arg === "--duration") {
31
33
  skipNext = true;
32
34
  continue;
33
35
  }
@@ -55,8 +57,9 @@ USAGE:
55
57
 
56
58
  SUBCOMMANDS:
57
59
  list List issues in a group
58
- get <id> Show details for one issue
60
+ get <id|slug> Show details for one issue
59
61
  summary Summarize issue health for a group
62
+ diff Show issues new or changed since a timestamp
60
63
  close <id> Close an issue (write operation)
61
64
  bulk-close Close many issues in one request (write operation)
62
65
  reopen <id> Reopen a closed issue (write operation)
@@ -66,25 +69,49 @@ OPTIONS:
66
69
  --group <id> Group ID (or set default-group via 'corelayer config set')
67
70
  --status <status> Filter by status (list)
68
71
  --severity <sev> Filter by severity (list)
69
- --limit <n> Limit results (list)
70
- --page <n> Page number (list)
72
+ --limit <n> Limit results (list, diff)
73
+ --page <n> Page number (list, diff)
71
74
  --feedback <text> Feedback message (close)
72
75
  --last-seen-before <date|preset>
73
76
  Filter bulk-close to issues seen before a cutoff
74
77
  --last-seen-before-or-on <date|preset>
75
78
  Filter bulk-close to issues seen on or before a cutoff
79
+ --since <timestamp|preset>
80
+ Diff: ISO 8601 timestamp or preset (1hour, 24hours, 7days, 14days, 30days)
81
+ --duration <duration>
82
+ Diff: human-friendly duration (e.g. 2hours, 4hours, 30m, 1d)
76
83
  --yes Skip confirmation prompt (delete)
77
84
  --json Output as JSON
78
85
  -h, --help Print help
79
86
 
80
87
  EXAMPLES:
81
88
  corelayer issues list --group g_123 --status Open
82
- corelayer issues get i_456 --json
89
+ corelayer issues get corelayer-prod-engine-20260602-1 --json
90
+ corelayer issues diff --group g_123 --since 2026-06-01T00:00:00Z
91
+ corelayer issues diff --group g_123 --since 24hours
92
+ corelayer issues diff --group g_123 --duration 2hours --limit 50
83
93
  corelayer issues close i_456 --feedback "fixed in deploy 2026-04-07"
84
94
  corelayer issues bulk-close --group g_123 --last-seen-before-or-on 14days --feedback "Not seen in two weeks"
85
95
  corelayer issues delete i_456 --yes
86
96
  `);
87
97
  }
98
+ function parseDuration(value) {
99
+ const match = value
100
+ .trim()
101
+ .toLowerCase()
102
+ .match(/^(\d+(?:\.\d+)?)\s*(m|min|minutes?|h|hr|hours?|d|days?)$/);
103
+ if (!match)
104
+ return null;
105
+ const n = parseFloat(match[1]);
106
+ const unit = match[2];
107
+ if (unit.startsWith("m"))
108
+ return Math.round(n * 60 * 1000);
109
+ if (unit.startsWith("h"))
110
+ return Math.round(n * 60 * 60 * 1000);
111
+ if (unit.startsWith("d"))
112
+ return Math.round(n * 24 * 60 * 60 * 1000);
113
+ return null;
114
+ }
88
115
  export async function runIssues(args, ctx) {
89
116
  if (args.includes("--help") || args.includes("-h")) {
90
117
  printHelp();
@@ -114,7 +141,7 @@ export async function runIssues(args, ctx) {
114
141
  printJson(result);
115
142
  return;
116
143
  }
117
- const rows = result.issues.map(issue => [
144
+ const rows = result.issues.map((issue) => [
118
145
  issue.id,
119
146
  issue.slug || "-",
120
147
  issue.severity || "-",
@@ -129,11 +156,11 @@ export async function runIssues(args, ctx) {
129
156
  return;
130
157
  }
131
158
  if (sub === "get") {
132
- const issueId = commandArgs[0];
133
- if (!issueId) {
134
- fail("Usage: corelayer issues get <issueId>");
159
+ const issueIdentifier = commandArgs[0];
160
+ if (!issueIdentifier) {
161
+ fail("Usage: corelayer issues get <issueId|slug>");
135
162
  }
136
- const issue = await client.getIssue(issueId);
163
+ const issue = await client.getIssue(issueIdentifier);
137
164
  if (ctx.json) {
138
165
  printJson(issue);
139
166
  return;
@@ -239,5 +266,50 @@ export async function runIssues(args, ctx) {
239
266
  printJson(summary);
240
267
  return;
241
268
  }
242
- fail("Usage: corelayer issues <list|get|close|bulk-close|reopen|delete|summary> [options]");
269
+ if (sub === "diff") {
270
+ const groupId = readFlag(args, "--group") || config.defaults?.group;
271
+ if (!groupId) {
272
+ fail("groupId is required. Use --group <groupId> or set default-group via corelayer config set default-group <groupId>");
273
+ }
274
+ const sinceFlag = readFlag(args, "--since");
275
+ const durationFlag = readFlag(args, "--duration");
276
+ if (!sinceFlag && !durationFlag) {
277
+ fail("One of --since <timestamp|preset> or --duration <duration> is required.\n" +
278
+ "Examples: --since 2026-06-01T00:00:00Z --since 24hours --duration 2hours");
279
+ }
280
+ let sinceValue;
281
+ if (durationFlag) {
282
+ const ms = parseDuration(durationFlag);
283
+ if (ms === null) {
284
+ fail(`Invalid --duration value: "${durationFlag}". Examples: 30m, 2hours, 4h, 1d, 7days`);
285
+ }
286
+ sinceValue = new Date(Date.now() - ms).toISOString();
287
+ }
288
+ else {
289
+ sinceValue = sinceFlag;
290
+ }
291
+ const result = await client.diffIssues(groupId, sinceValue, {
292
+ limit: readFlag(args, "--limit"),
293
+ page: readFlag(args, "--page"),
294
+ });
295
+ if (ctx.json) {
296
+ printJson(result);
297
+ return;
298
+ }
299
+ process.stdout.write(`DIFF SINCE ${result.since}\n`);
300
+ const rows = result.issues.map((issue) => [
301
+ issue.id,
302
+ issue.slug || "-",
303
+ issue.severity || "-",
304
+ issue.status || "-",
305
+ issue.title || "-",
306
+ formatDate(issue.last_seen_at || issue.lastSeenAt),
307
+ ]);
308
+ printTable(["ID", "SLUG", "SEVERITY", "STATUS", "TITLE", "LAST SEEN"], rows);
309
+ if (!ctx.quiet) {
310
+ process.stdout.write(`${result.total} issue${result.total === 1 ? "" : "s"} changed since ${result.since}\n`);
311
+ }
312
+ return;
313
+ }
314
+ fail("Usage: corelayer issues <list|get|close|bulk-close|reopen|delete|summary|diff> [options]");
243
315
  }
@@ -94,6 +94,15 @@ export class CorelayerClient {
94
94
  async deleteIssue(issueId) {
95
95
  await this.request("DELETE", `/api/v1/issues/${issueId}`);
96
96
  }
97
+ async diffIssues(groupId, since, options = {}) {
98
+ const params = new URLSearchParams({ groupId, since });
99
+ for (const [key, value] of Object.entries(options)) {
100
+ if (value !== undefined && value !== null && value !== "") {
101
+ params.set(key, String(value));
102
+ }
103
+ }
104
+ return this.request("GET", `/api/v1/issues/diff?${params.toString()}`);
105
+ }
97
106
  async getIssueSummary(groupId) {
98
107
  const params = new URLSearchParams({ groupId });
99
108
  return this.request("GET", `/api/v1/issues/summary?${params.toString()}`);
@@ -128,7 +137,28 @@ export class CorelayerClient {
128
137
  params.set("groupId", groupId);
129
138
  }
130
139
  const suffix = params.toString() ? `?${params.toString()}` : "";
131
- return this.request("GET", `/api/v1/integrations/accounts${suffix}`);
140
+ const raw = await this.request("GET", `/api/v1/integrations/accounts${suffix}`);
141
+ return {
142
+ accounts: (raw.accounts ?? []).map((account) => ({
143
+ id: account.id,
144
+ group_id: account.group_id,
145
+ provider_code: account.provider_code,
146
+ is_active: account.is_active,
147
+ created_at: account.created_at,
148
+ resources: (account.resources ?? []).map((resource) => ({
149
+ id: resource.id,
150
+ resource_type: resource.resource_type,
151
+ external_id: resource.external_id,
152
+ name: resource.name,
153
+ is_active: resource.is_active,
154
+ })),
155
+ })),
156
+ providers: (raw.providers ?? []).map((provider) => ({
157
+ provider_code: provider.provider_code,
158
+ display_name: provider.display_name,
159
+ })),
160
+ total: raw.total ?? 0,
161
+ };
132
162
  }
133
163
  }
134
164
  export async function exchangeCliCode(baseUrl, code) {
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@corelayer-ai/cli",
3
- "version": "0.4.3",
3
+ "version": "0.4.5",
4
4
  "description": "Corelayer CLI",
5
5
  "type": "module",
6
6
  "bin": {
7
- "corelayer": "./dist/index.js"
7
+ "corelayer": "dist/index.js"
8
8
  },
9
9
  "files": [
10
10
  "dist",
package/skill/SKILL.md CHANGED
@@ -37,12 +37,23 @@ corelayer issues list --status open
37
37
  ### Inspect a specific issue
38
38
 
39
39
  ```bash
40
- corelayer issues get <issueId>
41
- corelayer issues get <issueId> --json
40
+ corelayer issues get <issueId|slug>
41
+ corelayer issues get <issueId|slug> --json
42
42
  ```
43
43
 
44
44
  Returns: title, status, severity, event count, what happened, root cause, and next steps.
45
45
 
46
+ ### Diff issues since a timestamp (post-deploy triage)
47
+
48
+ ```bash
49
+ corelayer issues diff --group <groupId> --since 2026-06-01T00:00:00Z
50
+ corelayer issues diff --group <groupId> --since 24hours
51
+ corelayer issues diff --group <groupId> --duration 2hours --limit 50
52
+ corelayer issues diff --group <groupId> --duration 30m --json
53
+ ```
54
+
55
+ Returns issues that are new or changed since the given timestamp. Useful after PR merges/deploys to identify regressions or newly surfaced issues.
56
+
46
57
  ### Triage issues
47
58
 
48
59
  ```bash
@@ -84,7 +95,7 @@ Setting a default group avoids repeating `--group` on every command.
84
95
  List issues for a group. Requires `--group` or a configured default group.
85
96
  Filterable by status (`open`, `closed`) and severity (`critical`, `high`, `medium`, `low`).
86
97
 
87
- ### `corelayer issues get <issueId>`
98
+ ### `corelayer issues get <issueId|slug>`
88
99
 
89
100
  Get full details for an issue including AI-generated analysis: what happened, root cause, and next steps.
90
101
 
@@ -92,6 +103,18 @@ Get full details for an issue including AI-generated analysis: what happened, ro
92
103
 
93
104
  Returns a JSON severity breakdown for the group.
94
105
 
106
+ ### `corelayer issues diff --group <id> (--since <timestamp|preset> | --duration <duration>) [--limit <n>] [--page <n>]`
107
+
108
+ Returns issues that are new or updated since the given point in time. Useful for post-deploy triage — run after a PR merge to see what regressions or new errors have surfaced.
109
+
110
+ `--since` accepts an ISO 8601 timestamp (`2026-06-01T00:00:00Z`) or a preset: `1hour`, `24hours`, `7days`, `14days`, `30days`.
111
+
112
+ `--duration` accepts human-friendly durations: `30m`, `2hours`, `4h`, `1d`, `7days`. The duration is subtracted from the current time to compute the since-timestamp.
113
+
114
+ `--limit` and `--page` paginate results. The API defaults to 20 results and caps `--limit` at 100.
115
+
116
+ Use `--json` for machine-readable output suitable for agent automation.
117
+
95
118
  ### `corelayer issues close <issueId> [--feedback "..."]`
96
119
 
97
120
  Close an issue. Optionally provide feedback (e.g., link to the fix).
@@ -139,7 +162,7 @@ Clear stored credentials.
139
162
  ```bash
140
163
  corelayer issues summary
141
164
  corelayer issues list --severity critical
142
- corelayer issues get <id> --json
165
+ corelayer issues get <issueId|slug> --json
143
166
  ```
144
167
 
145
168
  ### Scripting and automation