@chainpatrol/cli 0.5.0 → 0.7.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/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # @chainpatrol/cli
2
2
 
3
+ ## 0.7.0
4
+
5
+ ### Minor Changes
6
+
7
+ - c170343: Add `chainpatrol setup --cloud` flag that also installs a Claude Code
8
+ SessionStart hook at `~/.claude/hooks/chainpatrol-login.sh` and registers
9
+ it in `~/.claude/settings.json`. When the user has no chainpatrol
10
+ credentials, the hook emits SessionStart `additionalContext` so Claude
11
+ surfaces the device-code login URL on the first user turn — useful for
12
+ cloud Claude Code environments that can't run the interactive login from
13
+ a container startup script. The hook is a silent no-op once the user is
14
+ authenticated. Local installs (without `--cloud`) leave Claude Code
15
+ hooks untouched. `chainpatrol uninstall` always removes the hook if
16
+ present, without disturbing unrelated hooks or settings.
17
+
18
+ ## 0.6.0
19
+
20
+ ### Minor Changes
21
+
22
+ - 575b671: Add `chainpatrol orgs list` — lists organizations accessible to the caller along with each org's subscription status and active/automated service flags (reporting, reviewing, protection, takedowns, detection, dark web monitoring). Filter flags compose with AND and are applied server-side:
23
+
24
+ - `--subscription-status <list>` — comma-separated `PROSPECT`, `TRIAL`, `ACTIVE`, `INTEGRATION` (`INACTIVE` is intentionally not reachable through this filter)
25
+ - `--service-active <list>` / `--service-inactive <list>` — services that must be active / inactive
26
+ - `--service-automated <list>` / `--service-manual <list>` — services whose automation must be on / off (`reporting`, `reviewing`, `protection`, `takedowns`)
27
+ - `--query <text>` — partial name match
28
+
29
+ Use cases: "which ACTIVE customers have takedowns enabled but automation off", "which prospects don't have detection turned on yet". The bundled CLI skill gets a new `orgs list` section under the `queues snapshot` heading.
30
+
3
31
  ## 0.5.0
4
32
 
5
33
  ### Minor Changes
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-VFT3TD3E.js";
5
5
  import {
6
6
  createApiClient
7
- } from "./chunk-MXUZR2BV.js";
7
+ } from "./chunk-LLWKCA3H.js";
8
8
  import "./chunk-EEG7T6WT.js";
9
9
  import "./chunk-TFCNKBRC.js";
10
10
  import "./chunk-U73SABXK.js";
@@ -8,7 +8,7 @@ import {
8
8
  } from "./chunk-VFT3TD3E.js";
9
9
  import {
10
10
  createApiClient
11
- } from "./chunk-MXUZR2BV.js";
11
+ } from "./chunk-LLWKCA3H.js";
12
12
  import {
13
13
  DateTime
14
14
  } from "./chunk-TFCNKBRC.js";
@@ -147,6 +147,9 @@ function createApiClient(options) {
147
147
  },
148
148
  runHealthcheck(endpoint, input) {
149
149
  return request(endpoint, input);
150
+ },
151
+ getUserOrgs(input) {
152
+ return request("/user/orgs", input);
150
153
  }
151
154
  };
152
155
  }
@@ -4,13 +4,125 @@ import {
4
4
  } from "./chunk-IUZB3DQW.js";
5
5
 
6
6
  // src/commands/setup-skill.ts
7
- import { mkdirSync, writeFileSync, existsSync, readFileSync as readFileSync2, rmSync } from "fs";
8
- import { join } from "path";
7
+ import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2, existsSync as existsSync2, readFileSync as readFileSync3, rmSync } from "fs";
8
+ import { join as join2 } from "path";
9
+ import { homedir as homedir2 } from "os";
10
+
11
+ // src/commands/login-hook.ts
12
+ import { mkdirSync, writeFileSync, readFileSync, existsSync, unlinkSync } from "fs";
9
13
  import { homedir } from "os";
