@skrr-ai/cli 0.1.19 → 0.1.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/base-command.d.ts +12 -9
- package/dist/base-command.js +27 -26
- package/dist/commands/commitments/action-proposals/decide.js +22 -5
- package/dist/commands/commitments/action-proposals/execute.js +7 -3
- package/dist/commands/commitments/action-proposals/propose.d.ts +32 -0
- package/dist/commands/commitments/action-proposals/propose.js +111 -0
- package/dist/commands/commitments/action-proposals.js +6 -4
- package/dist/commands/commitments/create.d.ts +2 -0
- package/dist/commands/commitments/create.js +42 -2
- package/dist/commands/commitments/doctor.js +11 -0
- package/dist/commands/commitments/update.d.ts +2 -0
- package/dist/commands/commitments/update.js +40 -5
- package/dist/commands/store/browse.d.ts +14 -0
- package/dist/commands/store/browse.js +71 -0
- package/dist/commands/store/install.d.ts +16 -0
- package/dist/commands/store/install.js +54 -0
- package/dist/commands/store/releases.d.ts +19 -0
- package/dist/commands/store/releases.js +60 -0
- package/dist/commands/store/update.d.ts +15 -0
- package/dist/commands/store/update.js +69 -0
- package/dist/commands/store/updates.d.ts +24 -0
- package/dist/commands/store/updates.js +113 -0
- package/dist/commands/subscriptions/cancel.d.ts +14 -0
- package/dist/commands/subscriptions/cancel.js +47 -0
- package/dist/commands/subscriptions/health.d.ts +24 -0
- package/dist/commands/subscriptions/health.js +62 -0
- package/dist/commands/subscriptions/list.d.ts +9 -0
- package/dist/commands/subscriptions/list.js +52 -0
- package/dist/commands/subscriptions/status.d.ts +12 -0
- package/dist/commands/subscriptions/status.js +49 -0
- package/dist/commands/subscriptions/subscribe.d.ts +15 -0
- package/dist/commands/subscriptions/subscribe.js +59 -0
- package/dist/commands/tasks/complete.d.ts +10 -4
- package/dist/commands/tasks/complete.js +7 -5
- package/dist/commands/tasks/self-schedule.d.ts +30 -0
- package/dist/commands/tasks/self-schedule.js +114 -0
- package/dist/commands/triggers/disable.js +3 -1
- package/dist/commands/triggers/enable.js +3 -1
- package/dist/commands/triggers/rotate-secret.js +5 -0
- package/dist/commands/triggers/show.js +3 -1
- package/dist/lib/commitment-product.js +9 -0
- package/dist/lib/commitments.d.ts +21 -1
- package/dist/lib/commitments.js +62 -1
- package/dist/lib/node-adapter.js +4 -0
- package/dist/lib/task-extras.d.ts +18 -0
- package/dist/lib/task-extras.js +19 -1
- package/dist/lib/triggers.d.ts +21 -2
- package/dist/lib/triggers.js +48 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/refreshClassification.js +9 -2
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/refreshClassification.js +9 -2
- package/dist/node_modules/@skrr-ai/data-provider/index.js +4073 -3904
- package/oclif.manifest.json +18424 -17362
- package/package.json +1 -1
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
5
|
+
const base_command_1 = require("../../base-command");
|
|
6
|
+
const format_1 = require("../../lib/format");
|
|
7
|
+
class StoreBrowse extends base_command_1.BaseCommand {
|
|
8
|
+
static description = 'Browse published agents in the store';
|
|
9
|
+
static examples = [
|
|
10
|
+
'<%= config.bin %> store browse',
|
|
11
|
+
'<%= config.bin %> store browse --q "cost watchdog"',
|
|
12
|
+
'<%= config.bin %> store browse --category engineering --limit 10 --json',
|
|
13
|
+
];
|
|
14
|
+
static flags = {
|
|
15
|
+
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
16
|
+
q: core_1.Flags.string({ description: 'Search query' }),
|
|
17
|
+
category: core_1.Flags.string({ description: 'Filter by category' }),
|
|
18
|
+
limit: core_1.Flags.integer({ description: 'Max results', default: 20 }),
|
|
19
|
+
cursor: core_1.Flags.string({ description: 'Pagination cursor from a previous page' }),
|
|
20
|
+
sort: core_1.Flags.string({ description: 'Sort order', options: ['popular', 'newest', 'rating'] }),
|
|
21
|
+
};
|
|
22
|
+
async run() {
|
|
23
|
+
this.requireAuth();
|
|
24
|
+
const { flags } = await this.parse(StoreBrowse);
|
|
25
|
+
let response;
|
|
26
|
+
try {
|
|
27
|
+
response = await data_provider_1.dataService.getStoreAgents({
|
|
28
|
+
limit: flags.limit,
|
|
29
|
+
...(flags.q ? { q: flags.q } : {}),
|
|
30
|
+
...(flags.category ? { category: flags.category } : {}),
|
|
31
|
+
...(flags.cursor ? { cursor: flags.cursor } : {}),
|
|
32
|
+
...(flags.sort ? { sortBy: flags.sort } : {}),
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
this.handleApiError(err);
|
|
37
|
+
}
|
|
38
|
+
if (flags.json) {
|
|
39
|
+
this.log(JSON.stringify(response, null, 2));
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const r = response;
|
|
43
|
+
const items = r?.data ?? [];
|
|
44
|
+
if (items.length === 0) {
|
|
45
|
+
this.log('No agents found.');
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
(0, format_1.renderTable)(items.map((a) => ({
|
|
49
|
+
id: String(a.id ?? '-'),
|
|
50
|
+
name: String(a.name ?? '-'),
|
|
51
|
+
// Price is a property of the LISTING, so it is read from the listing
|
|
52
|
+
// row rather than from anything the agent carries.
|
|
53
|
+
price: a.price ? String(a.price) : 'free',
|
|
54
|
+
rating: a.rating ? `${Number(a.rating).toFixed(1)} (${a.ratingCount ?? 0})` : '-',
|
|
55
|
+
installs: String(a.installCount ?? 0),
|
|
56
|
+
author: String(a.authorName ?? '-'),
|
|
57
|
+
})), [
|
|
58
|
+
{ key: 'id', header: 'ID' },
|
|
59
|
+
{ key: 'name', header: 'NAME', maxWidth: 30 },
|
|
60
|
+
{ key: 'price', header: 'PRICE' },
|
|
61
|
+
{ key: 'rating', header: 'RATING' },
|
|
62
|
+
{ key: 'installs', header: 'INSTALLS' },
|
|
63
|
+
{ key: 'author', header: 'PUBLISHER', maxWidth: 22 },
|
|
64
|
+
], (line) => this.log(line));
|
|
65
|
+
if (r?.next_cursor) {
|
|
66
|
+
this.log('');
|
|
67
|
+
this.log(`Next page: --cursor ${r.next_cursor}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
exports.default = StoreBrowse;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base-command';
|
|
2
|
+
export default class StoreInstall extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static args: {
|
|
6
|
+
agentId: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
7
|
+
};
|
|
8
|
+
static flags: {
|
|
9
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
10
|
+
release: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
11
|
+
space: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
12
|
+
'include-bootstrap': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
13
|
+
'include-memory': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
14
|
+
};
|
|
15
|
+
run(): Promise<void>;
|
|
16
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
5
|
+
const base_command_1 = require("../../base-command");
|
|
6
|
+
class StoreInstall extends base_command_1.BaseCommand {
|
|
7
|
+
static description = 'Install a published agent — you get your own copy of it';
|
|
8
|
+
static examples = [
|
|
9
|
+
'<%= config.bin %> store install agent_abc123',
|
|
10
|
+
'<%= config.bin %> store install agent_abc123 --release ar_def456',
|
|
11
|
+
'<%= config.bin %> store install agent_abc123 --json',
|
|
12
|
+
];
|
|
13
|
+
static args = {
|
|
14
|
+
agentId: core_1.Args.string({ description: 'The store agent to install', required: true }),
|
|
15
|
+
};
|
|
16
|
+
static flags = {
|
|
17
|
+
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
18
|
+
release: core_1.Flags.string({ description: 'Install a specific release (defaults to the latest)' }),
|
|
19
|
+
space: core_1.Flags.string({ description: 'Space to install into' }),
|
|
20
|
+
'include-bootstrap': core_1.Flags.boolean({
|
|
21
|
+
description: "Include the publisher's shared bootstrap files, if they published any",
|
|
22
|
+
}),
|
|
23
|
+
'include-memory': core_1.Flags.boolean({
|
|
24
|
+
description: "Include the publisher's shared memories, if they published any",
|
|
25
|
+
}),
|
|
26
|
+
};
|
|
27
|
+
async run() {
|
|
28
|
+
this.requireAuth();
|
|
29
|
+
const { args, flags } = await this.parse(StoreInstall);
|
|
30
|
+
let response;
|
|
31
|
+
try {
|
|
32
|
+
response = await data_provider_1.dataService.installStoreAgent({
|
|
33
|
+
agentId: args.agentId,
|
|
34
|
+
...(flags.release ? { releaseId: flags.release } : {}),
|
|
35
|
+
...(flags.space ? { spaceId: flags.space } : {}),
|
|
36
|
+
...(flags['include-bootstrap'] ? { includeBootstrap: true } : {}),
|
|
37
|
+
...(flags['include-memory'] ? { includeMemory: true } : {}),
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
this.handleApiError(err);
|
|
42
|
+
}
|
|
43
|
+
if (flags.json) {
|
|
44
|
+
this.log(JSON.stringify(response, null, 2));
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const installedId = response?.installedAgentId;
|
|
48
|
+
this.log(`Installed as ${installedId ?? '-'}.`);
|
|
49
|
+
// The thing worth saying once: this is a COPY, and it is yours. Edits you
|
|
50
|
+
// make to it survive the publisher's future updates.
|
|
51
|
+
this.log('This is your own copy. Edits you make to it are kept when the publisher ships an update.');
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
exports.default = StoreInstall;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base-command';
|
|
2
|
+
/**
|
|
3
|
+
* What versions of a published agent exist.
|
|
4
|
+
*
|
|
5
|
+
* Operator-relevant rather than store chrome: pinning an install to a specific
|
|
6
|
+
* release, or reading what changed before taking an update, both need this and
|
|
7
|
+
* neither is a browsing activity.
|
|
8
|
+
*/
|
|
9
|
+
export default class StoreReleases extends BaseCommand {
|
|
10
|
+
static description: string;
|
|
11
|
+
static examples: string[];
|
|
12
|
+
static args: {
|
|
13
|
+
agentId: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
14
|
+
};
|
|
15
|
+
static flags: {
|
|
16
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
17
|
+
};
|
|
18
|
+
run(): Promise<void>;
|
|
19
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
5
|
+
const base_command_1 = require("../../base-command");
|
|
6
|
+
const format_1 = require("../../lib/format");
|
|
7
|
+
/**
|
|
8
|
+
* What versions of a published agent exist.
|
|
9
|
+
*
|
|
10
|
+
* Operator-relevant rather than store chrome: pinning an install to a specific
|
|
11
|
+
* release, or reading what changed before taking an update, both need this and
|
|
12
|
+
* neither is a browsing activity.
|
|
13
|
+
*/
|
|
14
|
+
class StoreReleases extends base_command_1.BaseCommand {
|
|
15
|
+
static description = 'List the published releases of a store agent';
|
|
16
|
+
static examples = [
|
|
17
|
+
'<%= config.bin %> store releases agent_abc123',
|
|
18
|
+
'<%= config.bin %> store releases agent_abc123 --json',
|
|
19
|
+
];
|
|
20
|
+
static args = {
|
|
21
|
+
agentId: core_1.Args.string({ description: 'The store agent', required: true }),
|
|
22
|
+
};
|
|
23
|
+
static flags = {
|
|
24
|
+
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
25
|
+
};
|
|
26
|
+
async run() {
|
|
27
|
+
this.requireAuth();
|
|
28
|
+
const { args, flags } = await this.parse(StoreReleases);
|
|
29
|
+
let response;
|
|
30
|
+
try {
|
|
31
|
+
response = await data_provider_1.dataService.getStoreAgentReleases(args.agentId);
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
this.handleApiError(err);
|
|
35
|
+
}
|
|
36
|
+
if (flags.json) {
|
|
37
|
+
this.log(JSON.stringify(response, null, 2));
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const items = response?.data ?? [];
|
|
41
|
+
if (items.length === 0) {
|
|
42
|
+
this.log('No published releases.');
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
(0, format_1.renderTable)(items.map((r) => ({
|
|
46
|
+
id: String(r.id ?? '-'),
|
|
47
|
+
version: String(r.versionLabel ?? '-'),
|
|
48
|
+
price: r.price ? String(r.price) : 'free',
|
|
49
|
+
published: r.publishedAt ? String(r.publishedAt).slice(0, 10) : '-',
|
|
50
|
+
changelog: String(r.changelog ?? ''),
|
|
51
|
+
})), [
|
|
52
|
+
{ key: 'id', header: 'RELEASE ID' },
|
|
53
|
+
{ key: 'version', header: 'VERSION' },
|
|
54
|
+
{ key: 'price', header: 'PRICE' },
|
|
55
|
+
{ key: 'published', header: 'PUBLISHED' },
|
|
56
|
+
{ key: 'changelog', header: 'CHANGELOG', maxWidth: 44 },
|
|
57
|
+
], (line) => this.log(line));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
exports.default = StoreReleases;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base-command';
|
|
2
|
+
export default class StoreUpdate extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static args: {
|
|
6
|
+
agentId: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
7
|
+
};
|
|
8
|
+
static flags: {
|
|
9
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
10
|
+
release: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
11
|
+
installed: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
12
|
+
strategy: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
13
|
+
};
|
|
14
|
+
run(): Promise<void>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
5
|
+
const base_command_1 = require("../../base-command");
|
|
6
|
+
class StoreUpdate extends base_command_1.BaseCommand {
|
|
7
|
+
static description = 'Update an installed agent to a published release, keeping the edits you made to your copy';
|
|
8
|
+
static examples = [
|
|
9
|
+
'<%= config.bin %> store update agent_abc123',
|
|
10
|
+
'<%= config.bin %> store update agent_abc123 --release ar_def456',
|
|
11
|
+
'<%= config.bin %> store update agent_abc123 --strategy replace',
|
|
12
|
+
];
|
|
13
|
+
static args = {
|
|
14
|
+
agentId: core_1.Args.string({ description: 'The store agent you installed', required: true }),
|
|
15
|
+
};
|
|
16
|
+
static flags = {
|
|
17
|
+
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
18
|
+
release: core_1.Flags.string({ description: 'Target release id (defaults to the latest)' }),
|
|
19
|
+
installed: core_1.Flags.string({ description: 'Your installed copy (defaults to the purchase)' }),
|
|
20
|
+
strategy: core_1.Flags.string({
|
|
21
|
+
description: 'merge (default) keeps your edits and refuses on a conflict; replace takes the publisher version',
|
|
22
|
+
options: ['merge', 'replace'],
|
|
23
|
+
}),
|
|
24
|
+
};
|
|
25
|
+
async run() {
|
|
26
|
+
this.requireAuth();
|
|
27
|
+
const { args, flags } = await this.parse(StoreUpdate);
|
|
28
|
+
let response;
|
|
29
|
+
try {
|
|
30
|
+
response = await data_provider_1.dataService.updateInstalledStoreAgent({
|
|
31
|
+
agentId: args.agentId,
|
|
32
|
+
...(flags.installed ? { installedAgentId: flags.installed } : {}),
|
|
33
|
+
...(flags.release ? { targetReleaseId: flags.release } : {}),
|
|
34
|
+
...(flags.strategy ? { strategy: flags.strategy } : {}),
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
// A conflict is not a failure of the update; it is the update asking a
|
|
39
|
+
// question. Print the fields, and the one command that answers it.
|
|
40
|
+
const conflict = err;
|
|
41
|
+
const body = conflict?.body;
|
|
42
|
+
if (body?.code === 'UPDATE_CONFLICT' || body?.code === 'UPDATE_NO_BASE') {
|
|
43
|
+
this.log(body.error ?? 'This update needs a decision.');
|
|
44
|
+
if (body.conflicts?.length) {
|
|
45
|
+
this.log(`Both of you changed: ${body.conflicts.join(', ')}`);
|
|
46
|
+
}
|
|
47
|
+
this.log('');
|
|
48
|
+
this.log(`Take the publisher version: skrr store update ${args.agentId} --strategy replace`);
|
|
49
|
+
this.error('Update not applied.', { exit: 1 });
|
|
50
|
+
}
|
|
51
|
+
this.handleApiError(err);
|
|
52
|
+
}
|
|
53
|
+
if (flags.json) {
|
|
54
|
+
this.log(JSON.stringify(response, null, 2));
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const merge = response
|
|
58
|
+
?.merge;
|
|
59
|
+
this.log(`Updated to ${response?.targetVersionLabel ?? response?.targetReleaseId ?? ''}.`);
|
|
60
|
+
if (merge?.kept?.length) {
|
|
61
|
+
// The promise that makes an automatic update worth having, made visible.
|
|
62
|
+
this.log(`Kept your changes to: ${merge.kept.join(', ')}`);
|
|
63
|
+
}
|
|
64
|
+
if (merge?.taken?.length) {
|
|
65
|
+
this.log(`Applied: ${merge.taken.join(', ')}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
exports.default = StoreUpdate;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base-command';
|
|
2
|
+
/**
|
|
3
|
+
* What is waiting on you across everything you installed.
|
|
4
|
+
*
|
|
5
|
+
* Three states, kept apart because they ask for three different things:
|
|
6
|
+
*
|
|
7
|
+
* ready a same-major release that will apply cleanly
|
|
8
|
+
* review one that could not be applied on its own — you and the publisher
|
|
9
|
+
* both changed the same field, or the version your copy came from is
|
|
10
|
+
* unknown so your edits cannot be told apart from theirs
|
|
11
|
+
* buy a new major, which under the channel decision is a fresh purchase
|
|
12
|
+
* rather than an update
|
|
13
|
+
*
|
|
14
|
+
* Collapsing them into "update available" is what makes a person ignore the
|
|
15
|
+
* whole column: two of the three cannot be resolved by pressing update.
|
|
16
|
+
*/
|
|
17
|
+
export default class StoreUpdates extends BaseCommand {
|
|
18
|
+
static description: string;
|
|
19
|
+
static examples: string[];
|
|
20
|
+
static flags: {
|
|
21
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
22
|
+
};
|
|
23
|
+
run(): Promise<void>;
|
|
24
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
5
|
+
const base_command_1 = require("../../base-command");
|
|
6
|
+
const format_1 = require("../../lib/format");
|
|
7
|
+
/**
|
|
8
|
+
* What is waiting on you across everything you installed.
|
|
9
|
+
*
|
|
10
|
+
* Three states, kept apart because they ask for three different things:
|
|
11
|
+
*
|
|
12
|
+
* ready a same-major release that will apply cleanly
|
|
13
|
+
* review one that could not be applied on its own — you and the publisher
|
|
14
|
+
* both changed the same field, or the version your copy came from is
|
|
15
|
+
* unknown so your edits cannot be told apart from theirs
|
|
16
|
+
* buy a new major, which under the channel decision is a fresh purchase
|
|
17
|
+
* rather than an update
|
|
18
|
+
*
|
|
19
|
+
* Collapsing them into "update available" is what makes a person ignore the
|
|
20
|
+
* whole column: two of the three cannot be resolved by pressing update.
|
|
21
|
+
*/
|
|
22
|
+
class StoreUpdates extends base_command_1.BaseCommand {
|
|
23
|
+
static description = 'Show what is waiting across the agents you installed';
|
|
24
|
+
static examples = [
|
|
25
|
+
'<%= config.bin %> store updates',
|
|
26
|
+
'<%= config.bin %> store updates --json',
|
|
27
|
+
];
|
|
28
|
+
static flags = {
|
|
29
|
+
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
30
|
+
};
|
|
31
|
+
async run() {
|
|
32
|
+
this.requireAuth();
|
|
33
|
+
const { flags } = await this.parse(StoreUpdates);
|
|
34
|
+
let purchased;
|
|
35
|
+
try {
|
|
36
|
+
purchased = await data_provider_1.dataService.getPurchasedAgents();
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
this.handleApiError(err);
|
|
40
|
+
}
|
|
41
|
+
const items = purchased?.data ?? [];
|
|
42
|
+
const rows = [];
|
|
43
|
+
for (const item of items) {
|
|
44
|
+
const agentId = String(item.sourceAgentId ?? item.id ?? '');
|
|
45
|
+
if (!agentId) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
let status;
|
|
49
|
+
try {
|
|
50
|
+
status = await data_provider_1.dataService.getAgentPurchaseStatus(agentId);
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// One unreadable listing must not hide the rest. A row we could not
|
|
54
|
+
// read is reported as such rather than silently dropped.
|
|
55
|
+
rows.push({ agent: agentId, state: 'unreadable', have: '-', waiting: '-', detail: '' });
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
if (!status?.purchased) {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
const have = status.installedVersionLabel ?? '-';
|
|
62
|
+
if (status.pendingUpdate) {
|
|
63
|
+
rows.push({
|
|
64
|
+
agent: agentId,
|
|
65
|
+
state: 'review',
|
|
66
|
+
have,
|
|
67
|
+
waiting: status.pendingUpdate.versionLabel ?? '-',
|
|
68
|
+
detail: status.pendingUpdate.reason === 'conflict'
|
|
69
|
+
? `you both changed ${(status.pendingUpdate.conflicts ?? []).join(', ') || 'a field'}`
|
|
70
|
+
: 'the version your copy came from is unknown',
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
if (status.availableMajor) {
|
|
74
|
+
rows.push({
|
|
75
|
+
agent: agentId,
|
|
76
|
+
state: 'buy',
|
|
77
|
+
have,
|
|
78
|
+
waiting: status.availableMajor.versionLabel ?? '-',
|
|
79
|
+
detail: 'a new major is a separate purchase',
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
if (!status.pendingUpdate && status.updateAvailable && status.updateKind === 'minor') {
|
|
83
|
+
rows.push({
|
|
84
|
+
agent: agentId,
|
|
85
|
+
state: 'ready',
|
|
86
|
+
have,
|
|
87
|
+
waiting: status.latestVersionLabel ?? '-',
|
|
88
|
+
detail: 'applies cleanly',
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (flags.json) {
|
|
93
|
+
this.log(JSON.stringify({ object: 'list', data: rows }, null, 2));
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (rows.length === 0) {
|
|
97
|
+
this.log('Nothing waiting.');
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
(0, format_1.renderTable)(rows, [
|
|
101
|
+
{ key: 'agent', header: 'AGENT' },
|
|
102
|
+
{ key: 'state', header: 'STATE' },
|
|
103
|
+
{ key: 'have', header: 'YOU HAVE' },
|
|
104
|
+
{ key: 'waiting', header: 'WAITING' },
|
|
105
|
+
{ key: 'detail', header: 'WHY', maxWidth: 46 },
|
|
106
|
+
], (line) => this.log(line));
|
|
107
|
+
this.log('');
|
|
108
|
+
this.log('ready → skrr store update <agent>');
|
|
109
|
+
this.log('review → skrr store update <agent> --strategy replace (takes the publisher version)');
|
|
110
|
+
this.log('buy → skrr store install <agent>');
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
exports.default = StoreUpdates;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base-command';
|
|
2
|
+
export default class SubscriptionsCancel extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static args: {
|
|
6
|
+
agentId: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
7
|
+
};
|
|
8
|
+
static flags: {
|
|
9
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
10
|
+
reason: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
11
|
+
'expected-version': import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
12
|
+
};
|
|
13
|
+
run(): Promise<void>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
5
|
+
const base_command_1 = require("../../base-command");
|
|
6
|
+
class SubscriptionsCancel extends base_command_1.BaseCommand {
|
|
7
|
+
static description = 'End a service subscription. Stops future work; keeps everything already delivered';
|
|
8
|
+
static examples = [
|
|
9
|
+
'<%= config.bin %> subscriptions cancel agent_abc123',
|
|
10
|
+
'<%= config.bin %> subscriptions cancel agent_abc123 --reason "no longer needed"',
|
|
11
|
+
'<%= config.bin %> subscriptions cancel agent_abc123 --expected-version 3',
|
|
12
|
+
];
|
|
13
|
+
static args = {
|
|
14
|
+
agentId: core_1.Args.string({ description: 'The service to unsubscribe from', required: true }),
|
|
15
|
+
};
|
|
16
|
+
static flags = {
|
|
17
|
+
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
18
|
+
reason: core_1.Flags.string({ description: 'Why it is being cancelled (recorded on the lease)' }),
|
|
19
|
+
'expected-version': core_1.Flags.integer({
|
|
20
|
+
description: 'Fence — refuse if the lease has changed since you read it. Pass it when a program read the subscription first.',
|
|
21
|
+
}),
|
|
22
|
+
};
|
|
23
|
+
async run() {
|
|
24
|
+
this.requireAuth();
|
|
25
|
+
const { args, flags } = await this.parse(SubscriptionsCancel);
|
|
26
|
+
let response;
|
|
27
|
+
try {
|
|
28
|
+
response = await data_provider_1.dataService.unsubscribeFromStoreAgent(args.agentId, {
|
|
29
|
+
...(flags.reason ? { reason: flags.reason } : {}),
|
|
30
|
+
...(flags['expected-version'] !== undefined
|
|
31
|
+
? { expectedVersion: flags['expected-version'] }
|
|
32
|
+
: {}),
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
this.handleApiError(err);
|
|
37
|
+
}
|
|
38
|
+
if (flags.json) {
|
|
39
|
+
this.log(JSON.stringify(response, null, 2));
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
this.log(`Ended subscription ${response?.entitlementId} (${response?.status}).`);
|
|
43
|
+
// Said plainly, because it is the thing people fear about cancelling.
|
|
44
|
+
this.log(response?.retained ?? '');
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
exports.default = SubscriptionsCancel;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base-command';
|
|
2
|
+
/**
|
|
3
|
+
* Has this service actually delivered?
|
|
4
|
+
*
|
|
5
|
+
* The question every recurring charge has to answer, and the reason a
|
|
6
|
+
* subscription is modelled as a Commitment rather than a billing schedule.
|
|
7
|
+
*
|
|
8
|
+
* `unverified` — the work is done and nobody has looked — is counted as
|
|
9
|
+
* DELIVERED and reported separately as "waiting on you". It is not a failure:
|
|
10
|
+
* counting it as one would let a subscriber who stops confirming make a working
|
|
11
|
+
* service read as broken. It is surfaced anyway, because it is the subscriber's
|
|
12
|
+
* own evidence in a refund conversation.
|
|
13
|
+
*/
|
|
14
|
+
export default class SubscriptionsHealth extends BaseCommand {
|
|
15
|
+
static description: string;
|
|
16
|
+
static examples: string[];
|
|
17
|
+
static args: {
|
|
18
|
+
agentId: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
19
|
+
};
|
|
20
|
+
static flags: {
|
|
21
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
22
|
+
};
|
|
23
|
+
run(): Promise<void>;
|
|
24
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
5
|
+
const base_command_1 = require("../../base-command");
|
|
6
|
+
/**
|
|
7
|
+
* Has this service actually delivered?
|
|
8
|
+
*
|
|
9
|
+
* The question every recurring charge has to answer, and the reason a
|
|
10
|
+
* subscription is modelled as a Commitment rather than a billing schedule.
|
|
11
|
+
*
|
|
12
|
+
* `unverified` — the work is done and nobody has looked — is counted as
|
|
13
|
+
* DELIVERED and reported separately as "waiting on you". It is not a failure:
|
|
14
|
+
* counting it as one would let a subscriber who stops confirming make a working
|
|
15
|
+
* service read as broken. It is surfaced anyway, because it is the subscriber's
|
|
16
|
+
* own evidence in a refund conversation.
|
|
17
|
+
*/
|
|
18
|
+
class SubscriptionsHealth extends base_command_1.BaseCommand {
|
|
19
|
+
static description = 'Show what a service has actually delivered, and what awaits you';
|
|
20
|
+
static examples = [
|
|
21
|
+
'<%= config.bin %> subscriptions health agent_abc123',
|
|
22
|
+
'<%= config.bin %> subscriptions health agent_abc123 --json',
|
|
23
|
+
];
|
|
24
|
+
static args = {
|
|
25
|
+
agentId: core_1.Args.string({ description: 'The service to check', required: true }),
|
|
26
|
+
};
|
|
27
|
+
static flags = {
|
|
28
|
+
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
29
|
+
};
|
|
30
|
+
async run() {
|
|
31
|
+
this.requireAuth();
|
|
32
|
+
const { args, flags } = await this.parse(SubscriptionsHealth);
|
|
33
|
+
let response;
|
|
34
|
+
try {
|
|
35
|
+
response = await data_provider_1.dataService.getStoreAgentSubscriptionHealth(args.agentId);
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
this.handleApiError(err);
|
|
39
|
+
}
|
|
40
|
+
if (flags.json) {
|
|
41
|
+
this.log(JSON.stringify(response, null, 2));
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
this.log(response?.summary ?? '');
|
|
45
|
+
if (!response?.read) {
|
|
46
|
+
// "We could not look" and "nothing arrived" lead somewhere different, so
|
|
47
|
+
// they are never printed the same way.
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
this.log('');
|
|
51
|
+
this.log(`delivered ${response.delivered} / ${response.tasks}`);
|
|
52
|
+
this.log(`waiting on you ${response.awaitingConfirmation}`);
|
|
53
|
+
this.log(`still owed ${response.owed}`);
|
|
54
|
+
this.log(`blocked ${response.blocked}`);
|
|
55
|
+
if (response.noContract > 0) {
|
|
56
|
+
// "Declared nothing" and "contract met" are different things to know
|
|
57
|
+
// about what you are paying for.
|
|
58
|
+
this.log(`no stated contract ${response.noContract}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
exports.default = SubscriptionsHealth;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base-command';
|
|
2
|
+
export default class SubscriptionsList extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
7
|
+
};
|
|
8
|
+
run(): Promise<void>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
5
|
+
const base_command_1 = require("../../base-command");
|
|
6
|
+
const format_1 = require("../../lib/format");
|
|
7
|
+
class SubscriptionsList extends base_command_1.BaseCommand {
|
|
8
|
+
static description = 'List the service subscriptions you hold';
|
|
9
|
+
static examples = [
|
|
10
|
+
'<%= config.bin %> subscriptions list',
|
|
11
|
+
'<%= config.bin %> subscriptions list --json',
|
|
12
|
+
];
|
|
13
|
+
static flags = {
|
|
14
|
+
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
15
|
+
};
|
|
16
|
+
async run() {
|
|
17
|
+
this.requireAuth();
|
|
18
|
+
const { flags } = await this.parse(SubscriptionsList);
|
|
19
|
+
let response;
|
|
20
|
+
try {
|
|
21
|
+
response = await data_provider_1.dataService.getStoreSubscriptions();
|
|
22
|
+
}
|
|
23
|
+
catch (err) {
|
|
24
|
+
this.handleApiError(err);
|
|
25
|
+
}
|
|
26
|
+
if (flags.json) {
|
|
27
|
+
this.log(JSON.stringify(response, null, 2));
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const items = response?.data ?? [];
|
|
31
|
+
if (items.length === 0) {
|
|
32
|
+
this.log('No active subscriptions.');
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
(0, format_1.renderTable)(items.map((s) => ({
|
|
36
|
+
entitlementId: s.entitlementId,
|
|
37
|
+
service: s.sourceAgentId,
|
|
38
|
+
instance: s.instanceAgentId ?? '-',
|
|
39
|
+
// Who pays for the work is part of what you bought, so it is a column
|
|
40
|
+
// rather than something you have to ask for with --json.
|
|
41
|
+
pays: s.billingMode,
|
|
42
|
+
expires: s.expiresAt ? String(s.expiresAt).slice(0, 10) : 'no end date',
|
|
43
|
+
})), [
|
|
44
|
+
{ key: 'entitlementId', header: 'ENTITLEMENT' },
|
|
45
|
+
{ key: 'service', header: 'SERVICE' },
|
|
46
|
+
{ key: 'instance', header: 'YOUR INSTANCE' },
|
|
47
|
+
{ key: 'pays', header: 'COMPUTE PAID BY' },
|
|
48
|
+
{ key: 'expires', header: 'EXPIRES' },
|
|
49
|
+
], (line) => this.log(line));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
exports.default = SubscriptionsList;
|