@skrr-ai/cli 0.1.116 → 0.1.118
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 +21 -0
- package/dist/base-command.js +95 -8
- package/dist/commands/actions/browse.js +2 -1
- package/dist/commands/actions/install.d.ts +2 -0
- package/dist/commands/actions/install.js +67 -2
- package/dist/commands/actions/list.js +2 -1
- package/dist/commands/actions/show.js +2 -1
- package/dist/commands/commitments/create.d.ts +21 -2
- package/dist/commands/commitments/create.js +74 -4
- package/dist/commands/convos/recovery.js +12 -4
- package/dist/commands/followups/plans/list.js +1 -1
- package/dist/commands/guide.d.ts +21 -0
- package/dist/commands/guide.js +46 -0
- package/dist/commands/instructions/guide.js +34 -52
- package/dist/commands/memory/maintain.js +1 -1
- package/dist/commands/skills/browse.js +2 -1
- package/dist/commands/skills/details.js +4 -2
- package/dist/commands/skills/featured.js +2 -1
- package/dist/commands/skills/install.d.ts +2 -0
- package/dist/commands/skills/install.js +62 -3
- package/dist/commands/skills/search.js +2 -1
- package/dist/commands/slack/send-as-agent.js +3 -3
- package/dist/commands/spaces/create.js +8 -2
- package/dist/commands/spaces/guide.d.ts +21 -0
- package/dist/commands/spaces/guide.js +40 -0
- package/dist/commands/spaces/index.d.ts +0 -1
- package/dist/commands/spaces/index.js +1 -6
- package/dist/commands/store/acquisitions/list.js +2 -1
- package/dist/commands/store/acquisitions/show.js +2 -1
- package/dist/commands/store/browse.js +4 -2
- package/dist/commands/store/install.d.ts +1 -0
- package/dist/commands/store/install.js +26 -2
- package/dist/commands/store/releases.js +4 -2
- package/dist/commands/store/show.js +3 -2
- package/dist/commands/store/tip.js +2 -2
- package/dist/commands/tasks/checkout.js +2 -3
- package/dist/commands/tasks/comments/add.js +3 -5
- package/dist/commands/tasks/complete.js +2 -3
- package/dist/commands/tasks/deliverable/add.d.ts +1 -1
- package/dist/commands/tasks/deliverable/add.js +4 -7
- package/dist/commands/tasks/expectations/assess.js +2 -2
- package/dist/commands/tasks/guide.d.ts +8 -0
- package/dist/commands/tasks/guide.js +23 -10
- package/dist/commands/tasks/report.js +9 -5
- package/dist/commands/tasks/resource/add.js +2 -3
- package/dist/commands/tasks/result/submit.js +2 -3
- package/dist/commands/tasks/resume/save.js +2 -3
- package/dist/commands/tasks/review.js +2 -3
- package/dist/commands/tasks/triage.js +2 -1
- package/dist/commands/tasks/updates/add.js +2 -3
- package/dist/generated/agent-guides.json +8312 -0
- package/dist/generated/managed-instruction-guides.json +1 -1
- package/dist/help.js +4 -3
- package/dist/hooks/command-not-found.js +1 -1
- package/dist/lib/action-listings.js +2 -1
- package/dist/lib/agent-guide-reference-gate.d.ts +28 -0
- package/dist/lib/agent-guide-reference-gate.js +186 -0
- package/dist/lib/agent-guides.d.ts +51 -0
- package/dist/lib/agent-guides.js +170 -0
- package/dist/lib/api-fetch.js +3 -1
- package/dist/lib/command-miss.d.ts +13 -2
- package/dist/lib/command-miss.js +134 -8
- package/dist/lib/guide-pointer.d.ts +15 -0
- package/dist/lib/guide-pointer.js +51 -0
- package/dist/lib/lookbackPlans.d.ts +3 -1
- package/dist/lib/lookbackPlans.js +9 -0
- package/dist/lib/node-adapter.js +4 -3
- package/dist/lib/outbox.d.ts +0 -14
- package/dist/lib/outbox.js +0 -21
- package/dist/lib/roles.d.ts +1 -1
- package/dist/lib/store-listing.d.ts +6 -1
- package/dist/lib/store-listing.js +6 -1
- package/dist/lib/task-admission.js +27 -5
- package/dist/lib/task-batch.d.ts +10 -7
- package/dist/lib/task-batch.js +5 -20
- package/dist/lib/task-operations.d.ts +8 -20
- package/dist/lib/task-operations.js +9 -94
- package/dist/lib/task-preflight.js +70 -33
- package/dist/lib/task-runtime-headers.d.ts +11 -0
- package/dist/lib/task-runtime-headers.js +73 -0
- package/dist/lib/task-write-attribution.js +1 -1
- package/dist/lib/usage-discovery.d.ts +4 -0
- package/dist/lib/usage-discovery.js +5 -0
- package/dist/lib/usd-micros.d.ts +27 -0
- package/dist/lib/usd-micros.js +67 -2
- package/dist/lib/voice-call-intent.js +3 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/harnessPermissionControls.d.ts +17 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/harnessPermissionControls.js +35 -2
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/harnessPermissionControls.d.ts +17 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/harnessPermissionControls.js +44 -0
- package/dist/node_modules/@skrr-ai/auth-core/package.json +1 -1
- package/dist/node_modules/@skrr-ai/data-provider/index.js +11927 -11678
- package/oclif.manifest.json +251 -14
- package/package.json +4 -2
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
export default class Guide extends Command {
|
|
3
|
+
static baseFlags: {
|
|
4
|
+
bare: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
5
|
+
token: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
6
|
+
workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
raw: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
9
|
+
};
|
|
10
|
+
static description: string;
|
|
11
|
+
static args: {
|
|
12
|
+
id: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
13
|
+
section: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
14
|
+
};
|
|
15
|
+
static flags: {
|
|
16
|
+
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
17
|
+
offline: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
18
|
+
};
|
|
19
|
+
static examples: string[];
|
|
20
|
+
run(): Promise<void>;
|
|
21
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
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 agent_guides_1 = require("../lib/agent-guides");
|
|
7
|
+
// Documentation stays available when a daemon-issued Agent credential is
|
|
8
|
+
// unavailable. Do not run BaseCommand's mandatory credential initialization.
|
|
9
|
+
class Guide extends core_1.Command {
|
|
10
|
+
static baseFlags = base_command_1.BaseCommand.baseFlags;
|
|
11
|
+
static description = 'Read Skrr operation guides on demand';
|
|
12
|
+
static args = {
|
|
13
|
+
id: core_1.Args.string({ description: 'Guide id', ignoreStdin: true }),
|
|
14
|
+
section: core_1.Args.string({ description: 'Section id', ignoreStdin: true }),
|
|
15
|
+
};
|
|
16
|
+
static flags = {
|
|
17
|
+
json: core_1.Flags.boolean({ description: 'Output the guide and source provenance as JSON' }),
|
|
18
|
+
offline: core_1.Flags.boolean({
|
|
19
|
+
description: 'Read the bundled release guides without checking credentials or the server',
|
|
20
|
+
}),
|
|
21
|
+
};
|
|
22
|
+
static examples = [
|
|
23
|
+
'<%= config.bin %> guide',
|
|
24
|
+
'<%= config.bin %> guide tasks',
|
|
25
|
+
'<%= config.bin %> guide tasks updates --offline',
|
|
26
|
+
];
|
|
27
|
+
async run() {
|
|
28
|
+
const { args, flags } = await this.parse(Guide);
|
|
29
|
+
const request = {
|
|
30
|
+
...(args.id ? { id: args.id } : {}),
|
|
31
|
+
...(args.section ? { section: args.section } : {}),
|
|
32
|
+
};
|
|
33
|
+
const read = await (0, agent_guides_1.readAgentGuide)(request, flags);
|
|
34
|
+
if (!read.found)
|
|
35
|
+
return (0, agent_guides_1.writeAgentGuideMiss)(this, read.miss, flags.json);
|
|
36
|
+
if (flags.json) {
|
|
37
|
+
process.stdout.write((0, agent_guides_1.agentGuideJson)(read));
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const notice = (0, agent_guides_1.agentGuideFallbackNotice)(read);
|
|
41
|
+
if (notice)
|
|
42
|
+
process.stderr.write(`${notice}\n`);
|
|
43
|
+
process.stdout.write((0, data_provider_1.renderAgentGuideText)(read.response));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
exports.default = Guide;
|
|
@@ -4,19 +4,22 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const core_1 = require("@oclif/core");
|
|
7
|
+
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
7
8
|
const node_crypto_1 = require("node:crypto");
|
|
8
9
|
const base_command_1 = require("../../base-command");
|
|
9
10
|
const managed_instruction_guides_json_1 = __importDefault(require("../../generated/managed-instruction-guides.json"));
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
const agent_guides_1 = require("../../lib/agent-guides");
|
|
12
|
+
// The installed v20 instructions still name this command; the guide body they
|
|
13
|
+
// ask for now lives in the tasks card. The card also dropped the membership
|
|
14
|
+
// and scheduling rules, so one trailing line keeps an agent pointed at where
|
|
15
|
+
// those went.
|
|
16
|
+
const TASKS_GUIDE_POINTER = 'Membership and scheduling now live in `skrr guide spaces access` for Space membership ' +
|
|
17
|
+
'and `skrr guide tasks followups` for follow-ups and scheduling.';
|
|
15
18
|
// Documentation stays available when a daemon-issued Agent credential is
|
|
16
19
|
// unavailable. Do not run BaseCommand's mandatory credential initialization.
|
|
17
20
|
class InstructionsGuide extends core_1.Command {
|
|
18
21
|
static baseFlags = base_command_1.BaseCommand.baseFlags;
|
|
19
|
-
static description = '
|
|
22
|
+
static description = 'Kept for installed instructions — prints the tasks guide. `skrr guide` reads every guide.';
|
|
20
23
|
static args = {
|
|
21
24
|
name: core_1.Args.string({
|
|
22
25
|
description: 'Guide to read',
|
|
@@ -37,55 +40,34 @@ class InstructionsGuide extends core_1.Command {
|
|
|
37
40
|
];
|
|
38
41
|
async run() {
|
|
39
42
|
const { flags } = await this.parse(InstructionsGuide);
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const credential = autonomous ??
|
|
50
|
-
(await (0, credential_resolver_1.resolveCredential)({
|
|
51
|
-
flagToken: flags.token,
|
|
52
|
-
bareMode: flags.bare,
|
|
53
|
-
allowUnreadableStoredCredential: true,
|
|
54
|
-
}));
|
|
55
|
-
if (credential.token) {
|
|
56
|
-
reason = 'server-unavailable';
|
|
57
|
-
const response = await (0, api_fetch_1.apiFetch)('/api/instructions/presets/oversky-task-management/guide', { credential, signal: AbortSignal.timeout(3_000) });
|
|
58
|
-
if ((0, node_crypto_1.createHash)('sha256').update(response.body).digest('hex') !== response.hash) {
|
|
59
|
-
// An integrity failure, not a network failure: the server
|
|
60
|
-
// answered, but the body it sent does not match its own hash.
|
|
61
|
-
// Give it its own reason before the catch below can flatten it
|
|
62
|
-
// into 'server-unavailable', which describes the opposite world.
|
|
63
|
-
reason = 'server-hash-mismatch';
|
|
64
|
-
throw new Error('The server guide hash does not match its body.');
|
|
65
|
-
}
|
|
66
|
-
guide = response;
|
|
67
|
-
source = 'server';
|
|
68
|
-
reason = undefined;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
catch {
|
|
72
|
-
// A missing/unreadable auth envelope or delegated daemon cannot make
|
|
73
|
-
// a read-only local guide unavailable, and must never emit auth JSON.
|
|
74
|
-
reason ??= 'server-unavailable';
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
if (flags.json)
|
|
43
|
+
const read = await (0, agent_guides_1.readAgentGuide)({ id: 'tasks' }, flags);
|
|
44
|
+
if (!read.found)
|
|
45
|
+
return (0, agent_guides_1.writeAgentGuideMiss)(this, read.miss, flags.json);
|
|
46
|
+
const body = (0, data_provider_1.renderAgentGuideText)(read.response);
|
|
47
|
+
if (flags.json) {
|
|
48
|
+
// The ManagedInstructionGuide shape is the contract older callers read:
|
|
49
|
+
// keep its keys, but `body` is the tasks card text and `hash` its sha256,
|
|
50
|
+
// so a consumer that verifies hash against body still succeeds.
|
|
51
|
+
const preset = managed_instruction_guides_json_1.default['oversky-task-management'];
|
|
78
52
|
this.log(JSON.stringify({
|
|
79
|
-
|
|
80
|
-
|
|
53
|
+
key: preset.key,
|
|
54
|
+
name: preset.name,
|
|
55
|
+
templateVersion: preset.templateVersion,
|
|
56
|
+
body,
|
|
57
|
+
hash: (0, node_crypto_1.createHash)('sha256').update(body, 'utf8').digest('hex'),
|
|
58
|
+
redirectedTo: 'tasks',
|
|
59
|
+
provenance: {
|
|
60
|
+
source: read.source,
|
|
61
|
+
fallback: read.source === 'bundled',
|
|
62
|
+
...(read.reason ? { reason: read.reason } : {}),
|
|
63
|
+
},
|
|
81
64
|
}, null, 2));
|
|
82
|
-
|
|
83
|
-
if (source === 'bundled')
|
|
84
|
-
this.logToStderr(reason === 'server-hash-mismatch'
|
|
85
|
-
? `The server guide’s body does not match its hash; using the CLI’s bundled task-management guide (template v${guide.templateVersion}).`
|
|
86
|
-
: `Using the CLI’s bundled task-management guide (template v${guide.templateVersion}).`);
|
|
87
|
-
this.log(guide.body);
|
|
65
|
+
return;
|
|
88
66
|
}
|
|
67
|
+
const notice = (0, agent_guides_1.agentGuideFallbackNotice)(read);
|
|
68
|
+
if (notice)
|
|
69
|
+
process.stderr.write(`${notice}\n`);
|
|
70
|
+
this.log(`${body}\n${TASKS_GUIDE_POINTER}`);
|
|
89
71
|
}
|
|
90
72
|
}
|
|
91
73
|
exports.default = InstructionsGuide;
|
|
@@ -16,7 +16,7 @@ class MemoryMaintain extends base_command_1.BaseCommand {
|
|
|
16
16
|
static description = 'Apply an auditable canonical memory maintenance operation';
|
|
17
17
|
static examples = [
|
|
18
18
|
'<%= config.bin %> memory maintain remember \'{"path":"/notes","claim":"Ship notes on Fridays."}\' --agent agent_abc123',
|
|
19
|
-
'<%= config.bin %> memory maintain archive \'{"
|
|
19
|
+
'<%= config.bin %> memory maintain archive \'{"path":"/notes/old-note"}\' --agent agent_abc123',
|
|
20
20
|
];
|
|
21
21
|
static args = {
|
|
22
22
|
operation: core_1.Args.string({ required: true, options: [...OPERATIONS], ignoreStdin: true }),
|
|
@@ -6,6 +6,7 @@ const core_1 = require("@oclif/core");
|
|
|
6
6
|
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
7
7
|
const base_command_1 = require("../../base-command");
|
|
8
8
|
const format_1 = require("../../lib/format");
|
|
9
|
+
const usd_micros_1 = require("../../lib/usd-micros");
|
|
9
10
|
function skillBrowseDescription(skill) {
|
|
10
11
|
const description = String(skill.description ?? '').trim();
|
|
11
12
|
if (description && description !== '>' && description !== '|')
|
|
@@ -64,7 +65,7 @@ class SkillsBrowse extends base_command_1.BaseCommand {
|
|
|
64
65
|
this.handleApiError(err);
|
|
65
66
|
}
|
|
66
67
|
if (flags.json) {
|
|
67
|
-
this.log(JSON.stringify(response, null, 2));
|
|
68
|
+
this.log(JSON.stringify((0, usd_micros_1.withUsdPrices)(response), null, 2));
|
|
68
69
|
return;
|
|
69
70
|
}
|
|
70
71
|
const r = response;
|
|
@@ -4,6 +4,8 @@ const core_1 = require("@oclif/core");
|
|
|
4
4
|
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
5
5
|
const base_command_1 = require("../../base-command");
|
|
6
6
|
const local_skills_1 = require("../../lib/local-skills");
|
|
7
|
+
const store_listing_1 = require("../../lib/store-listing");
|
|
8
|
+
const usd_micros_1 = require("../../lib/usd-micros");
|
|
7
9
|
class SkillsDetails extends base_command_1.BaseCommand {
|
|
8
10
|
static description = 'Show full details for a skill';
|
|
9
11
|
static examples = [
|
|
@@ -49,7 +51,7 @@ class SkillsDetails extends base_command_1.BaseCommand {
|
|
|
49
51
|
await this.failOnStoreMiss(err, args.id);
|
|
50
52
|
}
|
|
51
53
|
if (flags.json) {
|
|
52
|
-
this.log(JSON.stringify(skill, null, 2));
|
|
54
|
+
this.log(JSON.stringify((0, usd_micros_1.withUsdPrices)(skill), null, 2));
|
|
53
55
|
return;
|
|
54
56
|
}
|
|
55
57
|
const s = skill;
|
|
@@ -59,7 +61,7 @@ class SkillsDetails extends base_command_1.BaseCommand {
|
|
|
59
61
|
this.log(`Author: ${s.authorName ?? s.author ?? '-'}`);
|
|
60
62
|
this.log(`Rating: ${s.rating != null ? s.rating.toFixed(1) : '-'} (${s.ratingCount ?? 0} reviews)`);
|
|
61
63
|
this.log(`Installs: ${s.installCount ?? 0}`);
|
|
62
|
-
this.log(`Price: ${s.price ?
|
|
64
|
+
this.log(`Price: ${(0, store_listing_1.formatListingPrice)(typeof s.price === 'number' ? s.price : null)}`);
|
|
63
65
|
this.log(`Public: ${s.isPublic ? 'yes' : 'no'}`);
|
|
64
66
|
this.log(`Created: ${s.createdAt ?? '-'}`);
|
|
65
67
|
if (s.description) {
|
|
@@ -5,6 +5,7 @@ const core_1 = require("@oclif/core");
|
|
|
5
5
|
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
6
6
|
const base_command_1 = require("../../base-command");
|
|
7
7
|
const format_1 = require("../../lib/format");
|
|
8
|
+
const usd_micros_1 = require("../../lib/usd-micros");
|
|
8
9
|
const browse_1 = require("./browse");
|
|
9
10
|
function featuredSkillIndex(response, limit) {
|
|
10
11
|
const envelope = response;
|
|
@@ -41,7 +42,7 @@ class SkillsFeatured extends base_command_1.BaseCommand {
|
|
|
41
42
|
}
|
|
42
43
|
const index = featuredSkillIndex(response, flags.limit);
|
|
43
44
|
if (flags.json)
|
|
44
|
-
return void this.log(JSON.stringify(index, null, 2));
|
|
45
|
+
return void this.log(JSON.stringify((0, usd_micros_1.withUsdPrices)(index), null, 2));
|
|
45
46
|
const items = index.data;
|
|
46
47
|
if (items.length === 0) {
|
|
47
48
|
this.log('No featured skills.');
|
|
@@ -9,6 +9,8 @@ export default class SkillsInstall extends BaseCommand {
|
|
|
9
9
|
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
10
10
|
agent: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
11
|
service: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
yes: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
13
|
+
'expected-price': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
14
|
};
|
|
13
15
|
/** A store 404 for a name that may be a skill on the caller's machine. */
|
|
14
16
|
private failOnStoreMiss;
|
|
@@ -3,12 +3,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const core_1 = require("@oclif/core");
|
|
4
4
|
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
5
5
|
const base_command_1 = require("../../base-command");
|
|
6
|
+
const prompt_1 = require("../../lib/prompt");
|
|
6
7
|
const local_skills_1 = require("../../lib/local-skills");
|
|
8
|
+
const usd_micros_1 = require("../../lib/usd-micros");
|
|
7
9
|
class SkillsInstall extends base_command_1.BaseCommand {
|
|
8
|
-
static description = 'Install a skill from the store to a service (agent)';
|
|
10
|
+
static description = 'Install a skill from the store to a service (agent). A paid skill shows its price and asks you to confirm first.';
|
|
9
11
|
static examples = [
|
|
10
12
|
'<%= config.bin %> skills install <skill-id>',
|
|
11
13
|
'<%= config.bin %> skills install <skill-id> --agent <agent-id>',
|
|
14
|
+
'<%= config.bin %> skills install <skill-id> --yes',
|
|
12
15
|
'<%= config.bin %> skills install <skill-id> --json',
|
|
13
16
|
];
|
|
14
17
|
static args = {
|
|
@@ -25,6 +28,14 @@ class SkillsInstall extends base_command_1.BaseCommand {
|
|
|
25
28
|
description: '[DEPRECATED] Use --agent. Same meaning, kept for script compatibility.',
|
|
26
29
|
hidden: true,
|
|
27
30
|
}),
|
|
31
|
+
yes: core_1.Flags.boolean({
|
|
32
|
+
char: 'y',
|
|
33
|
+
description: 'Confirm a paid install without prompting. The price is still printed.',
|
|
34
|
+
}),
|
|
35
|
+
'expected-price': core_1.Flags.string({
|
|
36
|
+
description: 'Refuse unless the install would charge exactly this USD amount (e.g. 4 or 2.50; 0 pins free). ' +
|
|
37
|
+
'Use it to pin the price the person named, not just the one read now.',
|
|
38
|
+
}),
|
|
28
39
|
};
|
|
29
40
|
/** A store 404 for a name that may be a skill on the caller's machine. */
|
|
30
41
|
async failOnStoreMiss(err, id) {
|
|
@@ -56,18 +67,66 @@ class SkillsInstall extends base_command_1.BaseCommand {
|
|
|
56
67
|
retryable: false,
|
|
57
68
|
});
|
|
58
69
|
}
|
|
70
|
+
// What installing would charge NOW, read before the install sends it.
|
|
71
|
+
// A paid skill shows its price and asks first; the install then pins what
|
|
72
|
+
// was shown, so a listing whose price moved in between is refused rather
|
|
73
|
+
// than charged (OSK-18042 — same convention as `store install`, OSK-12240).
|
|
74
|
+
let listing;
|
|
75
|
+
try {
|
|
76
|
+
listing = await data_provider_1.dataService.getSkill(args.id);
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
return await this.failOnStoreMiss(err, args.id);
|
|
80
|
+
}
|
|
81
|
+
const charge = Number(listing.price) || 0;
|
|
82
|
+
// A caller-pinned price binds the install to what the PERSON named, not
|
|
83
|
+
// just to what this command read (OSK-18256 — same convention as
|
|
84
|
+
// `store install`).
|
|
85
|
+
const expectedMicros = (0, usd_micros_1.expectedPriceFlagMicros)(flags['expected-price']);
|
|
86
|
+
if (expectedMicros === null) {
|
|
87
|
+
this.error(`--expected-price must be a USD amount with at most 2 decimals, e.g. 4 or 2.50 (got "${flags['expected-price']}")`, { exit: 2 });
|
|
88
|
+
}
|
|
89
|
+
if (expectedMicros !== undefined && expectedMicros !== charge) {
|
|
90
|
+
this.failWithCliError({
|
|
91
|
+
message: (0, usd_micros_1.expectedPriceMismatchMessage)(expectedMicros, charge),
|
|
92
|
+
code: 'EXPECTED_PRICE_MISMATCH',
|
|
93
|
+
exit: 1,
|
|
94
|
+
retryable: false,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
if (charge > 0) {
|
|
98
|
+
const name = listing.displayName || listing.name || args.id;
|
|
99
|
+
// Printed before any prompt and even with --yes, so a scripted purchase
|
|
100
|
+
// still leaves the price it agreed to in its own output.
|
|
101
|
+
this.logToStderr(`${name} is a paid skill.`);
|
|
102
|
+
this.logToStderr(` Price: ${(0, data_provider_1.formatStoreAcquisitionPrice)(charge)} USD`);
|
|
103
|
+
if (listing.offerVersionId) {
|
|
104
|
+
this.logToStderr(` Offer: ${listing.offerVersionId}`);
|
|
105
|
+
}
|
|
106
|
+
const confirmed = await (0, prompt_1.confirmDestructive)(`Buy ${name} for ${(0, data_provider_1.formatStoreAcquisitionPrice)(charge)}?`, flags.yes).catch((err) => this.error(err.message, { exit: err.exit ?? 1 }));
|
|
107
|
+
if (!confirmed) {
|
|
108
|
+
this.log('Cancelled. Nothing was bought.');
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
59
112
|
let result;
|
|
60
113
|
try {
|
|
61
114
|
result = await data_provider_1.dataService.installSkill({
|
|
62
115
|
skillId: args.id,
|
|
63
116
|
targetAgentId,
|
|
117
|
+
// Pin what the person was shown: the charge always, the offer when
|
|
118
|
+
// there is one to charge under.
|
|
119
|
+
expectedPrice: charge,
|
|
120
|
+
...(charge > 0 && listing.offerVersionId
|
|
121
|
+
? { expectedOfferVersionId: listing.offerVersionId }
|
|
122
|
+
: {}),
|
|
64
123
|
});
|
|
65
124
|
}
|
|
66
125
|
catch (err) {
|
|
67
|
-
await this.failOnStoreMiss(err, args.id);
|
|
126
|
+
return await this.failOnStoreMiss(err, args.id);
|
|
68
127
|
}
|
|
69
128
|
if (flags.json) {
|
|
70
|
-
this.log(JSON.stringify(result, null, 2));
|
|
129
|
+
this.log(JSON.stringify((0, usd_micros_1.withUsdPrices)(result), null, 2));
|
|
71
130
|
return;
|
|
72
131
|
}
|
|
73
132
|
const r = result;
|
|
@@ -5,6 +5,7 @@ const data_provider_1 = require("@skrr-ai/data-provider");
|
|
|
5
5
|
const base_command_1 = require("../../base-command");
|
|
6
6
|
const format_1 = require("../../lib/format");
|
|
7
7
|
const search_query_1 = require("../../lib/search-query");
|
|
8
|
+
const usd_micros_1 = require("../../lib/usd-micros");
|
|
8
9
|
class SkillsSearch extends base_command_1.BaseCommand {
|
|
9
10
|
static description = 'Search skills in the skrr store by keyword (same as `search skills`)';
|
|
10
11
|
static examples = [
|
|
@@ -53,7 +54,7 @@ class SkillsSearch extends base_command_1.BaseCommand {
|
|
|
53
54
|
this.handleApiError(err);
|
|
54
55
|
}
|
|
55
56
|
if (flags.json) {
|
|
56
|
-
this.log(JSON.stringify(response, null, 2));
|
|
57
|
+
this.log(JSON.stringify((0, usd_micros_1.withUsdPrices)(response), null, 2));
|
|
57
58
|
return;
|
|
58
59
|
}
|
|
59
60
|
const r = response;
|
|
@@ -181,14 +181,14 @@ class SlackSendAsAgent extends base_command_1.BaseCommand {
|
|
|
181
181
|
exports.default = SlackSendAsAgent;
|
|
182
182
|
function generatedSessionIdempotencyKey(agentId, channelId, text) {
|
|
183
183
|
const requestId = process.env.OVERSKY_SESSION_REQUEST_ID || process.env.OVERSKY_REQUEST_ID;
|
|
184
|
-
if (requestId)
|
|
185
|
-
return `session:slack:${requestId}`;
|
|
186
184
|
const digest = crypto
|
|
187
185
|
.createHash('sha256')
|
|
188
186
|
.update(JSON.stringify({ agentId, channelId, text }))
|
|
189
187
|
.digest('hex')
|
|
190
188
|
.slice(0, 32);
|
|
191
|
-
|
|
189
|
+
if (requestId)
|
|
190
|
+
return `session:slack:${requestId}:${digest}`;
|
|
191
|
+
return `session:slack:${crypto.randomUUID()}`;
|
|
192
192
|
}
|
|
193
193
|
function formatSessionSlackResult(result, agentId, channelId) {
|
|
194
194
|
const status = result.status || 'submitted';
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const core_1 = require("@oclif/core");
|
|
4
4
|
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
5
|
-
const
|
|
5
|
+
const node_crypto_1 = require("node:crypto");
|
|
6
6
|
const api_fetch_1 = require("../../lib/api-fetch");
|
|
7
7
|
const base_command_1 = require("../../base-command");
|
|
8
8
|
const label_ref_1 = require("../../lib/label-ref");
|
|
@@ -124,7 +124,13 @@ class SpacesCreate extends base_command_1.BaseCommand {
|
|
|
124
124
|
// replay must collapse onto the write that already landed. A key sent only
|
|
125
125
|
// on the replay would create a second Space instead — the exact duplicate
|
|
126
126
|
// the outbox exists to prevent.
|
|
127
|
-
|
|
127
|
+
//
|
|
128
|
+
// The key is fresh per invocation and travels with the queued write; it is
|
|
129
|
+
// never derived from the payload. A payload-derived key made a second
|
|
130
|
+
// `spaces create` with the same title and parent replay the first for 24
|
|
131
|
+
// hours, so a person who archived "Billing migration" and asked for a new
|
|
132
|
+
// one got the archived Space back, and their new work was filed inside it.
|
|
133
|
+
const idempotencyKey = `space-create_${(0, node_crypto_1.randomUUID)()}`;
|
|
128
134
|
let created;
|
|
129
135
|
try {
|
|
130
136
|
// apiFetch rather than `dataService.createSpace`: the shared transport
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
/** Local documentation must remain readable without credentials or a daemon. */
|
|
3
|
+
export default class SpacesGuide extends Command {
|
|
4
|
+
static baseFlags: {
|
|
5
|
+
bare: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
6
|
+
token: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
raw: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
10
|
+
};
|
|
11
|
+
static description: string;
|
|
12
|
+
static args: {
|
|
13
|
+
section: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
14
|
+
};
|
|
15
|
+
static flags: {
|
|
16
|
+
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
17
|
+
offline: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
18
|
+
};
|
|
19
|
+
static examples: string[];
|
|
20
|
+
run(): Promise<void>;
|
|
21
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
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 agent_guides_1 = require("../../lib/agent-guides");
|
|
7
|
+
/** Local documentation must remain readable without credentials or a daemon. */
|
|
8
|
+
class SpacesGuide extends core_1.Command {
|
|
9
|
+
static baseFlags = base_command_1.BaseCommand.baseFlags;
|
|
10
|
+
static description = 'Alias of `skrr guide spaces views` — the Space perspective map. `skrr guide spaces` reads the whole guide.';
|
|
11
|
+
static args = {
|
|
12
|
+
section: core_1.Args.string({
|
|
13
|
+
description: 'A section of the spaces guide to read instead of `views`',
|
|
14
|
+
ignoreStdin: true,
|
|
15
|
+
}),
|
|
16
|
+
};
|
|
17
|
+
static flags = {
|
|
18
|
+
json: core_1.Flags.boolean({ description: 'Output the guide and source provenance as JSON' }),
|
|
19
|
+
offline: core_1.Flags.boolean({
|
|
20
|
+
description: 'Read the bundled release guides without checking credentials or the server',
|
|
21
|
+
}),
|
|
22
|
+
};
|
|
23
|
+
static examples = [
|
|
24
|
+
'<%= config.bin %> spaces guide',
|
|
25
|
+
'<%= config.bin %> spaces guide goals',
|
|
26
|
+
'<%= config.bin %> spaces guide --json',
|
|
27
|
+
];
|
|
28
|
+
async run() {
|
|
29
|
+
const { args, flags } = await this.parse(SpacesGuide);
|
|
30
|
+
const read = await (0, agent_guides_1.readAgentGuide)({ id: 'spaces', section: args.section ?? 'views' }, flags);
|
|
31
|
+
if (!read.found)
|
|
32
|
+
return (0, agent_guides_1.writeAgentGuideMiss)(this, read.miss, flags.json);
|
|
33
|
+
if (flags.json) {
|
|
34
|
+
process.stdout.write((0, agent_guides_1.agentGuideJson)(read));
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
process.stdout.write((0, data_provider_1.renderAgentGuideText)(read.response));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
exports.default = SpacesGuide;
|
|
@@ -9,7 +9,6 @@ declare const PERSPECTIVES: SpacePerspective[];
|
|
|
9
9
|
export default class Spaces extends BaseCommand {
|
|
10
10
|
static description: string;
|
|
11
11
|
static examples: string[];
|
|
12
|
-
static aliases: string[];
|
|
13
12
|
static flags: {
|
|
14
13
|
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
15
14
|
};
|
|
@@ -102,12 +102,7 @@ const PERSPECTIVES = [
|
|
|
102
102
|
exports.PERSPECTIVES = PERSPECTIVES;
|
|
103
103
|
class Spaces extends base_command_1.BaseCommand {
|
|
104
104
|
static description = 'Discover space perspectives and the CLI commands for each one';
|
|
105
|
-
static examples = [
|
|
106
|
-
'<%= config.bin %> spaces',
|
|
107
|
-
'<%= config.bin %> spaces --json',
|
|
108
|
-
'<%= config.bin %> spaces guide',
|
|
109
|
-
];
|
|
110
|
-
static aliases = ['spaces guide'];
|
|
105
|
+
static examples = ['<%= config.bin %> spaces', '<%= config.bin %> spaces --json'];
|
|
111
106
|
static flags = {
|
|
112
107
|
json: core_1.Flags.boolean({ description: 'Output the perspective guide as JSON' }),
|
|
113
108
|
};
|
|
@@ -5,6 +5,7 @@ const core_1 = require("@oclif/core");
|
|
|
5
5
|
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
6
6
|
const base_command_1 = require("../../../base-command");
|
|
7
7
|
const store_acquisition_1 = require("../../../lib/store-acquisition");
|
|
8
|
+
const usd_micros_1 = require("../../../lib/usd-micros");
|
|
8
9
|
/**
|
|
9
10
|
* Every purchase or install an agent asked to make for you, newest first
|
|
10
11
|
* (OSK-13403). Before this, a request was only reachable by its id — one from
|
|
@@ -42,7 +43,7 @@ class StoreAcquisitionsList extends base_command_1.BaseCommand {
|
|
|
42
43
|
}
|
|
43
44
|
const requests = result?.requests ?? [];
|
|
44
45
|
if (flags.json) {
|
|
45
|
-
this.printJsonResult((0, list_output_1.listResult)(result, 'requests'));
|
|
46
|
+
this.printJsonResult((0, list_output_1.listResult)((0, usd_micros_1.withUsdPrices)(result), 'requests'));
|
|
46
47
|
return;
|
|
47
48
|
}
|
|
48
49
|
if (requests.length === 0) {
|
|
@@ -4,6 +4,7 @@ const core_1 = require("@oclif/core");
|
|
|
4
4
|
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
5
5
|
const base_command_1 = require("../../../base-command");
|
|
6
6
|
const store_acquisition_1 = require("../../../lib/store-acquisition");
|
|
7
|
+
const usd_micros_1 = require("../../../lib/usd-micros");
|
|
7
8
|
/**
|
|
8
9
|
* A purchase an agent asked to make, read from the server's stored request
|
|
9
10
|
* (OSK-12240) — the same data the web approval card shows.
|
|
@@ -38,7 +39,7 @@ class StoreAcquisitionsShow extends base_command_1.BaseCommand {
|
|
|
38
39
|
this.error('The purchase request could not be read.', { exit: 1 });
|
|
39
40
|
}
|
|
40
41
|
if (flags.json) {
|
|
41
|
-
this.log(JSON.stringify(request, null, 2));
|
|
42
|
+
this.log(JSON.stringify((0, usd_micros_1.withUsdPrices)(request), null, 2));
|
|
42
43
|
return;
|
|
43
44
|
}
|
|
44
45
|
for (const line of (0, store_acquisition_1.describeAcquisitionRequestLines)(request)) {
|
|
@@ -4,6 +4,8 @@ const core_1 = require("@oclif/core");
|
|
|
4
4
|
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
5
5
|
const base_command_1 = require("../../base-command");
|
|
6
6
|
const format_1 = require("../../lib/format");
|
|
7
|
+
const store_listing_1 = require("../../lib/store-listing");
|
|
8
|
+
const usd_micros_1 = require("../../lib/usd-micros");
|
|
7
9
|
class StoreBrowse extends base_command_1.BaseCommand {
|
|
8
10
|
static description = 'Browse published agents in the store';
|
|
9
11
|
static examples = [
|
|
@@ -63,7 +65,7 @@ class StoreBrowse extends base_command_1.BaseCommand {
|
|
|
63
65
|
this.handleApiError(err);
|
|
64
66
|
}
|
|
65
67
|
if (flags.json) {
|
|
66
|
-
this.log(JSON.stringify(response, null, 2));
|
|
68
|
+
this.log(JSON.stringify((0, usd_micros_1.withUsdPrices)(response), null, 2));
|
|
67
69
|
return;
|
|
68
70
|
}
|
|
69
71
|
const r = response;
|
|
@@ -77,7 +79,7 @@ class StoreBrowse extends base_command_1.BaseCommand {
|
|
|
77
79
|
name: String(a.name ?? '-'),
|
|
78
80
|
// Price is a property of the LISTING, so it is read from the listing
|
|
79
81
|
// row rather than from anything the agent carries.
|
|
80
|
-
price: a.price ?
|
|
82
|
+
price: (0, store_listing_1.formatListingPrice)(typeof a.price === 'number' ? a.price : null),
|
|
81
83
|
rating: a.rating ? `${Number(a.rating).toFixed(1)} (${a.ratingCount ?? 0})` : '-',
|
|
82
84
|
installs: String(a.installCount ?? 0),
|
|
83
85
|
author: String(a.authorName ?? '-'),
|
|
@@ -12,6 +12,7 @@ export default class StoreInstall extends BaseCommand {
|
|
|
12
12
|
'include-bootstrap': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
13
13
|
'include-memory': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
14
14
|
yes: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
15
|
+
'expected-price': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
16
|
'run-on': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
16
17
|
'share-outcomes': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
17
18
|
};
|