14
+ import { join, dirname } from "path";
15
+ var CLAUDE_DIR = join(homedir(), ".claude");
16
+ var HOOK_DIR = join(CLAUDE_DIR, "hooks");
17
+ var HOOK_FILE = join(HOOK_DIR, "chainpatrol-login.sh");
18
+ var SETTINGS_FILE = join(CLAUDE_DIR, "settings.json");
19
+ var HOOK_SCRIPT = `#!/bin/bash
20
+ # chainpatrol auto-login hook \u2014 installed by \`chainpatrol setup\`.
21
+ # On Claude Code session start, if the user has no chainpatrol credentials,
22
+ # emit additionalContext so Claude surfaces the device-code login URL on
23
+ # the first user turn. Safe to run repeatedly: no-ops once authenticated.
24
+ set -uo pipefail
25
+
26
+ CONFIG_DIR="\${CHAINPATROL_CONFIG_DIR:-$HOME/.chainpatrol}"
27
+ if [ -s "$CONFIG_DIR/credentials.json" ]; then
28
+ exit 0
29
+ fi
30
+
31
+ # Only nudge when the CLI is reachable \u2014 otherwise we'd ask Claude to run
32
+ # a command that isn't installed.
33
+ if ! command -v chainpatrol >/dev/null 2>&1 \\
34
+ && [ ! -x /usr/local/bin/chainpatrol ] \\
35
+ && ! ls /opt/node*/bin/chainpatrol >/dev/null 2>&1; then
36
+ exit 0
37
+ fi
38
+
39
+ cat <<'JSON'
40
+ {"hookSpecificOutput":{"hookEventName":"SessionStart","additionalContext":"chainpatrol auto-login: the user is not authenticated with ChainPatrol (no credentials.json found). If the user's task involves ChainPatrol or the chainpatrol CLI, start \`chainpatrol login\` in the background per the /chainpatrol skill's headless runbook (background + tail /tmp/cp-login.out) and surface the verification URL before doing anything else. If the user's task is unrelated, ignore this notice."}}
41
+ JSON
42
+ exit 0
43
+ `;
44
+ function installLoginHook() {
45
+ mkdirSync(HOOK_DIR, { recursive: true });
46
+ const hookWritten = !existsSync(HOOK_FILE) || readFileSync(HOOK_FILE, "utf-8") !== HOOK_SCRIPT;
47
+ if (hookWritten) {
48
+ writeFileSync(HOOK_FILE, HOOK_SCRIPT, { mode: 493 });
49
+ }
50
+ const settingsUpdated = registerHookInSettings();
51
+ return {
52
+ hookPath: HOOK_FILE,
53
+ hookWritten,
54
+ settingsPath: SETTINGS_FILE,
55
+ settingsUpdated
56
+ };
57
+ }
58
+ function uninstallLoginHook() {
59
+ let hookRemoved = false;
60
+ if (existsSync(HOOK_FILE)) {
61
+ unlinkSync(HOOK_FILE);
62
+ hookRemoved = true;
63
+ }
64
+ const settingsUpdated = unregisterHookFromSettings();
65
+ return { hookRemoved, settingsUpdated };
66
+ }
67
+ function readSettings() {
68
+ if (!existsSync(SETTINGS_FILE)) return {};
69
+ const raw = readFileSync(SETTINGS_FILE, "utf-8");
70
+ if (raw.trim() === "") return {};
71
+ return JSON.parse(raw);
72
+ }
73
+ function writeSettings(settings) {
74
+ mkdirSync(dirname(SETTINGS_FILE), { recursive: true });
75
+ writeFileSync(SETTINGS_FILE, JSON.stringify(settings, null, 2) + "\n", {
76
+ mode: 420
77
+ });
78
+ }
79
+ function hasHookEntry(settings) {
80
+ const matchers = settings.hooks?.SessionStart;
81
+ if (!Array.isArray(matchers)) return false;
82
+ return matchers.some(
83
+ (matcher) => Array.isArray(matcher?.hooks) && matcher.hooks.some((h) => h?.command === HOOK_FILE)
84
+ );
85
+ }
86
+ function registerHookInSettings() {
87
+ const settings = readSettings();
88
+ if (hasHookEntry(settings)) return false;
89
+ const hooks = settings.hooks ??= {};
90
+ const sessionStart = hooks.SessionStart ??= [];
91
+ sessionStart.push({
92
+ hooks: [{ type: "command", command: HOOK_FILE }]
93
+ });
94
+ writeSettings(settings);
95
+ return true;
96
+ }
97
+ function unregisterHookFromSettings() {
98
+ if (!existsSync(SETTINGS_FILE)) return false;
99
+ const settings = readSettings();
100
+ const sessionStart = settings.hooks?.SessionStart;
101
+ if (!Array.isArray(sessionStart)) return false;
102
+ let changed = false;
103
+ const filtered = sessionStart.map((matcher) => {
104
+ if (!Array.isArray(matcher?.hooks)) return matcher;
105
+ const remaining = matcher.hooks.filter((h) => h?.command !== HOOK_FILE);
106
+ if (remaining.length === matcher.hooks.length) return matcher;
107
+ changed = true;
108
+ return remaining.length > 0 ? { ...matcher, hooks: remaining } : null;
109
+ }).filter((m) => m !== null);
110
+ if (!changed) return false;
111
+ if (filtered.length === 0) {
112
+ delete settings.hooks.SessionStart;
113
+ if (Object.keys(settings.hooks).length === 0) {
114
+ delete settings.hooks;
115
+ }
116
+ } else {
117
+ settings.hooks.SessionStart = filtered;
118
+ }
119
+ writeSettings(settings);
120
+ return true;
121
+ }
10
122
 
11
123
  // src/lib/version.ts
12
- import { readFileSync } from "fs";
13
- import { dirname, resolve } from "path";
124
+ import { readFileSync as readFileSync2 } from "fs";
125
+ import { dirname as dirname2, resolve } from "path";
14
126
  import { fileURLToPath } from "url";
15
127
  var PACKAGE_NAME = "@chainpatrol/cli";
16
128
  var cached;
@@ -21,7 +133,7 @@ function getCliVersion() {
21
133
  }
