@skrr-ai/cli 0.1.35 → 0.1.36
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/commands/balance/index.js +2 -1
- package/dist/commands/balance/overage.d.ts +12 -0
- package/dist/commands/balance/overage.js +43 -0
- package/dist/commands/balance/plan.d.ts +11 -0
- package/dist/commands/balance/plan.js +59 -0
- package/dist/commands/balance/usage/events.d.ts +15 -0
- package/dist/commands/balance/usage/events.js +69 -0
- package/dist/commands/balance/usage.js +13 -2
- package/dist/commands/commitments/export.d.ts +3 -0
- package/dist/commands/commitments/export.js +59 -14
- package/dist/commands/learning/export.d.ts +5 -1
- package/dist/commands/learning/export.js +85 -21
- package/dist/commands/tasks/export.d.ts +6 -2
- package/dist/commands/tasks/export.js +69 -21
- package/dist/commands/tones/export.d.ts +3 -1
- package/dist/commands/tones/export.js +50 -21
- package/dist/lib/artifact-export.d.ts +84 -0
- package/dist/lib/artifact-export.js +122 -0
- package/dist/lib/balance.d.ts +13 -1
- package/dist/lib/balance.js +30 -0
- package/dist/lib/web-url.d.ts +2 -0
- package/dist/lib/web-url.js +2 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarness.d.ts +15 -10
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarness.js +18 -11
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessChannels.js +9 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarness.d.ts +15 -10
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarness.js +18 -11
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessChannels.js +9 -3
- package/dist/node_modules/@skrr-ai/auth-core/package.json +1 -1
- package/dist/node_modules/@skrr-ai/data-provider/package.json +1 -1
- package/dist/node_modules/@skrr-ai/inference-broker/dist/cjs/loopback-server.d.ts +2 -0
- package/dist/node_modules/@skrr-ai/inference-broker/dist/cjs/loopback-server.js +8 -3
- package/dist/node_modules/@skrr-ai/inference-broker/dist/cjs/managed-inference-broker.d.ts +2 -0
- package/dist/node_modules/@skrr-ai/inference-broker/dist/cjs/managed-inference-broker.js +6 -1
- package/dist/node_modules/@skrr-ai/inference-broker/dist/esm/loopback-server.d.ts +2 -0
- package/dist/node_modules/@skrr-ai/inference-broker/dist/esm/loopback-server.js +9 -4
- package/dist/node_modules/@skrr-ai/inference-broker/dist/esm/managed-inference-broker.d.ts +2 -0
- package/dist/node_modules/@skrr-ai/inference-broker/dist/esm/managed-inference-broker.js +7 -2
- package/dist/node_modules/@skrr-ai/inference-broker/package.json +1 -1
- package/oclif.manifest.json +6974 -6657
- package/package.json +1 -1
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const promises_1 = require("node:fs/promises");
|
|
4
3
|
const core_1 = require("@oclif/core");
|
|
5
4
|
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
6
5
|
const base_command_1 = require("../../base-command");
|
|
7
6
|
const list_1 = require("./list");
|
|
8
7
|
const tasks_1 = require("../../lib/tasks");
|
|
9
8
|
const task_transfer_1 = require("../../lib/task-transfer");
|
|
9
|
+
const artifact_export_1 = require("../../lib/artifact-export");
|
|
10
10
|
/** The list filter vocabulary is intentionally mirrored here; request construction stays shared. */
|
|
11
11
|
const FILTER_FLAGS = {
|
|
12
12
|
space: core_1.Flags.string({ description: 'Filter by space ID' }),
|
|
@@ -49,26 +49,24 @@ const FILTER_FLAGS = {
|
|
|
49
49
|
class TasksExport extends base_command_1.BaseCommand {
|
|
50
50
|
static description = 'Export a filtered task forest as portable JSON or flat CSV';
|
|
51
51
|
static examples = [
|
|
52
|
+
'<%= config.bin %> tasks export --space <space-id> --summary',
|
|
52
53
|
'<%= config.bin %> tasks export --space <space-id> --output tasks.json',
|
|
53
54
|
'<%= config.bin %> tasks export --space <space-id> --format csv --output tasks.csv',
|
|
54
|
-
'<%= config.bin %> tasks export --space <space-id> --
|
|
55
|
+
'<%= config.bin %> tasks export --space <space-id> --output - | jq .',
|
|
55
56
|
];
|
|
56
57
|
static flags = {
|
|
57
58
|
...FILTER_FLAGS,
|
|
59
|
+
...(0, artifact_export_1.paginatedExportFlags)({ defaultMaxItems: 1000 }),
|
|
58
60
|
format: core_1.Flags.string({
|
|
59
61
|
description: 'Portable output format',
|
|
60
62
|
options: ['json', 'csv'],
|
|
61
63
|
default: 'json',
|
|
62
64
|
}),
|
|
63
|
-
output: core_1.Flags.string({
|
|
64
|
-
description: 'Write to this path instead of stdout (use "-" for stdout)',
|
|
65
|
-
}),
|
|
66
65
|
'with-comments': core_1.Flags.boolean({
|
|
67
66
|
description: 'Include comment bodies. Imported comments are newly authored by the importing principal.',
|
|
68
67
|
}),
|
|
69
68
|
max: core_1.Flags.integer({
|
|
70
|
-
description: '
|
|
71
|
-
default: 10000,
|
|
69
|
+
description: 'Deprecated alias for --max-items',
|
|
72
70
|
min: 1,
|
|
73
71
|
max: 100000,
|
|
74
72
|
}),
|
|
@@ -76,6 +74,29 @@ class TasksExport extends base_command_1.BaseCommand {
|
|
|
76
74
|
async run() {
|
|
77
75
|
this.requireAuth();
|
|
78
76
|
const { flags } = await this.parse(TasksExport);
|
|
77
|
+
let selection;
|
|
78
|
+
try {
|
|
79
|
+
selection = (0, artifact_export_1.resolveExportSelection)(flags);
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
if (err instanceof artifact_export_1.ExportContractError) {
|
|
83
|
+
this.failWithCliError({
|
|
84
|
+
message: err.message,
|
|
85
|
+
code: err.code,
|
|
86
|
+
exit: 2,
|
|
87
|
+
retryable: false,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
throw err;
|
|
91
|
+
}
|
|
92
|
+
if (flags.max !== undefined && flags['max-items'] !== undefined) {
|
|
93
|
+
this.failWithCliError({
|
|
94
|
+
message: '--max and --max-items cannot be used together.',
|
|
95
|
+
code: 'TASK_EXPORT_MAX_FLAG_CONFLICT',
|
|
96
|
+
exit: 2,
|
|
97
|
+
retryable: false,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
79
100
|
if (flags.mine && flags['assignee-user']) {
|
|
80
101
|
this.failWithCliError({
|
|
81
102
|
message: '--mine and --assignee-user are mutually exclusive.',
|
|
@@ -97,9 +118,9 @@ class TasksExport extends base_command_1.BaseCommand {
|
|
|
97
118
|
const assigneeUserId = flags.mine || flags['assignee-user']?.trim().toLowerCase() === 'me'
|
|
98
119
|
? await this.resolveCurrentUserId()
|
|
99
120
|
: flags['assignee-user'];
|
|
100
|
-
const max = flags.max ??
|
|
121
|
+
const max = flags.max ?? flags['max-items'] ?? 1000;
|
|
101
122
|
const all = [];
|
|
102
|
-
let cursor;
|
|
123
|
+
let cursor = flags.cursor;
|
|
103
124
|
let hasMore = false;
|
|
104
125
|
do {
|
|
105
126
|
let response;
|
|
@@ -119,14 +140,6 @@ class TasksExport extends base_command_1.BaseCommand {
|
|
|
119
140
|
cursor = response.next_cursor ?? undefined;
|
|
120
141
|
hasMore = Boolean(response.has_more && cursor);
|
|
121
142
|
} while (hasMore && all.length < max);
|
|
122
|
-
if (hasMore) {
|
|
123
|
-
this.failWithCliError({
|
|
124
|
-
message: `Export reached the --max safety cap (${max}). Narrow filters or pass a larger --max.`,
|
|
125
|
-
code: 'TASK_EXPORT_MAX_REACHED',
|
|
126
|
-
exit: 2,
|
|
127
|
-
retryable: false,
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
143
|
const commentsByTaskId = new Map();
|
|
131
144
|
if (flags['with-comments']) {
|
|
132
145
|
for (const task of all) {
|
|
@@ -158,16 +171,51 @@ class TasksExport extends base_command_1.BaseCommand {
|
|
|
158
171
|
commentsByTaskId.set(taskId, comments);
|
|
159
172
|
}
|
|
160
173
|
}
|
|
174
|
+
const commentCount = [...commentsByTaskId.values()].reduce((sum, comments) => sum + comments.length, 0);
|
|
175
|
+
if (selection.summary) {
|
|
176
|
+
const summary = (0, artifact_export_1.contentFreeSummary)({
|
|
177
|
+
command: 'tasks export',
|
|
178
|
+
artifactSchemaVersion: 1,
|
|
179
|
+
itemCount: all.length,
|
|
180
|
+
counts: { tasks: all.length, comments: commentCount },
|
|
181
|
+
truncated: hasMore,
|
|
182
|
+
nextCursor: cursor,
|
|
183
|
+
});
|
|
184
|
+
this.log(selection.json ? JSON.stringify(summary, null, 2) : (0, artifact_export_1.humanExportSummary)(summary));
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
161
187
|
const exported = (0, task_transfer_1.buildPortableTaskExport)(all, commentsByTaskId);
|
|
162
188
|
const content = flags.format === 'csv'
|
|
163
189
|
? (0, task_transfer_1.portableTaskExportToCsv)(exported)
|
|
164
190
|
: JSON.stringify(exported, null, 2);
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
this.log(
|
|
191
|
+
const artifact = content.endsWith('\n') ? content : `${content}\n`;
|
|
192
|
+
if (selection.output === '-') {
|
|
193
|
+
this.log(content);
|
|
168
194
|
return;
|
|
169
195
|
}
|
|
170
|
-
|
|
196
|
+
let receipt;
|
|
197
|
+
try {
|
|
198
|
+
receipt = await (0, artifact_export_1.writeExportArtifact)({
|
|
199
|
+
command: 'tasks export',
|
|
200
|
+
artifactSchemaVersion: exported.version,
|
|
201
|
+
format: flags.format ?? 'json',
|
|
202
|
+
output: selection.output,
|
|
203
|
+
content: artifact,
|
|
204
|
+
itemCount: all.length,
|
|
205
|
+
truncated: hasMore,
|
|
206
|
+
nextCursor: cursor,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
catch (err) {
|
|
210
|
+
this.failWithCliError({
|
|
211
|
+
message: `Could not write ${selection.output}: ${err.message}`,
|
|
212
|
+
code: 'TASK_EXPORT_WRITE_FAILED',
|
|
213
|
+
exit: 1,
|
|
214
|
+
retryable: false,
|
|
215
|
+
details: { path: selection.output },
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
this.log(selection.json ? JSON.stringify(receipt, null, 2) : (0, artifact_export_1.humanExportReceipt)(receipt));
|
|
171
219
|
}
|
|
172
220
|
}
|
|
173
221
|
exports.default = TasksExport;
|
|
@@ -20,9 +20,11 @@ export default class TonesExport extends BaseCommand {
|
|
|
20
20
|
id: import("@oclif/core/lib/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
21
21
|
};
|
|
22
22
|
static flags: {
|
|
23
|
-
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
24
23
|
mine: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
25
24
|
out: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
25
|
+
summary: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
26
|
+
output: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
27
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
26
28
|
};
|
|
27
29
|
run(): Promise<void>;
|
|
28
30
|
}
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.TONE_BUNDLE_VERSION = void 0;
|
|
4
4
|
const core_1 = require("@oclif/core");
|
|
5
|
-
const promises_1 = require("node:fs/promises");
|
|
6
5
|
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
7
6
|
const base_command_1 = require("../../base-command");
|
|
8
7
|
const tone_input_1 = require("../../lib/tone-input");
|
|
8
|
+
const artifact_export_1 = require("../../lib/artifact-export");
|
|
9
9
|
/** Shape written by `export` and accepted by `import`. */
|
|
10
10
|
exports.TONE_BUNDLE_VERSION = 1;
|
|
11
11
|
/**
|
|
@@ -23,9 +23,10 @@ exports.TONE_BUNDLE_VERSION = 1;
|
|
|
23
23
|
class TonesExport extends base_command_1.BaseCommand {
|
|
24
24
|
static description = 'Export tones as JSON (round-trips with `tones import`)';
|
|
25
25
|
static examples = [
|
|
26
|
-
'<%= config.bin %> tones export',
|
|
27
|
-
'<%= config.bin %> tones export --mine --
|
|
28
|
-
'<%= config.bin %> tones export brief --
|
|
26
|
+
'<%= config.bin %> tones export --summary',
|
|
27
|
+
'<%= config.bin %> tones export --mine --output tones.json',
|
|
28
|
+
'<%= config.bin %> tones export brief --output brief.json',
|
|
29
|
+
'<%= config.bin %> tones export --output - | jq .',
|
|
29
30
|
];
|
|
30
31
|
static args = {
|
|
31
32
|
id: core_1.Args.string({
|
|
@@ -35,15 +36,28 @@ class TonesExport extends base_command_1.BaseCommand {
|
|
|
35
36
|
}),
|
|
36
37
|
};
|
|
37
38
|
static flags = {
|
|
38
|
-
|
|
39
|
-
description: 'Print the bundle to stdout even when --out wrote it to a file',
|
|
40
|
-
}),
|
|
39
|
+
...(0, artifact_export_1.standardExportFlags)(),
|
|
41
40
|
mine: core_1.Flags.boolean({ description: 'Export only tones you authored' }),
|
|
42
|
-
out: core_1.Flags.string({ description: '
|
|
41
|
+
out: core_1.Flags.string({ description: 'Deprecated alias for --output' }),
|
|
43
42
|
};
|
|
44
43
|
async run() {
|
|
45
44
|
this.requireAuth();
|
|
46
45
|
const { args, flags } = await this.parse(TonesExport);
|
|
46
|
+
let selection;
|
|
47
|
+
try {
|
|
48
|
+
selection = (0, artifact_export_1.resolveExportSelection)(flags);
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
if (err instanceof artifact_export_1.ExportContractError) {
|
|
52
|
+
this.failWithCliError({
|
|
53
|
+
message: err.message,
|
|
54
|
+
code: err.code,
|
|
55
|
+
exit: 2,
|
|
56
|
+
retryable: false,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
throw err;
|
|
60
|
+
}
|
|
47
61
|
let library;
|
|
48
62
|
try {
|
|
49
63
|
library = await data_provider_1.dataService.listTones();
|
|
@@ -79,6 +93,19 @@ class TonesExport extends base_command_1.BaseCommand {
|
|
|
79
93
|
else {
|
|
80
94
|
selected = flags.mine ? [...library.custom] : [...library.presets, ...library.custom];
|
|
81
95
|
}
|
|
96
|
+
if (selection.summary) {
|
|
97
|
+
const summary = (0, artifact_export_1.contentFreeSummary)({
|
|
98
|
+
command: 'tones export',
|
|
99
|
+
artifactSchemaVersion: exports.TONE_BUNDLE_VERSION,
|
|
100
|
+
itemCount: selected.length,
|
|
101
|
+
counts: {
|
|
102
|
+
presets: selected.filter((tone) => !(0, tone_input_1.isCustomTone)(tone)).length,
|
|
103
|
+
custom: selected.filter((tone) => (0, tone_input_1.isCustomTone)(tone)).length,
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
this.log(selection.json ? JSON.stringify(summary, null, 2) : (0, artifact_export_1.humanExportSummary)(summary));
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
82
109
|
const bundle = {
|
|
83
110
|
object: 'sky.tone.bundle',
|
|
84
111
|
version: exports.TONE_BUNDLE_VERSION,
|
|
@@ -97,30 +124,32 @@ class TonesExport extends base_command_1.BaseCommand {
|
|
|
97
124
|
visibility: (0, tone_input_1.isCustomTone)(tone) ? tone.visibility : 'private',
|
|
98
125
|
})),
|
|
99
126
|
};
|
|
100
|
-
const serialized =
|
|
101
|
-
if (
|
|
102
|
-
// stdout IS the bundle here — `skrr tones export > tones.json` and
|
|
103
|
-
// `… | jq` both work without a flag, so --json is a no-op on this path.
|
|
127
|
+
const serialized = (0, artifact_export_1.serializedArtifact)(bundle);
|
|
128
|
+
if (selection.output === '-') {
|
|
104
129
|
this.log(serialized.trimEnd());
|
|
105
130
|
return;
|
|
106
131
|
}
|
|
132
|
+
let receipt;
|
|
107
133
|
try {
|
|
108
|
-
await (0,
|
|
134
|
+
receipt = await (0, artifact_export_1.writeExportArtifact)({
|
|
135
|
+
command: 'tones export',
|
|
136
|
+
artifactSchemaVersion: exports.TONE_BUNDLE_VERSION,
|
|
137
|
+
format: 'json',
|
|
138
|
+
output: selection.output,
|
|
139
|
+
content: serialized,
|
|
140
|
+
itemCount: selected.length,
|
|
141
|
+
});
|
|
109
142
|
}
|
|
110
143
|
catch (err) {
|
|
111
144
|
this.failWithCliError({
|
|
112
|
-
message: `Could not write ${
|
|
145
|
+
message: `Could not write ${selection.output}: ${err.message}`,
|
|
113
146
|
code: 'TONE_BUNDLE_WRITE_FAILED',
|
|
114
147
|
exit: 1,
|
|
115
|
-
retryable:
|
|
116
|
-
details: { path:
|
|
148
|
+
retryable: false,
|
|
149
|
+
details: { path: selection.output },
|
|
117
150
|
});
|
|
118
151
|
}
|
|
119
|
-
|
|
120
|
-
this.log(serialized.trimEnd());
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
this.log(`Wrote ${bundle.tones.length} tone(s) to ${flags.out}.`);
|
|
152
|
+
this.log(selection.json ? JSON.stringify(receipt, null, 2) : (0, artifact_export_1.humanExportReceipt)(receipt));
|
|
124
153
|
}
|
|
125
154
|
}
|
|
126
155
|
exports.default = TonesExport;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
export declare const EXPORT_RECEIPT_SCHEMA_VERSION = 1;
|
|
2
|
+
export type ExportSelection = {
|
|
3
|
+
output?: string;
|
|
4
|
+
summary: boolean;
|
|
5
|
+
json: boolean;
|
|
6
|
+
};
|
|
7
|
+
export type ExportReceipt = {
|
|
8
|
+
object: 'skrr.export.receipt';
|
|
9
|
+
schemaVersion: typeof EXPORT_RECEIPT_SCHEMA_VERSION;
|
|
10
|
+
command: string;
|
|
11
|
+
artifactSchemaVersion: string | number;
|
|
12
|
+
format: string;
|
|
13
|
+
output: string;
|
|
14
|
+
contentDigest: string;
|
|
15
|
+
bytes: number;
|
|
16
|
+
lines: number;
|
|
17
|
+
itemCount: number;
|
|
18
|
+
truncated: boolean;
|
|
19
|
+
nextCursor: string | null;
|
|
20
|
+
};
|
|
21
|
+
export declare class ExportContractError extends Error {
|
|
22
|
+
readonly code: string;
|
|
23
|
+
constructor(message: string, code: string);
|
|
24
|
+
}
|
|
25
|
+
export declare function standardExportFlags(): {
|
|
26
|
+
summary: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
27
|
+
output: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
28
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
29
|
+
};
|
|
30
|
+
export declare function paginatedExportFlags(options?: {
|
|
31
|
+
defaultMaxItems?: number;
|
|
32
|
+
}): {
|
|
33
|
+
'max-items': import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
34
|
+
cursor: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
35
|
+
summary: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
36
|
+
output: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
37
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
38
|
+
};
|
|
39
|
+
export declare function resolveExportSelection(flags: {
|
|
40
|
+
output?: string;
|
|
41
|
+
out?: string;
|
|
42
|
+
summary?: boolean;
|
|
43
|
+
json?: boolean;
|
|
44
|
+
}): ExportSelection;
|
|
45
|
+
export declare function serializedArtifact(value: unknown): string;
|
|
46
|
+
export declare function buildExportReceipt(input: {
|
|
47
|
+
command: string;
|
|
48
|
+
artifactSchemaVersion: string | number;
|
|
49
|
+
format: string;
|
|
50
|
+
output: string;
|
|
51
|
+
content: string;
|
|
52
|
+
itemCount: number;
|
|
53
|
+
truncated?: boolean;
|
|
54
|
+
nextCursor?: string | null;
|
|
55
|
+
}): ExportReceipt;
|
|
56
|
+
export declare function writeExportArtifact(input: {
|
|
57
|
+
command: string;
|
|
58
|
+
artifactSchemaVersion: string | number;
|
|
59
|
+
format: string;
|
|
60
|
+
output: string;
|
|
61
|
+
content: string;
|
|
62
|
+
itemCount: number;
|
|
63
|
+
truncated?: boolean;
|
|
64
|
+
nextCursor?: string | null;
|
|
65
|
+
}): Promise<ExportReceipt>;
|
|
66
|
+
export declare function humanExportReceipt(receipt: ExportReceipt): string;
|
|
67
|
+
export declare function contentFreeSummary(input: {
|
|
68
|
+
command: string;
|
|
69
|
+
artifactSchemaVersion: string | number;
|
|
70
|
+
itemCount: number;
|
|
71
|
+
truncated?: boolean;
|
|
72
|
+
nextCursor?: string | null;
|
|
73
|
+
counts?: Record<string, number>;
|
|
74
|
+
}): {
|
|
75
|
+
object: "skrr.export.summary";
|
|
76
|
+
schemaVersion: number;
|
|
77
|
+
command: string;
|
|
78
|
+
artifactSchemaVersion: string | number;
|
|
79
|
+
itemCount: number;
|
|
80
|
+
counts: Record<string, number>;
|
|
81
|
+
truncated: boolean;
|
|
82
|
+
nextCursor: string | null;
|
|
83
|
+
};
|
|
84
|
+
export declare function humanExportSummary(summary: ReturnType<typeof contentFreeSummary>): string;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ExportContractError = exports.EXPORT_RECEIPT_SCHEMA_VERSION = void 0;
|
|
4
|
+
exports.standardExportFlags = standardExportFlags;
|
|
5
|
+
exports.paginatedExportFlags = paginatedExportFlags;
|
|
6
|
+
exports.resolveExportSelection = resolveExportSelection;
|
|
7
|
+
exports.serializedArtifact = serializedArtifact;
|
|
8
|
+
exports.buildExportReceipt = buildExportReceipt;
|
|
9
|
+
exports.writeExportArtifact = writeExportArtifact;
|
|
10
|
+
exports.humanExportReceipt = humanExportReceipt;
|
|
11
|
+
exports.contentFreeSummary = contentFreeSummary;
|
|
12
|
+
exports.humanExportSummary = humanExportSummary;
|
|
13
|
+
const node_crypto_1 = require("node:crypto");
|
|
14
|
+
const promises_1 = require("node:fs/promises");
|
|
15
|
+
const core_1 = require("@oclif/core");
|
|
16
|
+
exports.EXPORT_RECEIPT_SCHEMA_VERSION = 1;
|
|
17
|
+
class ExportContractError extends Error {
|
|
18
|
+
code;
|
|
19
|
+
constructor(message, code) {
|
|
20
|
+
super(message);
|
|
21
|
+
this.code = code;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
exports.ExportContractError = ExportContractError;
|
|
25
|
+
function standardExportFlags() {
|
|
26
|
+
return {
|
|
27
|
+
summary: core_1.Flags.boolean({
|
|
28
|
+
description: 'Print a content-free summary instead of the full artifact',
|
|
29
|
+
}),
|
|
30
|
+
output: core_1.Flags.string({
|
|
31
|
+
char: 'o',
|
|
32
|
+
description: 'Write the full artifact to this path; use "-" for deliberate stdout',
|
|
33
|
+
}),
|
|
34
|
+
json: core_1.Flags.boolean({
|
|
35
|
+
description: 'Print summary or file receipt as machine-readable JSON',
|
|
36
|
+
}),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function paginatedExportFlags(options = {}) {
|
|
40
|
+
return {
|
|
41
|
+
...standardExportFlags(),
|
|
42
|
+
'max-items': core_1.Flags.integer({
|
|
43
|
+
description: `Maximum records in this export chunk (default ${options.defaultMaxItems ?? 1000})`,
|
|
44
|
+
min: 1,
|
|
45
|
+
max: 100000,
|
|
46
|
+
}),
|
|
47
|
+
cursor: core_1.Flags.string({
|
|
48
|
+
description: 'Opaque cursor returned by a previous export chunk',
|
|
49
|
+
}),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function resolveExportSelection(flags) {
|
|
53
|
+
if (flags.output && flags.out) {
|
|
54
|
+
throw new ExportContractError('--output and the deprecated --out alias cannot be used together.', 'EXPORT_OUTPUT_FLAG_CONFLICT');
|
|
55
|
+
}
|
|
56
|
+
const output = flags.output ?? flags.out;
|
|
57
|
+
const summary = Boolean(flags.summary);
|
|
58
|
+
if (!output && !summary) {
|
|
59
|
+
throw new ExportContractError('Choose --summary, --output <path>, or --output - for deliberate stdout.', 'EXPORT_DESTINATION_REQUIRED');
|
|
60
|
+
}
|
|
61
|
+
if (output && summary) {
|
|
62
|
+
throw new ExportContractError('--summary and --output are mutually exclusive.', 'EXPORT_MODE_CONFLICT');
|
|
63
|
+
}
|
|
64
|
+
return { output, summary, json: Boolean(flags.json) };
|
|
65
|
+
}
|
|
66
|
+
function serializedArtifact(value) {
|
|
67
|
+
return `${JSON.stringify(value, null, 2)}\n`;
|
|
68
|
+
}
|
|
69
|
+
function buildExportReceipt(input) {
|
|
70
|
+
return {
|
|
71
|
+
object: 'skrr.export.receipt',
|
|
72
|
+
schemaVersion: exports.EXPORT_RECEIPT_SCHEMA_VERSION,
|
|
73
|
+
command: input.command,
|
|
74
|
+
artifactSchemaVersion: input.artifactSchemaVersion,
|
|
75
|
+
format: input.format,
|
|
76
|
+
output: input.output,
|
|
77
|
+
contentDigest: (0, node_crypto_1.createHash)('sha256').update(input.content).digest('hex'),
|
|
78
|
+
bytes: Buffer.byteLength(input.content),
|
|
79
|
+
lines: input.content.length ? input.content.split('\n').length - 1 : 0,
|
|
80
|
+
itemCount: input.itemCount,
|
|
81
|
+
truncated: Boolean(input.truncated),
|
|
82
|
+
nextCursor: input.nextCursor ?? null,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
async function writeExportArtifact(input) {
|
|
86
|
+
const receipt = buildExportReceipt(input);
|
|
87
|
+
if (input.output === '-')
|
|
88
|
+
return receipt;
|
|
89
|
+
await (0, promises_1.writeFile)(input.output, input.content, {
|
|
90
|
+
encoding: 'utf8',
|
|
91
|
+
flag: 'wx',
|
|
92
|
+
mode: 0o600,
|
|
93
|
+
});
|
|
94
|
+
return receipt;
|
|
95
|
+
}
|
|
96
|
+
function humanExportReceipt(receipt) {
|
|
97
|
+
const continuation = receipt.truncated && receipt.nextCursor ? ` Next cursor: ${receipt.nextCursor}.` : '';
|
|
98
|
+
return (`Wrote ${receipt.itemCount} item(s) to ${receipt.output} ` +
|
|
99
|
+
`(${receipt.bytes} bytes, sha256:${receipt.contentDigest}, schema ` +
|
|
100
|
+
`${receipt.artifactSchemaVersion}).${continuation}`);
|
|
101
|
+
}
|
|
102
|
+
function contentFreeSummary(input) {
|
|
103
|
+
return {
|
|
104
|
+
object: 'skrr.export.summary',
|
|
105
|
+
schemaVersion: exports.EXPORT_RECEIPT_SCHEMA_VERSION,
|
|
106
|
+
command: input.command,
|
|
107
|
+
artifactSchemaVersion: input.artifactSchemaVersion,
|
|
108
|
+
itemCount: input.itemCount,
|
|
109
|
+
counts: input.counts ?? {},
|
|
110
|
+
truncated: Boolean(input.truncated),
|
|
111
|
+
nextCursor: input.nextCursor ?? null,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
function humanExportSummary(summary) {
|
|
115
|
+
const counts = Object.entries(summary.counts)
|
|
116
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
117
|
+
.join(', ');
|
|
118
|
+
const continuation = summary.truncated && summary.nextCursor ? `; next cursor=${summary.nextCursor}` : '';
|
|
119
|
+
return (`${summary.command}: ${summary.itemCount} item(s)` +
|
|
120
|
+
(counts ? ` (${counts})` : '') +
|
|
121
|
+
`; schema ${summary.artifactSchemaVersion}${continuation}`);
|
|
122
|
+
}
|
package/dist/lib/balance.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { TSkyCodeUsageSnapshot } from '@skrr-ai/data-provider';
|
|
1
|
+
import type { TSubscription, TSkyCodeUsageEvents, TSkyCodeUsageSnapshot } from '@skrr-ai/data-provider';
|
|
2
2
|
/**
|
|
3
3
|
* balance.ts — request client for `/api/balance`.
|
|
4
4
|
*
|
|
@@ -79,6 +79,18 @@ export interface BalanceHistory {
|
|
|
79
79
|
/** The account's current credits, limit and period usage. */
|
|
80
80
|
export declare function getBalance(): Promise<BalanceStatus>;
|
|
81
81
|
export declare function getSkyCodeUsage(workspaceId?: string): Promise<TSkyCodeUsageSnapshot>;
|
|
82
|
+
/** The personal Sky Code subscription, distinct from published agent-service subscriptions. */
|
|
83
|
+
export declare function getSkyCodeSubscription(): Promise<TSubscription>;
|
|
84
|
+
/** Explicit personal consent to use stored balance after included Sky Code allowance. */
|
|
85
|
+
export declare function setSkyCodeOverageConsent(enabled: boolean): Promise<{
|
|
86
|
+
enabled: boolean;
|
|
87
|
+
}>;
|
|
88
|
+
export declare function getSkyCodeUsageEvents(workspaceId: string | undefined, params?: {
|
|
89
|
+
from?: string;
|
|
90
|
+
to?: string;
|
|
91
|
+
cursor?: string;
|
|
92
|
+
limit?: number;
|
|
93
|
+
}): Promise<TSkyCodeUsageEvents>;
|
|
82
94
|
/** Recent token transactions, newest first. Cursor is an ISO createdAt. */
|
|
83
95
|
export declare function getBalanceHistory(limit: number, cursor?: string): Promise<BalanceHistory>;
|
|
84
96
|
/**
|
package/dist/lib/balance.js
CHANGED
|
@@ -3,6 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.CREDITS_PER_USD = void 0;
|
|
4
4
|
exports.getBalance = getBalance;
|
|
5
5
|
exports.getSkyCodeUsage = getSkyCodeUsage;
|
|
6
|
+
exports.getSkyCodeSubscription = getSkyCodeSubscription;
|
|
7
|
+
exports.setSkyCodeOverageConsent = setSkyCodeOverageConsent;
|
|
8
|
+
exports.getSkyCodeUsageEvents = getSkyCodeUsageEvents;
|
|
6
9
|
exports.getBalanceHistory = getBalanceHistory;
|
|
7
10
|
exports.formatCredits = formatCredits;
|
|
8
11
|
exports.getWorkspaceBalance = getWorkspaceBalance;
|
|
@@ -27,6 +30,33 @@ async function getSkyCodeUsage(workspaceId) {
|
|
|
27
30
|
: '/api/balance/usage/sky-code';
|
|
28
31
|
return (0, api_fetch_1.apiFetch)(path);
|
|
29
32
|
}
|
|
33
|
+
/** The personal Sky Code subscription, distinct from published agent-service subscriptions. */
|
|
34
|
+
async function getSkyCodeSubscription() {
|
|
35
|
+
return (0, api_fetch_1.apiFetch)('/api/stripe/subscription');
|
|
36
|
+
}
|
|
37
|
+
/** Explicit personal consent to use stored balance after included Sky Code allowance. */
|
|
38
|
+
async function setSkyCodeOverageConsent(enabled) {
|
|
39
|
+
return (0, api_fetch_1.apiFetch)('/api/balance/usage/sky-code/overage', {
|
|
40
|
+
method: 'PUT',
|
|
41
|
+
body: { enabled },
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
async function getSkyCodeUsageEvents(workspaceId, params = {}) {
|
|
45
|
+
const query = new URLSearchParams();
|
|
46
|
+
if (params.from)
|
|
47
|
+
query.set('from', params.from);
|
|
48
|
+
if (params.to)
|
|
49
|
+
query.set('to', params.to);
|
|
50
|
+
if (params.cursor)
|
|
51
|
+
query.set('cursor', params.cursor);
|
|
52
|
+
if (params.limit !== undefined)
|
|
53
|
+
query.set('limit', String(params.limit));
|
|
54
|
+
const base = workspaceId
|
|
55
|
+
? `/api/balance/usage/sky-code/workspace/${encodeURIComponent(workspaceId)}/events`
|
|
56
|
+
: '/api/balance/usage/sky-code/events';
|
|
57
|
+
const suffix = query.toString();
|
|
58
|
+
return (0, api_fetch_1.apiFetch)(suffix ? `${base}?${suffix}` : base);
|
|
59
|
+
}
|
|
30
60
|
/** Recent token transactions, newest first. Cursor is an ISO createdAt. */
|
|
31
61
|
async function getBalanceHistory(limit, cursor) {
|
|
32
62
|
const query = new URLSearchParams({ limit: String(limit) });
|
package/dist/lib/web-url.d.ts
CHANGED
package/dist/lib/web-url.js
CHANGED
|
@@ -19,7 +19,9 @@
|
|
|
19
19
|
*
|
|
20
20
|
* 1. set `displayName` and `provider`;
|
|
21
21
|
* 2. move the old `provider` to the front of `aliases`;
|
|
22
|
-
* 3.
|
|
22
|
+
* 3. set `wireProvider` to the old spelling as a literal — installed daemons
|
|
23
|
+
* still speak it — and derive it from `provider` again only in the wire
|
|
24
|
+
* phase, once every peer accepts the new one;
|
|
23
25
|
* 4. regenerate `first-party-harness.json`
|
|
24
26
|
* (`node --import tsx scripts/emit-first-party-harness-json.mjs`);
|
|
25
27
|
* 5. ship the data migration, which is generic over `aliases`.
|
|
@@ -33,9 +35,11 @@
|
|
|
33
35
|
* canonical at the edge. Nothing new is ever written with one.
|
|
34
36
|
* `wireProvider` What the server and a daemon say to EACH OTHER — the
|
|
35
37
|
* capability a daemon advertises, `daemon:<p>:request|response`,
|
|
36
|
-
* the `provider` of a session RPC. It moves
|
|
37
|
-
* daemon on a user's machine may be
|
|
38
|
-
* cannot tell which one sent a
|
|
38
|
+
* the `provider` of a session RPC. It moves after the flip and
|
|
39
|
+
* BEFORE contract, because a daemon on a user's machine may be
|
|
40
|
+
* any version and the server cannot tell which one sent a
|
|
41
|
+
* request: only a released daemon that already advertises the
|
|
42
|
+
* canonical capability lets the old one age out of the fleet.
|
|
39
43
|
*
|
|
40
44
|
* The old code treated those three as one string, which is why no single
|
|
41
45
|
* change could rename it safely. See
|
|
@@ -63,18 +67,19 @@ export interface FirstPartyHarnessIdentity {
|
|
|
63
67
|
/**
|
|
64
68
|
* THE identity — the only literal product name in the codebase.
|
|
65
69
|
*
|
|
66
|
-
* Phase:
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* `
|
|
70
|
+
* Phase: WIRE MOVED. `skrr-code` is canonical — stored, returned, rendered — and
|
|
71
|
+
* it is now also what the server and a daemon say to each other. `sky-code` is
|
|
72
|
+
* still accepted on every ingress, so a daemon released before this change
|
|
73
|
+
* (which advertises and answers on `sky-code`) keeps working against a server
|
|
74
|
+
* that speaks `skrr-code`, and the reverse. Contract (OSK-8663) empties
|
|
75
|
+
* `aliases` once no connected daemon still advertises the old capability.
|
|
71
76
|
*/
|
|
72
77
|
declare const IDENTITY: {
|
|
73
78
|
readonly displayName: "skrr Code";
|
|
74
79
|
readonly command: "skrr code";
|
|
75
80
|
readonly provider: "skrr-code";
|
|
76
81
|
readonly aliases: readonly ["sky-code"];
|
|
77
|
-
readonly wireProvider: "
|
|
82
|
+
readonly wireProvider: "skrr-code";
|
|
78
83
|
};
|
|
79
84
|
/** The canonical slug, as a literal type. */
|
|
80
85
|
export type FirstPartyHarnessCanonicalProvider = typeof IDENTITY.provider;
|