@contextual-io/cli 0.5.0 → 0.7.1

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 CHANGED
@@ -20,7 +20,7 @@ $ npm install -g @contextual-io/cli
20
20
  $ ctxl COMMAND
21
21
  running command...
22
22
  $ ctxl (--version)
23
- @contextual-io/cli/0.5.0 linux-x64 node-v25.2.1
23
+ @contextual-io/cli/0.7.1 linux-x64 node-v25.9.0
24
24
  $ ctxl --help [COMMAND]
25
25
  USAGE
26
26
  $ ctxl COMMAND
@@ -48,8 +48,11 @@ USAGE
48
48
  * [`ctxl records list [URI]`](#ctxl-records-list-uri)
49
49
  * [`ctxl records patch [URI]`](#ctxl-records-patch-uri)
50
50
  * [`ctxl records query [URI]`](#ctxl-records-query-uri)
51
+ * [`ctxl records remove [URI]`](#ctxl-records-remove-uri)
51
52
  * [`ctxl records replace [URI]`](#ctxl-records-replace-uri)
53
+ * [`ctxl records rm [URI]`](#ctxl-records-rm-uri)
52
54
  * [`ctxl records search [URI]`](#ctxl-records-search-uri)
55
+ * [`ctxl records stats [URI]`](#ctxl-records-stats-uri)
53
56
  * [`ctxl types <COMMAND>`](#ctxl-types-command)
54
57
  * [`ctxl types add`](#ctxl-types-add)
55
58
  * [`ctxl types create`](#ctxl-types-create)
@@ -57,7 +60,9 @@ USAGE
57
60
  * [`ctxl types get [URI]`](#ctxl-types-get-uri)
58
61
  * [`ctxl types import`](#ctxl-types-import)
59
62
  * [`ctxl types list`](#ctxl-types-list)
63
+ * [`ctxl types remove [URI]`](#ctxl-types-remove-uri)
60
64
  * [`ctxl types replace [URI]`](#ctxl-types-replace-uri)
65
+ * [`ctxl types rm [URI]`](#ctxl-types-rm-uri)
61
66
  * [`ctxl types search`](#ctxl-types-search)
62
67
 
63
68
  ## `ctxl autocomplete [SHELL]`
@@ -349,6 +354,10 @@ GLOBAL FLAGS
349
354
  DESCRIPTION
350
355
  Delete record(s).
351
356
 
357
+ ALIASES
358
+ $ ctxl records rm
359
+ $ ctxl records remove
360
+
352
361
  EXAMPLES
353
362
  $ ctxl records delete native-object:my-type/instance-1
354
363
 
@@ -542,6 +551,43 @@ EXAMPLES
542
551
  $ ctxl records query --type my-type --include-total --query-file query.json
543
552
  ```
544
553
 
554
+ ## `ctxl records remove [URI]`
555
+
556
+ Delete record(s).
557
+
558
+ ```
559
+ USAGE
560
+ $ ctxl records remove [URI] [-C <value>] [-I <value>...] [-T <value>]
561
+
562
+ ARGUMENTS
563
+ [URI] uri of record
564
+
565
+ FLAGS
566
+ -I, --id=<value>... id(s)
567
+ -T, --type=<value> type
568
+
569
+ GLOBAL FLAGS
570
+ -C, --config-id=<value> Specify config id to use for call.
571
+
572
+ DESCRIPTION
573
+ Delete record(s).
574
+
575
+ ALIASES
576
+ $ ctxl records rm
577
+ $ ctxl records remove
578
+
579
+ EXAMPLES
580
+ $ ctxl records remove native-object:my-type/instance-1
581
+
582
+ $ ctxl records remove native-object:my-type --id instance-1
583
+
584
+ $ ctxl records remove native-object:my-type --id instance-1 --id instance-2
585
+
586
+ $ ctxl records remove --type my-type --id instance-1
587
+
588
+ $ ctxl records remove --type my-type --id instance-1 --id instance-2
589
+ ```
590
+
545
591
  ## `ctxl records replace [URI]`
546
592
 
547
593
  Replace a record.
@@ -572,6 +618,43 @@ EXAMPLES
572
618
  $ ctxl records replace --type my-type --id instance-1 --input-file record.json
573
619
  ```
574
620
 
621
+ ## `ctxl records rm [URI]`
622
+
623
+ Delete record(s).
624
+
625
+ ```
626
+ USAGE
627
+ $ ctxl records rm [URI] [-C <value>] [-I <value>...] [-T <value>]
628
+
629
+ ARGUMENTS
630
+ [URI] uri of record
631
+
632
+ FLAGS
633
+ -I, --id=<value>... id(s)
634
+ -T, --type=<value> type
635
+
636
+ GLOBAL FLAGS
637
+ -C, --config-id=<value> Specify config id to use for call.
638
+
639
+ DESCRIPTION
640
+ Delete record(s).
641
+
642
+ ALIASES
643
+ $ ctxl records rm
644
+ $ ctxl records remove
645
+
646
+ EXAMPLES
647
+ $ ctxl records rm native-object:my-type/instance-1
648
+
649
+ $ ctxl records rm native-object:my-type --id instance-1
650
+
651
+ $ ctxl records rm native-object:my-type --id instance-1 --id instance-2
652
+
653
+ $ ctxl records rm --type my-type --id instance-1
654
+
655
+ $ ctxl records rm --type my-type --id instance-1 --id instance-2
656
+ ```
657
+
575
658
  ## `ctxl records search [URI]`
576
659
 
577
660
  List records.
@@ -616,6 +699,35 @@ EXAMPLES
616
699
  $ ctxl records search --type my-type -s field1=value1 -s field2=value2 --include-total
617
700
  ```
618
701
 
702
+ ## `ctxl records stats [URI]`
703
+
704
+ Get the stats of a record.
705
+
706
+ ```
707
+ USAGE
708
+ $ ctxl records stats [URI] [-C <value>] [-I <value>] [-T <value>]
709
+
710
+ ARGUMENTS
711
+ [URI] uri of record
712
+
713
+ FLAGS
714
+ -I, --id=<value> id
715
+ -T, --type=<value> type
716
+
717
+ GLOBAL FLAGS
718
+ -C, --config-id=<value> Specify config id to use for call.
719
+
720
+ DESCRIPTION
721
+ Get the stats of a record.
722
+
723
+ EXAMPLES
724
+ $ ctxl records stats native-object:my-type/instance-1
725
+
726
+ $ ctxl records stats native-object:my-type --id instance-1
727
+
728
+ $ ctxl records stats --type my-type --id instance-1
729
+ ```
730
+
619
731
  ## `ctxl types <COMMAND>`
620
732
 
621
733
  Manage types.
@@ -702,6 +814,10 @@ GLOBAL FLAGS
702
814
  DESCRIPTION
703
815
  Delete a type.
704
816
 
817
+ ALIASES
818
+ $ ctxl types rm
819
+ $ ctxl types remove
820
+
705
821
  EXAMPLES
706
822
  $ ctxl types delete native-object:my-type
707
823
 
@@ -799,6 +915,36 @@ EXAMPLES
799
915
  $ ctxl types list -s field1=value1 -s field2=value2 --include-total
800
916
  ```
801
917
 
918
+ ## `ctxl types remove [URI]`
919
+
920
+ Delete a type.
921
+
922
+ ```
923
+ USAGE
924
+ $ ctxl types remove [URI] [-C <value>] [-T <value>]
925
+
926
+ ARGUMENTS
927
+ [URI] uri of type
928
+
929
+ FLAGS
930
+ -T, --type=<value> type
931
+
932
+ GLOBAL FLAGS
933
+ -C, --config-id=<value> Specify config id to use for call.
934
+
935
+ DESCRIPTION
936
+ Delete a type.
937
+
938
+ ALIASES
939
+ $ ctxl types rm
940
+ $ ctxl types remove
941
+
942
+ EXAMPLES
943
+ $ ctxl types remove native-object:my-type
944
+
945
+ $ ctxl types remove --type my-type
946
+ ```
947
+
802
948
  ## `ctxl types replace [URI]`
803
949
 
804
950
  Replace a type.
@@ -826,6 +972,36 @@ EXAMPLES
826
972
  $ ctxl types replace --type my-type --input-file record.json
827
973
  ```
828
974
 
975
+ ## `ctxl types rm [URI]`
976
+
977
+ Delete a type.
978
+
979
+ ```
980
+ USAGE
981
+ $ ctxl types rm [URI] [-C <value>] [-T <value>]
982
+
983
+ ARGUMENTS
984
+ [URI] uri of type
985
+
986
+ FLAGS
987
+ -T, --type=<value> type
988
+
989
+ GLOBAL FLAGS
990
+ -C, --config-id=<value> Specify config id to use for call.
991
+
992
+ DESCRIPTION
993
+ Delete a type.
994
+
995
+ ALIASES
996
+ $ ctxl types rm
997
+ $ ctxl types remove
998
+
999
+ EXAMPLES
1000
+ $ ctxl types rm native-object:my-type
1001
+
1002
+ $ ctxl types rm --type my-type
1003
+ ```
1004
+
829
1005
  ## `ctxl types search`
830
1006
 
831
1007
  List types.
@@ -1,5 +1,6 @@
1
1
  import { BaseCommand } from "../../base.js";
2
2
  export default class RecordsDelete extends BaseCommand<typeof RecordsDelete> {
3
+ static aliases: string[];
3
4
  static args: {
4
5
  uri: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
5
6
  };
@@ -3,6 +3,7 @@ import { BaseCommand } from "../../base.js";
3
3
  import { parseUri } from "../../models/uri.js";
4
4
  import { getNativeObjectApiEndpoint } from "../../utils/endpoints.js";
5
5
  export default class RecordsDelete extends BaseCommand {
6
+ static aliases = ["records rm", "records remove"];
6
7
  static args = {
7
8
  "uri": Args.string({ description: "uri of record" }),
8
9
  };
@@ -0,0 +1,13 @@
1
+ import { BaseCommand } from "../../base.js";
2
+ export default class RecordsStats extends BaseCommand<typeof RecordsStats> {
3
+ static args: {
4
+ uri: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
5
+ };
6
+ static description: string;
7
+ static examples: string[];
8
+ static flags: {
9
+ id: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
+ type: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
+ };
12
+ run(): Promise<void>;
13
+ }
@@ -0,0 +1,73 @@
1
+ import { Args, Flags } from "@oclif/core";
2
+ import { BaseCommand } from "../../base.js";
3
+ import { parseUri } from "../../models/uri.js";
4
+ import { getNativeObjectApiEndpoint } from "../../utils/endpoints.js";
5
+ const bytesToString = (bytes) => {
6
+ if (bytes < 1000)
7
+ return `${bytes} B`;
8
+ bytes /= 1000;
9
+ if (bytes < 1000)
10
+ return `${bytes.toFixed(2)} kB`;
11
+ bytes /= 1000;
12
+ if (bytes < 1000)
13
+ return `${bytes.toFixed(2)} MB`;
14
+ bytes /= 1000;
15
+ return `${bytes.toFixed(2)} GB`;
16
+ };
17
+ export default class RecordsStats extends BaseCommand {
18
+ static args = {
19
+ "uri": Args.string({ description: "uri of record" }),
20
+ };
21
+ static description = "Get the stats of a record.";
22
+ static examples = [
23
+ "<%= config.bin %> <%= command.id %> native-object:my-type/instance-1",
24
+ "<%= config.bin %> <%= command.id %> native-object:my-type --id instance-1",
25
+ "<%= config.bin %> <%= command.id %> --type my-type --id instance-1",
26
+ ];
27
+ static flags = {
28
+ id: Flags.string({
29
+ char: "I",
30
+ description: "id",
31
+ }),
32
+ type: Flags.string({
33
+ char: "T",
34
+ description: "type",
35
+ }),
36
+ };
37
+ async run() {
38
+ const { uri } = this.args;
39
+ const { id: flagId, type: flagType } = this.flags;
40
+ let type = flagType;
41
+ let lookup = flagId;
42
+ if (uri) {
43
+ const { id, type: uriType } = parseUri(uri);
44
+ type = uriType;
45
+ if (id) {
46
+ lookup = id;
47
+ }
48
+ }
49
+ if (!type) {
50
+ throw new Error("Type not provided");
51
+ }
52
+ if (!lookup) {
53
+ throw new Error("Id not provided");
54
+ }
55
+ const record = await this.fetch(({ silo, tenantId }) => getNativeObjectApiEndpoint(tenantId, silo) + `/api/v1/${type}/${lookup}`);
56
+ const totalBytes = Buffer.byteLength(JSON.stringify(record));
57
+ const { _metaData, ...data } = record;
58
+ const bytesWithoutMetaData = Buffer.byteLength(JSON.stringify(data));
59
+ const rv = { total: bytesToString(totalBytes), withoutMetaData: bytesToString(bytesWithoutMetaData) };
60
+ if (type === "flow") {
61
+ const nodes = data.node_red_data.flows;
62
+ const largestFiveNodes = nodes
63
+ .map(n => [n, Buffer.byteLength(JSON.stringify(n))])
64
+ .sort(([, sizeA], [, sizeB]) => sizeA - sizeB)
65
+ .slice(-5)
66
+ .map(([{ id, name }, size]) => ({ id, name, size: bytesToString(size) }));
67
+ this.logJson({ ...rv, largestFiveNodes });
68
+ }
69
+ else {
70
+ this.logJson(rv);
71
+ }
72
+ }
73
+ }
@@ -1,5 +1,6 @@
1
1
  import { BaseCommand } from "../../base.js";
2
2
  export default class TypesDelete extends BaseCommand<typeof TypesDelete> {
3
+ static aliases: string[];
3
4
  static args: {
4
5
  uri: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
5
6
  };
@@ -3,6 +3,7 @@ import { BaseCommand } from "../../base.js";
3
3
  import { parseUri } from "../../models/uri.js";
4
4
  import { getRegistryApiEndpoint } from "../../utils/endpoints.js";
5
5
  export default class TypesDelete extends BaseCommand {
6
+ static aliases = ["types rm", "types remove"];
6
7
  static args = {
7
8
  "uri": Args.string({ description: "uri of type" }),
8
9
  };
@@ -0,0 +1,3 @@
1
+ import { Hook } from "@oclif/core";
2
+ declare const hook: Hook.Init;
3
+ export default hook;
@@ -0,0 +1,38 @@
1
+ import chalk from "chalk";
2
+ import { boxMessage } from "../../utils/message.js";
3
+ import { checkForUpdate, hasNotifiedVersion, markChecked } from "../../utils/update-check.js";
4
+ const defaultCheckFrequencyMs = 6 * 60 * 60 * 1000;
5
+ const dayMs = 24 * 60 * 60 * 1000;
6
+ const getUpdateMessage = ({ binName, currentVersion, latestVersion, packageName }) => boxMessage([
7
+ `A newer version of ${chalk.blueBright(chalk.bold(binName))} is available: ${chalk.bold(currentVersion)} -> ${chalk.bold(latestVersion)}`,
8
+ `Install ${chalk.greenBright(chalk.bold(packageName + "@latest"))} with your preferred package manager.`,
9
+ ].join("\n")) + "\n\n";
10
+ const hook = async function ({ config }) {
11
+ if (config.scopedEnvVarTrue("DISABLE_UPDATE_CHECK"))
12
+ return;
13
+ const updateCheckDays = Number.parseInt(config.scopedEnvVar("UPDATE_CHECK_DAYS") ?? "0", 10);
14
+ if (!Number.isSafeInteger(updateCheckDays) || updateCheckDays < 0)
15
+ return;
16
+ const checkFrequencyMs = updateCheckDays > 0 ? updateCheckDays * dayMs : defaultCheckFrequencyMs;
17
+ const result = await checkForUpdate({
18
+ currentVersion: config.version,
19
+ packageName: config.pjson.name,
20
+ timeoutMs: checkFrequencyMs,
21
+ });
22
+ if (!result) {
23
+ markChecked({ cacheDir: config.cacheDir });
24
+ return;
25
+ }
26
+ if (result.updateAvailable && !hasNotifiedVersion({ cacheDir: config.cacheDir, latestVersion: result.latestVersion })) {
27
+ process.stderr.write(getUpdateMessage({
28
+ binName: config.bin,
29
+ currentVersion: result.currentVersion,
30
+ latestVersion: result.latestVersion,
31
+ packageName: config.pjson.name,
32
+ }));
33
+ markChecked({ cacheDir: config.cacheDir, notifiedVersion: result.latestVersion });
34
+ return;
35
+ }
36
+ markChecked({ cacheDir: config.cacheDir });
37
+ };
38
+ export default hook;
@@ -0,0 +1,14 @@
1
+ type BoxOptions = {
2
+ borderColorFn?: (text: string) => string;
3
+ bottomLeftBorderChar?: string;
4
+ bottomRightBorderChar?: string;
5
+ textColorFn?: (text: string) => string;
6
+ topLeftBorderChar?: string;
7
+ topRightBorderChar?: string;
8
+ xBorderChar?: string;
9
+ xPadding?: number;
10
+ yBorderChar?: string;
11
+ yPadding?: number;
12
+ };
13
+ export declare const boxMessage: (message: string, { borderColorFn, textColorFn, xPadding, yPadding, }?: BoxOptions) => string;
14
+ export {};
@@ -0,0 +1,31 @@
1
+ import chalk from "chalk";
2
+ import { stripVTControlCharacters } from "node:util";
3
+ const BoxTL = "╭";
4
+ const BoxTR = "╮";
5
+ const BoxBL = "╰";
6
+ const BoxBR = "╯";
7
+ const BoxX = "─";
8
+ const BoxY = "│";
9
+ const getVisibleLength = (value) => stripVTControlCharacters(value).length;
10
+ export const boxMessage = (message, { borderColorFn = (text) => chalk.yellow(text), textColorFn = (text) => chalk.white(text), xPadding = 2, yPadding = 0, } = {}) => {
11
+ xPadding = Math.max(0, xPadding);
12
+ yPadding = Math.max(0, yPadding);
13
+ const lines = message.split("\n");
14
+ const maxLength = Math.max(...lines.map(line => getVisibleLength(line)));
15
+ const totalInnerWidth = maxLength + xPadding * 2;
16
+ const leftPadding = " ".repeat(xPadding);
17
+ const topBorder = borderColorFn(`${BoxTL}${BoxX.repeat(totalInnerWidth)}${BoxTR}`);
18
+ const bottomBorder = borderColorFn(`${BoxBL}${BoxX.repeat(totalInnerWidth)}${BoxBR}`);
19
+ const yPaddingLines = Array.from({ length: yPadding }, () => `${textColorFn(BoxY)}${" ".repeat(totalInnerWidth)}${textColorFn(BoxY)}`);
20
+ const contentLines = lines.map(line => {
21
+ const rightPadding = " ".repeat(maxLength - getVisibleLength(line) + xPadding);
22
+ return `${borderColorFn(BoxY)}${leftPadding}${textColorFn(line)}${rightPadding}${borderColorFn(BoxY)}`;
23
+ });
24
+ return [
25
+ topBorder,
26
+ ...yPaddingLines,
27
+ ...contentLines,
28
+ ...yPaddingLines,
29
+ bottomBorder,
30
+ ].join("\n");
31
+ };
@@ -0,0 +1,23 @@
1
+ export type UpdateCheckResult = {
2
+ currentVersion: string;
3
+ latestVersion: string;
4
+ updateAvailable: boolean;
5
+ };
6
+ export declare const compareVersions: (left: string, right: string) => -1 | 0 | 1;
7
+ export declare const checkForUpdate: ({ currentVersion, packageName, timeoutMs, }: {
8
+ currentVersion: string;
9
+ packageName: string;
10
+ timeoutMs?: number;
11
+ }) => Promise<undefined | UpdateCheckResult>;
12
+ export declare const shouldRunPeriodicCheck: ({ cacheDir, frequencyMs, }: {
13
+ cacheDir: string;
14
+ frequencyMs: number;
15
+ }) => boolean;
16
+ export declare const markChecked: ({ cacheDir, notifiedVersion, }: {
17
+ cacheDir: string;
18
+ notifiedVersion?: string;
19
+ }) => void;
20
+ export declare const hasNotifiedVersion: ({ cacheDir, latestVersion, }: {
21
+ cacheDir: string;
22
+ latestVersion: string;
23
+ }) => boolean;
@@ -0,0 +1,101 @@
1
+ import fetch from "cross-fetch";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { z } from "zod";
5
+ const NpmLatestVersionResponse = z.object({
6
+ version: z.string(),
7
+ });
8
+ const updateCheckFileName = "update-check.json";
9
+ const parseVersionPart = (value) => {
10
+ const parsed = Number.parseInt(value, 10);
11
+ return Number.isNaN(parsed) ? 0 : parsed;
12
+ };
13
+ const splitVersion = (version) => {
14
+ const trimmed = version.startsWith("v") ? version.slice(1) : version;
15
+ const [corePart, prerelease] = trimmed.split("-", 2);
16
+ const core = corePart.split(".").map((part) => parseVersionPart(part));
17
+ return { core, prerelease };
18
+ };
19
+ export const compareVersions = (left, right) => {
20
+ const leftVersion = splitVersion(left);
21
+ const rightVersion = splitVersion(right);
22
+ const maxLength = Math.max(leftVersion.core.length, rightVersion.core.length);
23
+ for (let i = 0; i < maxLength; i += 1) {
24
+ const leftPart = leftVersion.core[i] ?? 0;
25
+ const rightPart = rightVersion.core[i] ?? 0;
26
+ if (leftPart > rightPart)
27
+ return 1;
28
+ if (leftPart < rightPart)
29
+ return -1;
30
+ }
31
+ if (!leftVersion.prerelease && rightVersion.prerelease)
32
+ return 1;
33
+ if (leftVersion.prerelease && !rightVersion.prerelease)
34
+ return -1;
35
+ return 0;
36
+ };
37
+ const readState = (cacheDir) => {
38
+ const statePath = path.join(cacheDir, updateCheckFileName);
39
+ if (!fs.existsSync(statePath))
40
+ return {};
41
+ try {
42
+ const rawState = fs.readFileSync(statePath, "utf8");
43
+ return JSON.parse(rawState);
44
+ }
45
+ catch {
46
+ return {};
47
+ }
48
+ };
49
+ const writeState = (cacheDir, state) => {
50
+ if (!fs.existsSync(cacheDir)) {
51
+ fs.mkdirSync(cacheDir, { recursive: true });
52
+ }
53
+ const statePath = path.join(cacheDir, updateCheckFileName);
54
+ fs.writeFileSync(statePath, JSON.stringify(state, null, 2), "utf8");
55
+ };
56
+ const fetchLatestVersion = async (packageName, timeoutMs) => {
57
+ try {
58
+ const encodedPackageName = encodeURIComponent(packageName);
59
+ const response = await fetch(`https://registry.npmjs.org/${encodedPackageName}/latest`, {
60
+ signal: AbortSignal.timeout(timeoutMs),
61
+ });
62
+ if (!response.ok)
63
+ return undefined;
64
+ const { version } = NpmLatestVersionResponse.parse(await response.json());
65
+ return version;
66
+ }
67
+ catch {
68
+ return undefined;
69
+ }
70
+ };
71
+ export const checkForUpdate = async ({ currentVersion, packageName, timeoutMs = 1500, }) => {
72
+ const latestVersion = await fetchLatestVersion(packageName, timeoutMs);
73
+ if (!latestVersion)
74
+ return undefined;
75
+ return {
76
+ currentVersion,
77
+ latestVersion,
78
+ updateAvailable: compareVersions(latestVersion, currentVersion) > 0,
79
+ };
80
+ };
81
+ export const shouldRunPeriodicCheck = ({ cacheDir, frequencyMs, }) => {
82
+ const state = readState(cacheDir);
83
+ if (!state.lastCheckedAt)
84
+ return true;
85
+ const lastCheckedAt = new Date(state.lastCheckedAt).getTime();
86
+ if (Number.isNaN(lastCheckedAt))
87
+ return true;
88
+ return Date.now() - lastCheckedAt >= frequencyMs;
89
+ };
90
+ export const markChecked = ({ cacheDir, notifiedVersion, }) => {
91
+ const state = readState(cacheDir);
92
+ writeState(cacheDir, {
93
+ ...state,
94
+ lastCheckedAt: new Date().toISOString(),
95
+ lastNotifiedVersion: notifiedVersion ?? state.lastNotifiedVersion,
96
+ });
97
+ };
98
+ export const hasNotifiedVersion = ({ cacheDir, latestVersion, }) => {
99
+ const state = readState(cacheDir);
100
+ return state.lastNotifiedVersion === latestVersion;
101
+ };
@@ -326,7 +326,10 @@
326
326
  ]
327
327
  },
328
328
  "records:delete": {
329
- "aliases": [],
329
+ "aliases": [
330
+ "records:rm",
331
+ "records:remove"
332
+ ],
330
333
  "args": {
331
334
  "uri": {
332
335
  "description": "uri of record",
@@ -858,6 +861,63 @@
858
861
  "replace.js"
859
862
  ]
860
863
  },
864
+ "records:stats": {
865
+ "aliases": [],
866
+ "args": {
867
+ "uri": {
868
+ "description": "uri of record",
869
+ "name": "uri"
870
+ }
871
+ },
872
+ "description": "Get the stats of a record.",
873
+ "examples": [
874
+ "<%= config.bin %> <%= command.id %> native-object:my-type/instance-1",
875
+ "<%= config.bin %> <%= command.id %> native-object:my-type --id instance-1",
876
+ "<%= config.bin %> <%= command.id %> --type my-type --id instance-1"
877
+ ],
878
+ "flags": {
879
+ "config-id": {
880
+ "char": "C",
881
+ "helpGroup": "GLOBAL",
882
+ "name": "config-id",
883
+ "summary": "Specify config id to use for call.",
884
+ "hasDynamicHelp": false,
885
+ "multiple": false,
886
+ "type": "option"
887
+ },
888
+ "id": {
889
+ "char": "I",
890
+ "description": "id",
891
+ "name": "id",
892
+ "hasDynamicHelp": false,
893
+ "multiple": false,
894
+ "type": "option"
895
+ },
896
+ "type": {
897
+ "char": "T",
898
+ "description": "type",
899
+ "name": "type",
900
+ "hasDynamicHelp": false,
901
+ "multiple": false,
902
+ "type": "option"
903
+ }
904
+ },
905
+ "hasDynamicHelp": false,
906
+ "hiddenAliases": [],
907
+ "id": "records:stats",
908
+ "pluginAlias": "@contextual-io/cli",
909
+ "pluginName": "@contextual-io/cli",
910
+ "pluginType": "core",
911
+ "strict": true,
912
+ "enableJsonFlag": false,
913
+ "isESM": true,
914
+ "relativePath": [
915
+ "dist",
916
+ "commands",
917
+ "records",
918
+ "stats.js"
919
+ ]
920
+ },
861
921
  "types:add": {
862
922
  "aliases": [
863
923
  "types:create",
@@ -906,7 +966,10 @@
906
966
  ]
907
967
  },
908
968
  "types:delete": {
909
- "aliases": [],
969
+ "aliases": [
970
+ "types:rm",
971
+ "types:remove"
972
+ ],
910
973
  "args": {
911
974
  "uri": {
912
975
  "description": "uri of type",
@@ -1196,5 +1259,5 @@
1196
1259
  ]
1197
1260
  }
1198
1261
  },
1199
- "version": "0.5.0"
1262
+ "version": "0.7.1"
1200
1263
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@contextual-io/cli",
3
3
  "description": "Contextual CLI",
4
- "version": "0.5.0",
4
+ "version": "0.7.1",
5
5
  "author": "Nasser Oloumi",
6
6
  "bin": {
7
7
  "ctxl": "./bin/run.js"
@@ -11,7 +11,7 @@
11
11
  "@oclif/plugin-autocomplete": "^3.2.39",
12
12
  "@oclif/plugin-help": "^6",
13
13
  "@oclif/plugin-not-found": "^3.2.73",
14
- "@oclif/table": "^0.5.1",
14
+ "@oclif/table": "^0.5.2",
15
15
  "chalk": "^5.6.2",
16
16
  "cross-fetch": "^4.1.0",
17
17
  "open": "^11.0.0",
@@ -33,7 +33,7 @@
33
33
  "eslint-config-prettier": "^10",
34
34
  "eslint-plugin-unused-imports": "^4.3.0",
35
35
  "mocha": "^10",
36
- "oclif": "^4",
36
+ "oclif": "^4.22.81",
37
37
  "shx": "^0.3.3",
38
38
  "ts-node": "^10",
39
39
  "typescript": "^5"
@@ -57,6 +57,9 @@
57
57
  "bin": "ctxl",
58
58
  "dirname": "ctxl",
59
59
  "commands": "./dist/commands",
60
+ "hooks": {
61
+ "init": "./dist/hooks/init/index.js"
62
+ },
60
63
  "plugins": [
61
64
  "@oclif/plugin-help",
62
65
  "@oclif/plugin-not-found",