22
134
  function resolveCliVersion() {
23
135
  try {
24
- const here = dirname(fileURLToPath(import.meta.url));
136
+ const here = dirname2(fileURLToPath(import.meta.url));
25
137
  const candidates = [
26
138
  resolve(here, "..", "package.json"),
27
139
  resolve(here, "..", "..", "package.json")
@@ -36,7 +148,7 @@ function resolveCliVersion() {
36
148
  }
37
149
  function tryReadVersion(path) {
38
150
  try {
39
- const raw = readFileSync(path, "utf-8");
151
+ const raw = readFileSync2(path, "utf-8");
40
152
  const pkg = JSON.parse(raw);
41
153
  if (pkg.name === PACKAGE_NAME && typeof pkg.version === "string") {
42
154
  return pkg.version;
@@ -66,8 +178,8 @@ function compareVersions(a, b) {
66
178
  }
67
179
 
68
180
  // src/commands/setup-skill.ts
69
- var SKILL_DIR = join(homedir(), ".claude", "skills", "chainpatrol");
70
- var SKILL_FILE = join(SKILL_DIR, "SKILL.md");
181
+ var SKILL_DIR = join2(homedir2(), ".claude", "skills", "chainpatrol");
182
+ var SKILL_FILE = join2(SKILL_DIR, "SKILL.md");
71
183
  function buildSkillContent(version) {
72
184
  return `---
73
185
  name: chainpatrol
@@ -82,7 +194,9 @@ description: |
82
194
  "am I logged in", "list configs", "use the cli", "list reports",
83
195
  "customer reports", "reports reported by customer", "find detection gaps",
84
196
  "org healthcheck", "organization health check", "audit my org",
85
- "what's wrong with org", "review org setup".
197
+ "what's wrong with org", "review org setup", "list orgs", "list organizations",
198
+ "orgs with takedowns off", "automation off across orgs",
199
+ "which customers have X enabled", "service toggles by org".
86
200
  allowed-tools:
87
201
  - Bash
88
202
  - Read
@@ -443,6 +557,51 @@ Guide. Key signals in the response:
443
557
 
444
558
  Use \`--all\` to snapshot every org you have access to instead of a single slug.
445
559
 
560
+ ### \`orgs list\` \u2014 List organizations with subscription status and service toggles
561
+
562
+ Returns every organization the caller can see, with each org's
563
+ subscription status (\`PROSPECT\`, \`TRIAL\`, \`ACTIVE\`, \`INTEGRATION\`) and
564
+ which services are active and automated. Use it to answer questions like
565
+ "which customers have takedowns enabled but automation off?" or "which
566
+ prospects don't have detection turned on yet?" \u2014 filters compose with AND
567
+ and are applied server-side, so one call returns the final list.
568
+
569
+ \`\`\`bash
570
+ chainpatrol --json orgs list \\
571
+ --subscription-status ACTIVE \\
572
+ --service-active takedowns \\
573
+ --service-manual takedowns
574
+ \`\`\`
575
+
576
+ Filter flags (all optional, all comma-separated lists):
577
+
578
+ - \`--query <text>\` partial name match (substring, case-insensitive)
579
+ - \`--subscription-status <list>\` one or more of \`PROSPECT\`, \`TRIAL\`,
580
+ \`ACTIVE\`, \`INTEGRATION\`. \`INACTIVE\` is intentionally not reachable
581
+ through this filter \u2014 \`orgs list\` only ever returns live customers.
582
+ - \`--service-active <list>\` services that must be active
583
+ - \`--service-inactive <list>\` services that must be inactive
584
+ - \`--service-automated <list>\` services whose automation must be ON
585
+ (\`reporting\`, \`reviewing\`, \`protection\`, \`takedowns\` \u2014 the four
586
+ with an automation toggle)
587
+ - \`--service-manual <list>\` services whose automation must be OFF
588
+ (same four)
589
+
590
+ Service names: \`reporting\`, \`reviewing\`, \`protection\`, \`takedowns\`,
591
+ \`detection\`, \`darkWebMonitoring\`.
592
+
593
+ Customers see only orgs they're a member of. Staff/superuser sessions see
594
+ every matching org. The response is the same in both cases; visibility is
595
+ enforced server-side.
596
+
597
+ #### Use case: finding service configuration gaps across the customer base
598
+
599
+ When the user asks something like "which customers are paying us but don't
600
+ have takedowns automated yet?" or "any orgs running detection without
601
+ takedowns?", reach for \`orgs list\` \u2014 it's the only command that exposes
602
+ service flags across multiple orgs in one call. Run it in \`--json\` mode
603
+ and summarize patterns by service or by subscription tier.
604
+
446
605
  ### \`metrics summary | found | breakdown\` \u2014 Org metrics for spike/drop analysis
447
606
 
448
607
  \`\`\`bash
@@ -924,16 +1083,16 @@ function getBundledSkillContent() {
924
1083
  return buildSkillContent(getCliVersion());
925
1084
  }
926
1085
  function readInstalledSkillVersion() {
927
- if (!existsSync(SKILL_FILE)) return void 0;
1086
+ if (!existsSync2(SKILL_FILE)) return void 0;
928
1087
  try {
929
- const raw = readFileSync2(SKILL_FILE, "utf-8");
1088
+ const raw = readFileSync3(SKILL_FILE, "utf-8");
930
1089
  return parseSkillVersion(raw);
931
1090
  } catch {
932
1091
  return void 0;
933
1092
  }
934
1093
  }
935
1094
  function isSkillInstalled() {
936
- return existsSync(SKILL_FILE);
1095
+ return existsSync2(SKILL_FILE);
937
1096
  }
938
1097
  function parseSkillVersion(content) {
939
1098
  const fmMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
@@ -954,66 +1113,94 @@ var LOGO = `
954
1113
  `;
955
1114
  function setupSkill(options) {
956
1115
  const skillContent = buildSkillContent(getCliVersion());
957
- const alreadyExists = existsSync(SKILL_FILE);
958
- if (alreadyExists) {
959
- const existing = readFileSync2(SKILL_FILE, "utf-8");
960
- if (existing === skillContent) {
961
- if (options.json) {
962
- console.log(JSON.stringify({ status: "up-to-date", path: SKILL_FILE }));
963
- } else {
964
- console.log("Claude Code skill is already up to date.");
965
- }
966
- return;
967
- }
1116
+ const skillAlreadyExists = existsSync2(SKILL_FILE);
1117
+ const skillUpToDate = skillAlreadyExists && readFileSync3(SKILL_FILE, "utf-8") === skillContent;
1118
+ let skillStatus;
1119
+ if (!skillAlreadyExists) {
1120
+ mkdirSync2(SKILL_DIR, { recursive: true });
1121
+ writeFileSync2(SKILL_FILE, skillContent, { mode: 420 });
1122
+ skillStatus = "installed";
1123
+ } else if (!skillUpToDate) {
1124
+ writeFileSync2(SKILL_FILE, skillContent, { mode: 420 });
1125
+ skillStatus = "updated";
1126
+ } else {
1127
+ skillStatus = "up-to-date";
968
1128
  }
969
- mkdirSync(SKILL_DIR, { recursive: true });
970
- writeFileSync(SKILL_FILE, skillContent, { mode: 420 });
971
1129
  const completionResult = installCompletions();
1130
+ const loginHookResult = options.cloud ? installLoginHook() : null;
1131
+ const completionsChanged = completionResult.installed || completionResult.configuredShellRc;
1132
+ const loginHookChanged = loginHookResult != null && (loginHookResult.hookWritten || loginHookResult.settingsUpdated);
1133
+ const overallStatus = skillStatus !== "up-to-date" ? skillStatus : completionsChanged || loginHookChanged ? "updated" : "up-to-date";
972
1134
  if (options.json) {
973
1135
  console.log(
974
1136
  JSON.stringify({
975
- status: alreadyExists ? "updated" : "installed",
1137
+ status: overallStatus,
976
1138
  path: SKILL_FILE,
977
- completions: completionResult
1139
+ skill: { status: skillStatus, path: SKILL_FILE },
1140
+ completions: completionResult,
1141
+ loginHook: loginHookResult
978
1142
  })
979
1143
  );
980
- } else {
981
- console.log(LOGO);
1144
+ return;
1145
+ }
1146
+ if (overallStatus === "up-to-date") {
1147
+ console.log("Claude Code skill, completions, and login hook are already up to date.");
1148
+ return;
1149
+ }
1150
+ console.log(LOGO);
1151
+ if (skillStatus === "installed") {
1152
+ console.log(`Installed Claude Code skill at ${SKILL_FILE}`);
1153
+ } else if (skillStatus === "updated") {
1154
+ console.log(`Updated Claude Code skill at ${SKILL_FILE}`);
1155
+ }
1156
+ console.log("You can now use /chainpatrol in Claude Code from any project.");
1157
+ if (loginHookChanged && loginHookResult) {
1158
+ console.log(`Installed auto-login hook at ${loginHookResult.hookPath}`);
1159
+ if (loginHookResult.settingsUpdated) {
1160
+ console.log(`Registered SessionStart hook in ${loginHookResult.settingsPath}`);
1161
+ }
1162
+ }
1163
+ if (completionResult.installed) {
982
1164
  console.log(
983
- alreadyExists ? `Updated Claude Code skill at ${SKILL_FILE}` : `Installed Claude Code skill at ${SKILL_FILE}`
1165
+ `Installed ${completionResult.shell} completions at ${completionResult.path}`
984
1166
  );
985
- console.log("You can now use /chainpatrol in Claude Code from any project.");
986
- if (completionResult.installed) {
987
- console.log(
988
- `Installed ${completionResult.shell} completions at ${completionResult.path}`
989
- );
990
- if (completionResult.configuredShellRc) {
991
- console.log("Added completion config to ~/.zshrc");
992
- }
993
- console.log('Run "exec zsh" or open a new terminal to enable tab completion.');
1167
+ if (completionResult.configuredShellRc) {
1168
+ console.log("Added completion config to ~/.zshrc");
994
1169
  }
1170
+ console.log('Run "exec zsh" or open a new terminal to enable tab completion.');
995
1171
  }
996
1172
  }
997
1173
  function uninstallSkill(options) {
998
- if (!existsSync(SKILL_FILE)) {
999
- if (options.json) {
1000
- console.log(JSON.stringify({ status: "not-installed" }));
1001
- } else {
1002
- console.log("Claude Code skill is not installed.");
1003
- }
1004
- return;
1174
+ const skillInstalled = existsSync2(SKILL_FILE);
1175
+ if (skillInstalled) {
1176
+ rmSync(SKILL_DIR, { recursive: true });
1005
1177
  }
1006
- rmSync(SKILL_DIR, { recursive: true });
1007
1178
  const removedCompletions = uninstallCompletions();
1179
+ const loginHookResult = uninstallLoginHook();
1180
+ const removedAnything = skillInstalled || removedCompletions || loginHookResult.hookRemoved || loginHookResult.settingsUpdated;
1008
1181
  if (options.json) {
1009
1182
  console.log(
1010
- JSON.stringify({ status: "uninstalled", path: SKILL_FILE, removedCompletions })
1183
+ JSON.stringify({
1184
+ status: removedAnything ? "uninstalled" : "not-installed",
1185
+ path: SKILL_FILE,
1186
+ removedCompletions,
1187
+ loginHook: loginHookResult
1188
+ })
1011
1189
  );
1012
- } else {
1190
+ return;
1191
+ }
1192
+ if (!removedAnything) {
1193
+ console.log("Claude Code skill is not installed.");
1194
+ return;
1195
+ }
1196
+ if (skillInstalled) {
1013
1197
  console.log("Removed Claude Code skill from " + SKILL_DIR);
1014
- if (removedCompletions) {
1015
- console.log("Removed shell completions.");
1016
- }
1198
+ }
1199
+ if (loginHookResult.hookRemoved || loginHookResult.settingsUpdated) {
1200
+ console.log("Removed chainpatrol auto-login hook.");
1201
+ }
1202
+ if (removedCompletions) {
1203
+ console.log("Removed shell completions.");
1017
1204
  }
1018
1205
  }
1019
1206
 
package/dist/cli.js CHANGED
@@ -13,7 +13,7 @@ import {
13
13
  getCliVersion,
14
14
  isSkillInstalled,
15
15
  readInstalledSkillVersion
16
- } from "./chunk-BSK4YHFA.js";
16
+ } from "./chunk-ZN3VMRWG.js";
17
17
  import "./chunk-IUZB3DQW.js";
18
18
  import {
19
19
  DateTime
@@ -281,6 +281,31 @@ var HELP = {
281
281
  "--window-hours <n> Hours used for staleness windows"
282
282
  ]
283
283
  },
284
+ orgs: {
285
+ description: "List organizations accessible to you with subscription status and service toggles.",
286
+ usage: "chainpatrol orgs list [filters]",
287
+ examples: [
288
+ "chainpatrol orgs list",
289
+ "chainpatrol orgs list --subscription-status ACTIVE --service-active takedowns --service-manual takedowns"
290
+ ]
291
+ },
292
+ "orgs list": {
293
+ description: "List organizations with their subscription status and per-service active/automated flags. All filters compose with AND.",
294
+ usage: "chainpatrol orgs list [filters]",
295
+ options: [
296
+ "--query <text> Partial name match (substring, case-insensitive)",
297
+ "--subscription-status <l> Comma-separated list (PROSPECT,TRIAL,ACTIVE,INTEGRATION)",
298
+ "--service-active <l> Comma-separated services that must be active",
299
+ "--service-inactive <l> Comma-separated services that must be inactive",
300
+ "--service-automated <l> Services whose automation must be ON (reporting,reviewing,protection,takedowns)",
301
+ "--service-manual <l> Services whose automation must be OFF (reporting,reviewing,protection,takedowns)"
302
+ ],
303
+ examples: [
304
+ "chainpatrol orgs list --subscription-status ACTIVE",
305
+ "chainpatrol orgs list --service-active takedowns --service-manual takedowns",
306
+ "chainpatrol --json orgs list --subscription-status ACTIVE,TRIAL --service-active detection"
307
+ ]
308
+ },
284
309
  healthchecks: {
285
310
  description: "Run organization healthchecks via the public API. Use `list` to see every available check (including planned ones not yet implemented on the backend) and `run` to execute one or all implemented checks.",
286
311
  usage: "chainpatrol healthchecks <list|run <id>|run --all>",
@@ -329,7 +354,10 @@ var HELP = {
329
354
  },
330
355
  setup: {
331
356
  description: "Install Claude Code skill and shell completions.",
332
- usage: "chainpatrol setup"
357
+ usage: "chainpatrol setup [--cloud]",
358
+ options: [
359
+ "--cloud Also install a SessionStart hook that surfaces the device-code login URL when the user is not authenticated. Intended for Claude Code cloud / headless environments; omit for local installs."
360
+ ]
333
361
  },
334
362
  uninstall: {
335
363
  description: "Remove Claude Code skill and shell completions.",
@@ -369,6 +397,7 @@ function getTopLevelHelp() {
369
397
  " metrics Query organization metrics and breakdowns",
370
398
  " reports Create and list reports from terminal",
371
399
  " queues Snapshot operations review/takedown queues",
400
+ " orgs List organizations and filter by status/services",
372
401
  " presets Run saved workflows for common jobs",
373
402
  " setup Install Claude Code skill and shell completions",
374
403
  " uninstall Remove Claude Code skill and shell completions",
@@ -538,6 +567,7 @@ var COMMANDS = [
538
567
  "metrics",
539
568
  "reports",
540
569
  "queues",
570
+ "orgs",
541
571
  "presets",
542
572
  "setup",
543
573
  "uninstall",
@@ -614,11 +644,18 @@ ${getTopLevelHelp()}
614
644
  contactInfo: { type: "string" },
615
645
  externalSubmissionLink: { type: "string" },
616
646
  payloadFile: { type: "string" },
647
+ subscriptionStatus: { type: "string" },
648
+ serviceActive: { type: "string" },
649
+ serviceInactive: { type: "string" },
650
+ serviceAutomated: { type: "string" },
651
+ serviceManual: { type: "string" },
652
+ query: { type: "string" },
617
653
  help: { type: "boolean", shortFlag: "h" },
618
654
  version: { type: "boolean", shortFlag: "V" },
619
655
  quiet: { type: "boolean", default: false, shortFlag: "q" },
620
656
  noInput: { type: "boolean", default: false },
621
- noColor: { type: "boolean", default: false }
657
+ noColor: { type: "boolean", default: false },
658
+ cloud: { type: "boolean", default: false }
622
659
  }
623
660
  });
624
661
  var [command, subcommand, action] = cli.input;
@@ -717,12 +754,12 @@ function parseAttachmentUrls() {
717
754
  }
718
755
  async function handleConfigsList(org) {
719
756
  if (jsonMode) {
720
- const { listConfigsJson } = await import("./list-json-WTMYLZGY.js");
757
+ const { listConfigsJson } = await import("./list-json-LEKCCWQU.js");
721
758
  await listConfigsJson({ org });
722
759
  return;
723
760
  }
724
761
  const { render } = await import("ink");
725
- const { default: ConfigsList } = await import("./list-GEMCFDD5.js");
762
+ const { default: ConfigsList } = await import("./list-5ENZAOFL.js");
726
763
  const { default: React } = await import("react");
727
764
  render(React.createElement(ConfigsList, { org }));
728
765
  }
@@ -820,7 +857,7 @@ async function main() {
820
857
  case "detections": {
821
858
  const org = await resolveOrg();
822
859
  if (subcommand === "healthcheck") {
823
- const { runDetectionsHealthcheck } = await import("./healthcheck-KAONRGSS.js");
860
+ const { runDetectionsHealthcheck } = await import("./healthcheck-AQUXVKAO.js");
824
861
  await runDetectionsHealthcheck({
825
862
  org,
826
863
  source: cli.flags.source,
@@ -835,7 +872,7 @@ async function main() {
835
872
  break;
836
873
  }
837
874
  if (subcommand === "validate") {
838
- const { runDetectionsValidate } = await import("./validate-BJFEKI2N.js");
875
+ const { runDetectionsValidate } = await import("./validate-27RUCN7R.js");
839
876
  await runDetectionsValidate({
840
877
  org,
841
878
  source: cli.flags.source,
@@ -850,7 +887,7 @@ async function main() {
850
887
  break;
851
888
  }
852
889
  if (subcommand === "drift") {
853
- const { runDetectionsDrift } = await import("./drift-DZ6A7JL5.js");
890
+ const { runDetectionsDrift } = await import("./drift-VOKQJ36G.js");
854
891
  await runDetectionsDrift({
855
892
  org,
856
893
  source: cli.flags.source,
@@ -864,7 +901,7 @@ async function main() {
864
901
  break;
865
902
  }
866
903
  if (subcommand === "run") {
867
- const { runDetectionsRun } = await import("./run-43CC5AXR.js");
904
+ const { runDetectionsRun } = await import("./run-OT2X46GT.js");
868
905
  await runDetectionsRun({
869
906
  org,
870
907
  configId: cli.flags.configId,
@@ -883,7 +920,7 @@ async function main() {
883
920
  break;
884
921
  }
885
922
  if (action === "run") {
886
- const { runDetectionsRun } = await import("./run-43CC5AXR.js");
923
+ const { runDetectionsRun } = await import("./run-OT2X46GT.js");
887
924
  await runDetectionsRun({
888
925
  org,
889
926
  configId: cli.flags.configId,
@@ -901,7 +938,7 @@ async function main() {
901
938
  throw new Error("detections configs update requires --config-id");
902
939
  }
903
940
  const configPatch = getConfigPatchFromSetFlags();
904
- const { runDetectionsConfigsUpdate } = await import("./configs-update-RPN32YTL.js");
941
+ const { runDetectionsConfigsUpdate } = await import("./configs-update-VROBC2HI.js");
905
942
  await runDetectionsConfigsUpdate({
906
943
  org,
907
944
  configId: cli.flags.configId,
@@ -928,7 +965,7 @@ async function main() {
928
965
  case "metrics": {
929
966
  const org = await resolveOrg();
930
967
  if (subcommand === "summary") {
931
- const { runMetricsSummary } = await import("./summary-6NCA7PDP.js");
968
+ const { runMetricsSummary } = await import("./summary-JOCABBCO.js");
932
969
  await runMetricsSummary({
933
970
  org,
934
971
  from: cli.flags.from,
@@ -940,7 +977,7 @@ async function main() {
940
977
  break;
941
978
  }
942
979
  if (subcommand === "found") {
943
- const { runMetricsFound } = await import("./found-AOPBSLRD.js");
980
+ const { runMetricsFound } = await import("./found-A5HRTJCJ.js");
944
981
  await runMetricsFound({
945
982
  org,
946
983
  from: cli.flags.from,
@@ -957,7 +994,7 @@ async function main() {
957
994
  if (!by || !["day", "type", "brand"].includes(by)) {
958
995
  throw new Error("metrics breakdown requires --by <day|type|brand>");
959
996
  }
960
- const { runMetricsBreakdown } = await import("./breakdown-EBSACUST.js");
997
+ const { runMetricsBreakdown } = await import("./breakdown-AX6QNTQH.js");
961
998
  await runMetricsBreakdown({
962
999
  org,
963
1000
  by,
@@ -977,7 +1014,7 @@ async function main() {
977
1014
  case "reports": {
978
1015
  if (subcommand === "list") {
979
1016
  const org = await resolveOrg();
980
- const { runReportsList } = await import("./list-MWDFCHMJ.js");
1017
+ const { runReportsList } = await import("./list-CVFXTKNX.js");
981
1018
  await runReportsList({
982
1019
  org,
983
1020
  limit: cli.flags.limit,
@@ -993,7 +1030,7 @@ async function main() {
993
1030
  }
994
1031
  if (subcommand === "create") {
995
1032
  const org = await tryResolveOrg();
996
- const { runReportsCreate } = await import("./create-QP3M7EZM.js");
1033
+ const { runReportsCreate } = await import("./create-XTCUNT2C.js");
997
1034
  await runReportsCreate({
998
1035
  org,
999
1036
  title: cli.flags.title,
@@ -1017,7 +1054,7 @@ async function main() {
1017
1054
  }
1018
1055
  case "queues": {
1019
1056
  if (subcommand === "snapshot") {
1020
- const { runQueuesSnapshot } = await import("./snapshot-E3TPZOKT.js");
1057
+ const { runQueuesSnapshot } = await import("./snapshot-4QR4I67P.js");
1021
1058
  await runQueuesSnapshot({
1022
1059
  org: cli.flags.org,
1023
1060
  all: cli.flags.all,
@@ -1033,9 +1070,29 @@ async function main() {
1033
1070
  subcommand ? `Unknown subcommand: queues ${subcommand}${hint ? `. Did you mean "queues ${hint}"?` : ""}` : "Usage: chainpatrol queues snapshot [--org <slug>|--all]"
1034
1071
  );
1035
1072
  }
1073
+ case "orgs": {
1074
+ if (subcommand === "list") {
1075
+ const { runOrgsList } = await import("./list-CGRHTFAS.js");
1076
+ await runOrgsList({
1077
+ query: cli.flags.query,
1078
+ subscriptionStatus: cli.flags.subscriptionStatus,
1079
+ serviceActive: cli.flags.serviceActive,
1080
+ serviceInactive: cli.flags.serviceInactive,
1081
+ serviceAutomated: cli.flags.serviceAutomated,
1082
+ serviceManual: cli.flags.serviceManual,
1083
+ json: jsonMode,
1084
+ outputFormat: cliContext.outputFormat
1085
+ });
1086
+ break;
1087
+ }
1088
+ const hint = subcommand ? suggest(subcommand, ["list"]) : null;
1089
+ throw new Error(
1090
+ subcommand ? `Unknown subcommand: orgs ${subcommand}${hint ? `. Did you mean "orgs ${hint}"?` : ""}` : "Usage: chainpatrol orgs list [--subscription-status <list>] [--service-active <list>] [--service-automated <list>] ..."
1091
+ );
1092
+ }
1036
1093
  case "healthchecks": {
1037
1094
  if (subcommand === "list") {
1038
- const { runHealthchecksList } = await import("./list-UW63DIKX.js");
1095
+ const { runHealthchecksList } = await import("./list-PLZ67PNY.js");
1039
1096
  await runHealthchecksList({
1040
1097
  json: jsonMode,
1041
1098
  outputFormat: cliContext.outputFormat
@@ -1049,7 +1106,7 @@ async function main() {
1049
1106
  thresholds.minResults = cli.flags.minResults;
1050
1107
  if (cli.flags.lookbackHours !== void 0)
1051
1108
  thresholds.lookbackHours = cli.flags.lookbackHours;
1052
- const { runHealthchecksRun } = await import("./run-64SBCL4R.js");
1109
+ const { runHealthchecksRun } = await import("./run-MS5SA5YL.js");
1053
1110
  await runHealthchecksRun({
1054
1111
  org,
1055
1112
  id: action,
@@ -1067,7 +1124,7 @@ async function main() {
1067
1124
  }
1068
1125
  case "presets": {
1069
1126
  if (subcommand === "list") {
1070
- const { runPresetsList } = await import("./list-LN6NOZIJ.js");
1127
+ const { runPresetsList } = await import("./list-EYRN5JYC.js");
1071
1128
  await runPresetsList({ outputFormat: cliContext.outputFormat });
1072
1129
  break;
1073
1130
  }
@@ -1078,7 +1135,7 @@ async function main() {
1078
1135
  );
1079
1136
  }
1080
1137
  const org = await resolveOrg();
1081
- const { runPresetsRun } = await import("./run-MH5RYPWA.js");
1138
+ const { runPresetsRun } = await import("./run-YHDUUP66.js");
1082
1139
  await runPresetsRun({
1083
1140
  presetId: action,
1084
1141
  org,
@@ -1095,12 +1152,12 @@ async function main() {
1095
1152
  case "setup":
1096
1153
  case "install":
1097
1154
  case "i": {
1098
- const { setupSkill } = await import("./setup-skill-NQIZBJMR.js");
1099
- setupSkill({ json: jsonMode });
1155
+ const { setupSkill } = await import("./setup-skill-J7PZYVCE.js");
1156
+ setupSkill({ json: jsonMode, cloud: cli.flags.cloud });
1100
1157
  break;
1101
1158
  }
1102
1159
  case "uninstall": {
1103
- const { uninstallSkill } = await import("./setup-skill-NQIZBJMR.js");
1160
+ const { uninstallSkill } = await import("./setup-skill-J7PZYVCE.js");
1104
1161
  uninstallSkill({ json: jsonMode });
1105
1162
  break;
1106
1163
  }
@@ -7,7 +7,7 @@ import {
7
7
  } from "./chunk-VFT3TD3E.js";
8
8
  import {
9
9
  createApiClient
10
- } from "./chunk-MXUZR2BV.js";
10
+ } from "./chunk-LLWKCA3H.js";
11
11
  import "./chunk-EEG7T6WT.js";
12
12
  import "./chunk-TFCNKBRC.js";
13
13
  import "./chunk-U73SABXK.js";
@@ -8,7 +8,7 @@ import {
8
8
  } from "./chunk-VFT3TD3E.js";
9
9
  import {
10
10
  createApiClient
11
- } from "./chunk-MXUZR2BV.js";
11
+ } from "./chunk-LLWKCA3H.js";
12
12
  import "./chunk-EEG7T6WT.js";
13
13
  import "./chunk-TFCNKBRC.js";
14
14
  import "./chunk-U73SABXK.js";
@@ -8,7 +8,7 @@ import {
8
8
  } from "./chunk-VFT3TD3E.js";
9
9
  import {
10
10
  createApiClient
11
- } from "./chunk-MXUZR2BV.js";
11
+ } from "./chunk-LLWKCA3H.js";
12
12
  import "./chunk-EEG7T6WT.js";
13
13
  import "./chunk-TFCNKBRC.js";
14
14
  import "./chunk-U73SABXK.js";
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-VFT3TD3E.js";
5
5
  import {
6
6
  createApiClient
7
- } from "./chunk-MXUZR2BV.js";
7
+ } from "./chunk-LLWKCA3H.js";
8
8
  import "./chunk-EEG7T6WT.js";
9
9
  import {
10
10
  DateTime
@@ -8,7 +8,7 @@ import {
8
8
  } from "./chunk-VFT3TD3E.js";
9
9
  import {
10
10
  createApiClient
11
- } from "./chunk-MXUZR2BV.js";
11
+ } from "./chunk-LLWKCA3H.js";
12
12
  import "./chunk-EEG7T6WT.js";
13
13
  import "./chunk-TFCNKBRC.js";
14
14
  import "./chunk-U73SABXK.js";
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-JCMWDZYY.js";
5
5
  import {
6
6
  createApiClient
7
- } from "./chunk-MXUZR2BV.js";
7
+ } from "./chunk-LLWKCA3H.js";
8
8
  import {
9
9
  AuthCorruptedError,
10
10
  AuthExpiredError,
@@ -0,0 +1,182 @@
1
+ import {
2
+ CliExitError,
3
+ ExitCode
4
+ } from "./chunk-E2LAMILJ.js";
5
+ import {
6
+ printOutput,
7
+ toCsvRows
8
+ } from "./chunk-VFT3TD3E.js";
9
+ import {
10
+ createApiClient
11
+ } from "./chunk-LLWKCA3H.js";
12
+ import "./chunk-EEG7T6WT.js";
13
+ import "./chunk-TFCNKBRC.js";
14
+ import "./chunk-U73SABXK.js";
15
+
16
+ // src/commands/orgs/list.ts
17
+ var VALID_SUBSCRIPTION_STATUSES = /* @__PURE__ */ new Set([
18
+ "PROSPECT",
19
+ "TRIAL",
20
+ "ACTIVE",
21
+ "INTEGRATION"
22
+ ]);
23
+ var DUAL_SERVICES = ["reporting", "reviewing", "protection", "takedowns"];
24
+ var SINGLE_SERVICES = ["detection", "darkWebMonitoring"];
25
+ var ALL_SERVICES = [...DUAL_SERVICES, ...SINGLE_SERVICES];
26
+ function splitCsv(value) {
27
+ if (!value) return [];
28
+ return value.split(",").map((part) => part.trim()).filter(Boolean);
29
+ }
30
+ function parseSubscriptionStatuses(raw) {
31
+ const parts = splitCsv(raw);
32
+ if (parts.length === 0) return void 0;
33
+ const result = [];
34
+ for (const part of parts) {
35
+ const upper = part.toUpperCase();
36
+ if (!VALID_SUBSCRIPTION_STATUSES.has(upper)) {
37
+ throw new CliExitError(
38
+ `Unknown subscription status: '${part}'. Valid values: ${Array.from(VALID_SUBSCRIPTION_STATUSES).join(", ")}.`,
39
+ ExitCode.USAGE
40
+ );
41
+ }
42
+ result.push(upper);
43
+ }
44
+ return result;
45
+ }
46
+ function parseServiceList(raw, flagName) {
47
+ const parts = splitCsv(raw);
48
+ const result = [];
49
+ for (const part of parts) {
50
+ if (!ALL_SERVICES.includes(part)) {
51
+ throw new CliExitError(
52
+ `Unknown service '${part}' in --${flagName}. Valid services: ${ALL_SERVICES.join(", ")}.`,
53
+ ExitCode.USAGE
54
+ );
55
+ }
56
+ result.push(part);
57
+ }
58
+ return result;
59
+ }
60
+ function requireDualService(service, flagName) {
61
+ if (!DUAL_SERVICES.includes(service)) {
62
+ throw new CliExitError(
63
+ `Service '${service}' does not have an automation toggle and can't be used with --${flagName}. Use --service-active / --service-inactive instead.`,
64
+ ExitCode.USAGE
65
+ );
66
+ }
67
+ return service;
68
+ }
69
+ function buildServicesFilter(options) {
70
+ const filters = {};
71
+ const activeSetBy = /* @__PURE__ */ new Map();
72
+ const automatedSetBy = /* @__PURE__ */ new Map();
73
+ function setActive(service, active, flagName) {
74
+ const previous = activeSetBy.get(service);
75
+ if (previous && previous !== flagName) {
76
+ throw new CliExitError(
77
+ `Conflicting flags for service '${service}': --${previous} and --${flagName} can't both be passed.`,
78
+ ExitCode.USAGE
79
+ );
80
+ }
81
+ activeSetBy.set(service, flagName);
82
+ const existing = filters[service] ?? {};
83
+ filters[service] = { ...existing, active };
84
+ }
85
+ function setAutomated(service, automated, flagName) {
86
+ const previous = automatedSetBy.get(service);
87
+ if (previous && previous !== flagName) {
88
+ throw new CliExitError(
89
+ `Conflicting flags for service '${service}': --${previous} and --${flagName} can't both be passed.`,
90
+ ExitCode.USAGE
91
+ );
92
+ }
93
+ automatedSetBy.set(service, flagName);
94
+ const existing = filters[service] ?? {};
95
+ filters[service] = { ...existing, automated };
96
+ }
97
+ for (const service of parseServiceList(options.serviceActive, "service-active")) {
98
+ setActive(service, true, "service-active");
99
+ }
100
+ for (const service of parseServiceList(options.serviceInactive, "service-inactive")) {
101
+ setActive(service, false, "service-inactive");
102
+ }
103
+ for (const service of parseServiceList(options.serviceAutomated, "service-automated")) {
104
+ setAutomated(
105
+ requireDualService(service, "service-automated"),
106
+ true,
107
+ "service-automated"
108
+ );
109
+ }
110
+ for (const service of parseServiceList(options.serviceManual, "service-manual")) {
111
+ setAutomated(requireDualService(service, "service-manual"), false, "service-manual");
112
+ }
113
+ return Object.keys(filters).length > 0 ? filters : void 0;
114
+ }
115
+ function summarizeServices(org) {
116
+ const parts = [];
117
+ for (const service of DUAL_SERVICES) {
118
+ const entry = org.services[service];
119
+ if (!entry.active) continue;
120
+ parts.push(`${service}=${entry.automated ? "auto" : "manual"}`);
121
+ }
122
+ for (const service of SINGLE_SERVICES) {
123
+ if (org.services[service].active) parts.push(service);
124
+ }
125
+ return parts.length > 0 ? parts.join(" ") : "(no services enabled)";
126
+ }
127
+ async function runOrgsList(options) {
128
+ const client = options.apiClient ?? createApiClient();
129
+ const outputFormat = options.outputFormat ?? (options.json ? "json" : "human");
130
+ const input = {
131
+ query: options.query ?? "",
132
+ subscriptionStatus: parseSubscriptionStatuses(options.subscriptionStatus),
133
+ services: buildServicesFilter(options)
134
+ };
135
+ const result = await client.getUserOrgs(input);
136
+ const organizations = result.organizations;
137
+ printOutput({
138
+ outputFormat,
139
+ json: result,
140
+ markdown: [
141
+ `# Organizations (${organizations.length})`,
142
+ "",
143
+ ...organizations.map(
144
+ (org) => `- \`${org.slug}\` \u2014 ${org.name} \u2014 ${org.subscriptionStatus} \u2014 ${summarizeServices(org)}`
145
+ )
146
+ ].join("\n"),
147
+ csv: toCsvRows(
148
+ organizations.map((org) => ({
149
+ slug: org.slug,
150
+ name: org.name,
151
+ subscriptionStatus: org.subscriptionStatus,
152
+ reportingActive: org.services.reporting.active,
153
+ reportingAutomated: org.services.reporting.automated,
154
+ reviewingActive: org.services.reviewing.active,
155
+ reviewingAutomated: org.services.reviewing.automated,
156
+ protectionActive: org.services.protection.active,
157
+ protectionAutomated: org.services.protection.automated,
158
+ takedownsActive: org.services.takedowns.active,
159
+ takedownsAutomated: org.services.takedowns.automated,
160
+ detectionActive: org.services.detection.active,
161
+ darkWebMonitoringActive: org.services.darkWebMonitoring.active
162
+ }))
163
+ ),
164
+ human: () => {
165
+ if (organizations.length === 0) {
166
+ console.log("No organizations matched the filter.");
167
+ return;
168
+ }
169
+ console.log(`Found ${organizations.length} organization(s):`);
170
+ const slugWidth = Math.max(...organizations.map((org) => org.slug.length), 4);
171
+ const nameWidth = Math.max(...organizations.map((org) => org.name.length), 4);
172
+ for (const org of organizations) {
173
+ console.log(
174
+ ` ${org.slug.padEnd(slugWidth)} ${org.name.padEnd(nameWidth)} ${org.subscriptionStatus.padEnd(11)} ${summarizeServices(org)}`
175
+ );
176
+ }
177
+ }
178
+ });
179
+ }
180
+ export {
181
+ runOrgsList
182
+ };
@@ -8,7 +8,7 @@ import {
8
8
  } from "./chunk-VFT3TD3E.js";
9
9
  import {
10
10
  createApiClient
11
- } from "./chunk-MXUZR2BV.js";
11
+ } from "./chunk-LLWKCA3H.js";
12
12
  import "./chunk-EEG7T6WT.js";
13
13
  import "./chunk-TFCNKBRC.js";
14
14
  import "./chunk-U73SABXK.js";
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  PRESETS
3
- } from "./chunk-PIYOWGBZ.js";
3
+ } from "./chunk-AGXMZFUU.js";
4
4
  import "./chunk-E2LAMILJ.js";
5
5
  import {
6
6
  printOutput,
7
7
  toCsvRows
8
8
  } from "./chunk-VFT3TD3E.js";
9
- import "./chunk-MXUZR2BV.js";
9
+ import "./chunk-LLWKCA3H.js";
10
10
  import "./chunk-EEG7T6WT.js";
11
11
  import "./chunk-TFCNKBRC.js";
12
12
  import "./chunk-U73SABXK.js";
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-VFT3TD3E.js";
5
5
  import {
6
6
  createApiClient
7
- } from "./chunk-MXUZR2BV.js";
7
+ } from "./chunk-LLWKCA3H.js";
8
8
  import "./chunk-EEG7T6WT.js";
9
9
  import "./chunk-TFCNKBRC.js";
10
10
  import "./chunk-U73SABXK.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createApiClient
3
- } from "./chunk-MXUZR2BV.js";
3
+ } from "./chunk-LLWKCA3H.js";
4
4
  import "./chunk-EEG7T6WT.js";
5
5
  import "./chunk-TFCNKBRC.js";
6
6
  import "./chunk-U73SABXK.js";
@@ -8,7 +8,7 @@ import {
8
8
  } from "./chunk-VFT3TD3E.js";
9
9
  import {
10
10
  createApiClient
11
- } from "./chunk-MXUZR2BV.js";
11
+ } from "./chunk-LLWKCA3H.js";
12
12
  import "./chunk-EEG7T6WT.js";
13
13
  import "./chunk-TFCNKBRC.js";
14
14
  import "./chunk-U73SABXK.js";
@@ -8,7 +8,7 @@ import {
8
8
  } from "./chunk-VFT3TD3E.js";
9
9
  import {
10
10
  createApiClient
11
- } from "./chunk-MXUZR2BV.js";
11
+ } from "./chunk-LLWKCA3H.js";
12
12
  import "./chunk-EEG7T6WT.js";
13
13
  import "./chunk-TFCNKBRC.js";
14
14
  import "./chunk-U73SABXK.js";
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  getPresetDefinition,
3
3
  runPreset
4
- } from "./chunk-PIYOWGBZ.js";
4
+ } from "./chunk-AGXMZFUU.js";
5
5
  import {
6
6
  CliExitError,
7
7
  ExitCode
8
8
  } from "./chunk-E2LAMILJ.js";
9
9
  import "./chunk-VFT3TD3E.js";
10
- import "./chunk-MXUZR2BV.js";
10
+ import "./chunk-LLWKCA3H.js";
11
11
  import "./chunk-EEG7T6WT.js";
12
12
  import "./chunk-TFCNKBRC.js";
13
13
  import "./chunk-U73SABXK.js";
@@ -6,7 +6,7 @@ import {
6
6
  readInstalledSkillVersion,
7
7
  setupSkill,
8
8
  uninstallSkill
9
- } from "./chunk-BSK4YHFA.js";
9
+ } from "./chunk-ZN3VMRWG.js";
10
10
  import "./chunk-IUZB3DQW.js";
11
11
  export {
12
12
  getBundledSkillContent,
@@ -8,7 +8,7 @@ import {
8
8
  } from "./chunk-VFT3TD3E.js";
9
9
  import {
10
10
  createApiClient
11
- } from "./chunk-MXUZR2BV.js";
11
+ } from "./chunk-LLWKCA3H.js";
12
12
  import "./chunk-EEG7T6WT.js";
13
13
  import "./chunk-TFCNKBRC.js";
14
14
  import "./chunk-U73SABXK.js";
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-VFT3TD3E.js";
5
5
  import {
6
6
  createApiClient
7
- } from "./chunk-MXUZR2BV.js";
7
+ } from "./chunk-LLWKCA3H.js";
8
8
  import "./chunk-EEG7T6WT.js";
9
9
  import "./chunk-TFCNKBRC.js";
10
10
  import "./chunk-U73SABXK.js";
@@ -8,7 +8,7 @@ import {
8
8
  } from "./chunk-VFT3TD3E.js";
9
9
  import {
10
10
  createApiClient
11
- } from "./chunk-MXUZR2BV.js";
11
+ } from "./chunk-LLWKCA3H.js";
12
12
  import "./chunk-EEG7T6WT.js";
13
13
  import "./chunk-TFCNKBRC.js";
14
14
  import "./chunk-U73SABXK.js";
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@chainpatrol/cli",
3
3
  "description": "The official ChainPatrol CLI — terminal interface for threat detection",
4
4
  "author": "Umar Ahmed <umar@chainpatrol.io>",
5
- "version": "0.5.0",
5
+ "version": "0.7.0",
6
6
  "license": "UNLICENSED",
7
7
  "homepage": "https://chainpatrol.com/docs/cli",
8
8
  "keywords": [