@skrr-ai/cli 0.1.42 → 0.1.43
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/overage.js +4 -3
- package/dist/commands/balance/plan.js +10 -6
- package/dist/commands/balance/usage/events.js +3 -2
- package/dist/commands/balance/usage.js +2 -1
- package/dist/commands/browser/install.js +3 -2
- package/dist/commands/browser/uninstall.js +3 -2
- package/dist/commands/code/install.js +3 -2
- package/dist/commands/harnesses/install.d.ts +11 -0
- package/dist/commands/harnesses/install.js +33 -14
- package/dist/commands/harnesses/installers.d.ts +10 -0
- package/dist/commands/harnesses/installers.js +31 -0
- package/dist/commands/harnesses/list.js +3 -2
- package/dist/commands/tasks/attachments/set-role.d.ts +24 -0
- package/dist/commands/tasks/attachments/set-role.js +60 -0
- package/dist/commands/tasks/attachments/upload.d.ts +1 -0
- package/dist/commands/tasks/attachments/upload.js +18 -52
- package/dist/commands/tasks/comments/add.d.ts +1 -0
- package/dist/commands/tasks/comments/add.js +67 -2
- package/dist/commands/tasks/complete.d.ts +1 -0
- package/dist/commands/tasks/complete.js +56 -1
- package/dist/commands/tasks/result/submit.d.ts +3 -0
- package/dist/commands/tasks/result/submit.js +76 -8
- package/dist/commands/tasks/update.js +4 -2
- package/dist/commands/tasks/updates/add.d.ts +1 -0
- package/dist/commands/tasks/updates/add.js +63 -0
- package/dist/lib/api-fetch.js +7 -2
- package/dist/lib/cli-installers.d.ts +23 -4
- package/dist/lib/cli-installers.js +47 -7
- package/dist/lib/dedicated-machines.js +4 -2
- package/dist/lib/file-mime.js +1 -1
- package/dist/lib/first-party-harness-agent.js +6 -5
- package/dist/lib/first-party-harness-doctor.js +15 -32
- package/dist/lib/first-party-harness-managed.d.ts +9 -4
- package/dist/lib/first-party-harness-managed.js +13 -10
- package/dist/lib/first-party-harness.d.ts +25 -21
- package/dist/lib/first-party-harness.js +40 -27
- package/dist/lib/harness-provider-input.d.ts +18 -12
- package/dist/lib/harness-provider-input.js +18 -12
- package/dist/lib/harness-tiers.d.ts +4 -3
- package/dist/lib/harness-tiers.js +4 -3
- package/dist/lib/html-text.js +25 -0
- package/dist/lib/session-task-endpoints.d.ts +1 -1
- package/dist/lib/session-task-endpoints.js +3 -0
- package/dist/lib/task-asset-upload.d.ts +84 -0
- package/dist/lib/task-asset-upload.js +374 -0
- package/dist/lib/task-closure.d.ts +15 -0
- package/dist/lib/task-closure.js +20 -0
- package/dist/lib/tasks.d.ts +8 -0
- package/dist/lib/tasks.js +16 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarness.d.ts +113 -39
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarness.js +148 -71
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessChannels.d.ts +21 -33
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessChannels.js +24 -50
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessHome.d.ts +19 -7
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessHome.js +26 -10
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/harnessTrust.d.ts +9 -5
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/harnessTrust.js +9 -5
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.d.ts +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.js +1 -13
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarness.d.ts +113 -39
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarness.js +146 -70
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessChannels.d.ts +21 -33
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessChannels.js +24 -49
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessHome.d.ts +19 -7
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessHome.js +27 -11
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/harnessTrust.d.ts +9 -5
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/harnessTrust.js +9 -5
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.d.ts +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.js +1 -4
- package/dist/node_modules/@skrr-ai/auth-core/package.json +1 -1
- package/dist/node_modules/@skrr-ai/data-provider/index.js +3855 -3779
- package/dist/node_modules/@skrr-ai/data-provider/package.json +1 -1
- package/oclif.manifest.json +26935 -26810
- package/package.json +2 -2
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const core_1 = require("@oclif/core");
|
|
4
|
+
const auth_core_1 = require("@skrr-ai/auth-core");
|
|
4
5
|
const base_command_1 = require("../../base-command");
|
|
5
6
|
const balance_1 = require("../../lib/balance");
|
|
6
7
|
class BalanceOverage extends base_command_1.BaseCommand {
|
|
7
|
-
static description =
|
|
8
|
+
static description = `Enable or disable personal ${auth_core_1.FIRST_PARTY_HARNESS.displayName} overage after included allowance is exhausted`;
|
|
8
9
|
static examples = [
|
|
9
10
|
'<%= config.bin %> balance overage enabled',
|
|
10
11
|
'<%= config.bin %> balance overage disabled',
|
|
@@ -12,7 +13,7 @@ class BalanceOverage extends base_command_1.BaseCommand {
|
|
|
12
13
|
];
|
|
13
14
|
static args = {
|
|
14
15
|
state: core_1.Args.string({
|
|
15
|
-
description:
|
|
16
|
+
description: `Whether personal stored balance may pay for ${auth_core_1.FIRST_PARTY_HARNESS.displayName} overage`,
|
|
16
17
|
required: true,
|
|
17
18
|
options: ['enabled', 'disabled'],
|
|
18
19
|
ignoreStdin: true,
|
|
@@ -34,7 +35,7 @@ class BalanceOverage extends base_command_1.BaseCommand {
|
|
|
34
35
|
this.log(JSON.stringify({ ownerType: 'user', overageEnabled: result?.enabled === true }, null, 2));
|
|
35
36
|
return;
|
|
36
37
|
}
|
|
37
|
-
this.log(
|
|
38
|
+
this.log(`${auth_core_1.FIRST_PARTY_HARNESS.displayName} overage ${result?.enabled ? 'enabled' : 'disabled'} for your personal billing account.`);
|
|
38
39
|
this.log(result?.enabled
|
|
39
40
|
? 'New admissions may use stored balance after included allowance is exhausted.'
|
|
40
41
|
: 'New admissions will stop when included allowance is exhausted.');
|
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.renderSkyCodePlan = renderSkyCodePlan;
|
|
4
4
|
const core_1 = require("@oclif/core");
|
|
5
|
+
const auth_core_1 = require("@skrr-ai/auth-core");
|
|
5
6
|
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
6
7
|
const base_command_1 = require("../../base-command");
|
|
7
8
|
const balance_1 = require("../../lib/balance");
|
|
8
9
|
const web_url_1 = require("../../lib/web-url");
|
|
9
10
|
class BalancePlan extends base_command_1.BaseCommand {
|
|
10
|
-
static description =
|
|
11
|
+
static description = `Show your ${auth_core_1.FIRST_PARTY_HARNESS.displayName} plan, renewal state, available tiers, and the matching lifecycle page`;
|
|
11
12
|
static examples = [
|
|
12
13
|
'<%= config.bin %> balance plan',
|
|
13
14
|
'<%= config.bin %> balance plan --json',
|
|
@@ -33,7 +34,7 @@ class BalancePlan extends base_command_1.BaseCommand {
|
|
|
33
34
|
}
|
|
34
35
|
exports.default = BalancePlan;
|
|
35
36
|
function renderSkyCodePlan(subscription, lifecycleUrl, log) {
|
|
36
|
-
log(
|
|
37
|
+
log(`${auth_core_1.FIRST_PARTY_HARNESS.displayName} plan — ${subscription.tierName}`);
|
|
37
38
|
log(` Status ${subscription.status}`);
|
|
38
39
|
log(` Price $${subscription.monthlyPriceUsd}/month`);
|
|
39
40
|
log(` Current period ${subscription.currentPeriodStart ?? 'not started'}`);
|
|
@@ -43,10 +44,13 @@ function renderSkyCodePlan(subscription, lifecycleUrl, log) {
|
|
|
43
44
|
log(` Concurrent sessions ${subscription.concurrentSessions ?? 'not reported'}`);
|
|
44
45
|
log(` Requests per minute ${subscription.rateLimitPerMin}`);
|
|
45
46
|
log('');
|
|
46
|
-
log(
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
log(`Available ${auth_core_1.FIRST_PARTY_HARNESS.displayName} plans:`);
|
|
48
|
+
const paidPlans = data_provider_1.SKY_CODE_PLAN_KEYS.filter((plan) => plan !== 'free').map((key) => data_provider_1.SKY_CODE_PLAN_CATALOG[key]);
|
|
49
|
+
// Padded to the longest name rather than a fixed width: plan names embed the
|
|
50
|
+
// product's display name, whose length is not this renderer's to assume.
|
|
51
|
+
const nameWidth = Math.max(...paidPlans.map((plan) => plan.displayName.length)) + 1;
|
|
52
|
+
for (const plan of paidPlans) {
|
|
53
|
+
log(` ${plan.displayName.padEnd(nameWidth)} $${plan.monthlyPriceUsd}/month · ` +
|
|
50
54
|
`${(0, data_provider_1.usageMicrosToDisplayCredits)(plan.includedUsageMicros).toLocaleString()} monthly credits · ` +
|
|
51
55
|
`${(0, data_provider_1.usageMicrosToDisplayCredits)(plan.fiveHourUsageMicros).toLocaleString()} per 5 hours · ` +
|
|
52
56
|
`${plan.concurrentSessions} sessions · ${plan.requestsPerMinute} RPM`);
|
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.renderSkyCodeUsageEvents = renderSkyCodeUsageEvents;
|
|
4
4
|
const core_1 = require("@oclif/core");
|
|
5
|
+
const auth_core_1 = require("@skrr-ai/auth-core");
|
|
5
6
|
const base_command_1 = require("../../../base-command");
|
|
6
7
|
const balance_1 = require("../../../lib/balance");
|
|
7
8
|
class BalanceUsageEvents extends base_command_1.BaseCommand {
|
|
8
|
-
static description =
|
|
9
|
+
static description = `List the ${auth_core_1.FIRST_PARTY_HARNESS.displayName} charges and run/session attribution behind aggregate allowance usage`;
|
|
9
10
|
static examples = [
|
|
10
11
|
'<%= config.bin %> balance usage events',
|
|
11
12
|
'<%= config.bin %> balance usage events --limit 20 --json',
|
|
@@ -44,7 +45,7 @@ class BalanceUsageEvents extends base_command_1.BaseCommand {
|
|
|
44
45
|
}
|
|
45
46
|
exports.default = BalanceUsageEvents;
|
|
46
47
|
function renderSkyCodeUsageEvents(events, log) {
|
|
47
|
-
log(
|
|
48
|
+
log(`${auth_core_1.FIRST_PARTY_HARNESS.displayName} usage events · ${events.ownerType} ${events.ownerId}`);
|
|
48
49
|
log(` Window ${events.from} to ${events.to}`);
|
|
49
50
|
if (events.items.length === 0) {
|
|
50
51
|
log(' No usage events in this window.');
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.renderSkyCodeUsage = renderSkyCodeUsage;
|
|
4
4
|
const core_1 = require("@oclif/core");
|
|
5
|
+
const auth_core_1 = require("@skrr-ai/auth-core");
|
|
5
6
|
const base_command_1 = require("../../base-command");
|
|
6
7
|
const balance_1 = require("../../lib/balance");
|
|
7
8
|
/**
|
|
@@ -40,7 +41,7 @@ class BalanceUsage extends base_command_1.BaseCommand {
|
|
|
40
41
|
}
|
|
41
42
|
exports.default = BalanceUsage;
|
|
42
43
|
function renderSkyCodeUsage(usage, log) {
|
|
43
|
-
log(
|
|
44
|
+
log(`${auth_core_1.FIRST_PARTY_HARNESS.displayName} ${usage.plan ?? 'current'} plan · ${usage.ownerType} ${usage.ownerId}`);
|
|
44
45
|
log(` Monthly used ${(0, balance_1.formatCreditsWithUsd)(usage.monthly.usedUsageMicros)}`);
|
|
45
46
|
log(` Monthly reserved ${(0, balance_1.formatCreditsWithUsd)(usage.monthly.reservedUsageMicros)}`);
|
|
46
47
|
log(` Monthly remaining ${(0, balance_1.formatCreditsWithUsd)(usage.monthly.remainingUsageMicros)}`);
|
|
@@ -23,8 +23,9 @@ class BrowserInstall extends core_1.Command {
|
|
|
23
23
|
async run() {
|
|
24
24
|
const { flags } = await this.parse(BrowserInstall);
|
|
25
25
|
const args = ['install'];
|
|
26
|
-
// Any spelling of the first-party harness is
|
|
27
|
-
//
|
|
26
|
+
// Any ACCEPTED spelling of the first-party harness is handed to the daemon in
|
|
27
|
+
// the wire spelling; anything else — a retired spelling included — is forwarded
|
|
28
|
+
// unchanged for the daemon's own parser to accept or refuse.
|
|
28
29
|
if (flags.harness)
|
|
29
30
|
args.push('--harness', (0, harness_provider_input_1.daemonHarnessArgument)(flags.harness));
|
|
30
31
|
if (flags.config)
|
|
@@ -23,8 +23,9 @@ class BrowserUninstall extends core_1.Command {
|
|
|
23
23
|
async run() {
|
|
24
24
|
const { flags } = await this.parse(BrowserUninstall);
|
|
25
25
|
const args = ['uninstall'];
|
|
26
|
-
// Any spelling of the first-party harness is
|
|
27
|
-
//
|
|
26
|
+
// Any ACCEPTED spelling of the first-party harness is handed to the daemon in
|
|
27
|
+
// the wire spelling; anything else — a retired spelling included — is forwarded
|
|
28
|
+
// unchanged for the daemon's own parser to accept or refuse.
|
|
28
29
|
if (flags.harness)
|
|
29
30
|
args.push('--harness', (0, harness_provider_input_1.daemonHarnessArgument)(flags.harness));
|
|
30
31
|
if (flags.config)
|
|
@@ -201,8 +201,9 @@ class CodeInstall extends base_command_1.BaseCommand {
|
|
|
201
201
|
async installerNote(daemonId) {
|
|
202
202
|
try {
|
|
203
203
|
const res = await (0, api_fetch_1.apiFetch)(`/api/daemons/${encodeURIComponent(daemonId)}/cli-installers`, { credential: this.resolvedCredential });
|
|
204
|
-
// Any spelling: a daemon lists the provider the way it registered it,
|
|
205
|
-
// one that predates or postdates
|
|
204
|
+
// Any accepted spelling: a daemon lists the provider the way it registered it,
|
|
205
|
+
// and during a rename's alias window one that predates or postdates the flip
|
|
206
|
+
// spells it differently.
|
|
206
207
|
const row = (res.providers ?? []).find((p) => (0, auth_core_1.isFirstPartyHarnessProvider)(p.provider));
|
|
207
208
|
const reason = row?.installDisabledReason?.trim();
|
|
208
209
|
if (!reason)
|
|
@@ -46,6 +46,17 @@ export default class HarnessesInstall extends BaseCommand {
|
|
|
46
46
|
* reason the daemon already words. Both are answered before anything runs.
|
|
47
47
|
*/
|
|
48
48
|
private update;
|
|
49
|
+
/**
|
|
50
|
+
* Start an install or update, and survive a gateway that cut the request off.
|
|
51
|
+
*
|
|
52
|
+
* The relay holds the request while the daemon answers, and a gateway can end
|
|
53
|
+
* it first: an update returned HTTP 504 after 21.9s while the job it started
|
|
54
|
+
* ran to success, and the caller was told the outcome was unknown (OSK-10096
|
|
55
|
+
* verifier). The daemon is the only party that knows whether the request
|
|
56
|
+
* arrived, so on a server-side failure we ask it, and follow the job it
|
|
57
|
+
* started rather than reporting a result we do not have.
|
|
58
|
+
*/
|
|
59
|
+
private start;
|
|
49
60
|
/** Follow a job to its end, or report why it could not be followed (and return nothing). */
|
|
50
61
|
private follow;
|
|
51
62
|
/** What the daemon says about this provider right now, best effort. */
|
|
@@ -74,14 +74,9 @@ class HarnessesInstall extends base_command_1.BaseCommand {
|
|
|
74
74
|
await this.update(daemonId, provider, Boolean(flags.json));
|
|
75
75
|
return;
|
|
76
76
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
start = await (0, cli_installers_1.startManagedCliInstall)(daemonId, provider, this.resolvedCredential);
|
|
80
|
-
}
|
|
81
|
-
catch (err) {
|
|
82
|
-
this.handleApiError(err);
|
|
77
|
+
const start = await this.start(daemonId, provider, () => (0, cli_installers_1.startManagedCliInstall)(daemonId, provider, this.resolvedCredential), Boolean(flags.json));
|
|
78
|
+
if (!start)
|
|
83
79
|
return;
|
|
84
|
-
}
|
|
85
80
|
const jobId = start.job?.id;
|
|
86
81
|
if (!start.started || !jobId) {
|
|
87
82
|
// The daemon declined and already knows why. Read its own reason off the
|
|
@@ -163,14 +158,9 @@ class HarnessesInstall extends base_command_1.BaseCommand {
|
|
|
163
158
|
});
|
|
164
159
|
return;
|
|
165
160
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
start = await (0, cli_installers_1.startManagedCliUpdate)(daemonId, provider, this.resolvedCredential);
|
|
169
|
-
}
|
|
170
|
-
catch (err) {
|
|
171
|
-
this.handleApiError(err);
|
|
161
|
+
const start = await this.start(daemonId, provider, () => (0, cli_installers_1.startManagedCliUpdate)(daemonId, provider, this.resolvedCredential), json);
|
|
162
|
+
if (!start)
|
|
172
163
|
return;
|
|
173
|
-
}
|
|
174
164
|
const jobId = start.job?.id;
|
|
175
165
|
if (!start.started || !jobId) {
|
|
176
166
|
this.log(start.alreadyRunning
|
|
@@ -199,6 +189,35 @@ class HarnessesInstall extends base_command_1.BaseCommand {
|
|
|
199
189
|
this.log((0, cli_installers_1.updateOutcomeLine)(job) ??
|
|
200
190
|
`${provider} updated${job.installedVersion ? ` to ${job.installedVersion}` : ''}.`);
|
|
201
191
|
}
|
|
192
|
+
/**
|
|
193
|
+
* Start an install or update, and survive a gateway that cut the request off.
|
|
194
|
+
*
|
|
195
|
+
* The relay holds the request while the daemon answers, and a gateway can end
|
|
196
|
+
* it first: an update returned HTTP 504 after 21.9s while the job it started
|
|
197
|
+
* ran to success, and the caller was told the outcome was unknown (OSK-10096
|
|
198
|
+
* verifier). The daemon is the only party that knows whether the request
|
|
199
|
+
* arrived, so on a server-side failure we ask it, and follow the job it
|
|
200
|
+
* started rather than reporting a result we do not have.
|
|
201
|
+
*/
|
|
202
|
+
async start(daemonId, provider, begin, json) {
|
|
203
|
+
try {
|
|
204
|
+
return await begin();
|
|
205
|
+
}
|
|
206
|
+
catch (err) {
|
|
207
|
+
const status = err.status ?? 0;
|
|
208
|
+
if (status >= 500 || status === 408) {
|
|
209
|
+
const job = await (0, cli_installers_1.jobStartedDespiteTimeout)(daemonId, provider, this.resolvedCredential);
|
|
210
|
+
if (job?.id) {
|
|
211
|
+
if (!json) {
|
|
212
|
+
this.logToStderr(`The request to ${daemonId} did not come back (HTTP ${status}), but the daemon started job ${job.id}. Following it.`);
|
|
213
|
+
}
|
|
214
|
+
return { started: true, job };
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
this.handleApiError(err);
|
|
218
|
+
return undefined;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
202
221
|
/** Follow a job to its end, or report why it could not be followed (and return nothing). */
|
|
203
222
|
async follow(daemonId, jobId, verb, json) {
|
|
204
223
|
const outcome = await (0, cli_installers_1.followManagedCliInstallJob)({
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { BaseCommand } from '../../base-command';
|
|
2
|
+
import { type ManagedCliProviderState } from '../../lib/cli-installers';
|
|
2
3
|
/**
|
|
3
4
|
* What each managed provider's state is on one machine.
|
|
4
5
|
*
|
|
@@ -43,3 +44,12 @@ export default class HarnessesInstallers extends BaseCommand {
|
|
|
43
44
|
*/
|
|
44
45
|
private daemonIdFor;
|
|
45
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* What each installed CLI's update story is, as sentences under the table.
|
|
49
|
+
*
|
|
50
|
+
* Sentences, not a column: an update reason is "the copy inside Devin.app
|
|
51
|
+
* updates with that app", which no column fits. Silent for a daemon that
|
|
52
|
+
* reports no update fields at all — it cannot say, and inventing "no" for it
|
|
53
|
+
* would be worse than nothing.
|
|
54
|
+
*/
|
|
55
|
+
export declare function updateNotes(providers: readonly ManagedCliProviderState[], bin: string): string[];
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.updateNotes = updateNotes;
|
|
3
4
|
const core_1 = require("@oclif/core");
|
|
4
5
|
const base_command_1 = require("../../base-command");
|
|
5
6
|
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
@@ -126,6 +127,14 @@ class HarnessesInstallers extends base_command_1.BaseCommand {
|
|
|
126
127
|
for (const note of notes)
|
|
127
128
|
this.log(` ${note.provider}: ${note.detail}`);
|
|
128
129
|
}
|
|
130
|
+
// The VERSION column is where a reader asks "can I get a newer one", and
|
|
131
|
+
// the answer lived only in `--json` (OSK-10096 verifier).
|
|
132
|
+
const updateLines = updateNotes(providers, this.config.bin);
|
|
133
|
+
if (updateLines.length > 0) {
|
|
134
|
+
this.log('');
|
|
135
|
+
for (const line of updateLines)
|
|
136
|
+
this.log(` ${line}`);
|
|
137
|
+
}
|
|
129
138
|
// A provider the platform knows and this daemon did not mention. Without
|
|
130
139
|
// this it simply is not on the list, which reads as dropped support rather
|
|
131
140
|
// than as an older daemon — `devin` arrived in the 0.8.45 daemon release, so 0.8.35
|
|
@@ -177,3 +186,25 @@ class HarnessesInstallers extends base_command_1.BaseCommand {
|
|
|
177
186
|
}
|
|
178
187
|
}
|
|
179
188
|
exports.default = HarnessesInstallers;
|
|
189
|
+
/**
|
|
190
|
+
* What each installed CLI's update story is, as sentences under the table.
|
|
191
|
+
*
|
|
192
|
+
* Sentences, not a column: an update reason is "the copy inside Devin.app
|
|
193
|
+
* updates with that app", which no column fits. Silent for a daemon that
|
|
194
|
+
* reports no update fields at all — it cannot say, and inventing "no" for it
|
|
195
|
+
* would be worse than nothing.
|
|
196
|
+
*/
|
|
197
|
+
function updateNotes(providers, bin) {
|
|
198
|
+
const lines = [];
|
|
199
|
+
for (const provider of providers) {
|
|
200
|
+
if (provider.updatable === true) {
|
|
201
|
+
lines.push(`${provider.provider}: update it with \`${bin} harnesses install ${provider.provider} --update\``);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
for (const provider of providers) {
|
|
205
|
+
if (provider.updatable === false && provider.installed && provider.updateDisabledReason) {
|
|
206
|
+
lines.push(`${provider.provider}: ${provider.updateDisabledReason}`);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return lines;
|
|
210
|
+
}
|
|
@@ -421,8 +421,9 @@ class HarnessesList extends base_command_1.BaseCommand {
|
|
|
421
421
|
// mode. Materialize that default before the request so JSON cannot quietly
|
|
422
422
|
// return every historical offline row while the table shows seven live ones.
|
|
423
423
|
const status = flags.online ? 'online' : (flags.status ?? (flags.all ? undefined : 'online'));
|
|
424
|
-
// Any spelling of the first-party harness filters the same rows; the
|
|
425
|
-
// asked for the canonical one, which it matches against every
|
|
424
|
+
// Any accepted spelling of the first-party harness filters the same rows; the
|
|
425
|
+
// server is asked for the canonical one, which it matches against every
|
|
426
|
+
// accepted stored spelling.
|
|
426
427
|
const provider = flags.provider ? (0, harness_provider_input_1.canonicalHarnessInput)(flags.provider) : undefined;
|
|
427
428
|
const params = new URLSearchParams();
|
|
428
429
|
const serverStatus = serverStatusParam(status);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { BaseCommand } from '../../../base-command';
|
|
2
|
+
/**
|
|
3
|
+
* `skrr tasks attachments set-role <task> <attachment> --role …`
|
|
4
|
+
*
|
|
5
|
+
* The one way to change what an existing asset IS on a Task. Its real use is
|
|
6
|
+
* promotion: an agent may only upload `evidence` or `deliverable`, because an
|
|
7
|
+
* `input` is forwarded into every future Run of the Task — so when an agent's
|
|
8
|
+
* screenshot should become an input, a person promotes it here. The server
|
|
9
|
+
* refuses the call from an agent, whatever credential it holds, and moves the
|
|
10
|
+
* asset's ledger link with the role.
|
|
11
|
+
*/
|
|
12
|
+
export default class TasksAttachmentsSetRole extends BaseCommand {
|
|
13
|
+
static description: string;
|
|
14
|
+
static examples: string[];
|
|
15
|
+
static args: {
|
|
16
|
+
id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
17
|
+
attachmentId: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
18
|
+
};
|
|
19
|
+
static flags: {
|
|
20
|
+
role: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
21
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
22
|
+
};
|
|
23
|
+
run(): Promise<void>;
|
|
24
|
+
}
|
|
@@ -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
|
+
/**
|
|
7
|
+
* `skrr tasks attachments set-role <task> <attachment> --role …`
|
|
8
|
+
*
|
|
9
|
+
* The one way to change what an existing asset IS on a Task. Its real use is
|
|
10
|
+
* promotion: an agent may only upload `evidence` or `deliverable`, because an
|
|
11
|
+
* `input` is forwarded into every future Run of the Task — so when an agent's
|
|
12
|
+
* screenshot should become an input, a person promotes it here. The server
|
|
13
|
+
* refuses the call from an agent, whatever credential it holds, and moves the
|
|
14
|
+
* asset's ledger link with the role.
|
|
15
|
+
*/
|
|
16
|
+
class TasksAttachmentsSetRole extends base_command_1.BaseCommand {
|
|
17
|
+
static description = "Change an attachment's role (input, evidence, or deliverable). Making an asset an input " +
|
|
18
|
+
'sends it into every future Run of the task, so only a person can change a role.';
|
|
19
|
+
static examples = [
|
|
20
|
+
'<%= config.bin %> tasks attachments set-role <task-id> <attachment-id> --role input',
|
|
21
|
+
'<%= config.bin %> tasks attachments set-role <task-id> <attachment-id> --role evidence --json',
|
|
22
|
+
];
|
|
23
|
+
static args = {
|
|
24
|
+
id: core_1.Args.string({ description: 'Task ID', required: true, ignoreStdin: true }),
|
|
25
|
+
attachmentId: core_1.Args.string({ description: 'Attachment ID', required: true, ignoreStdin: true }),
|
|
26
|
+
};
|
|
27
|
+
static flags = {
|
|
28
|
+
role: core_1.Flags.string({
|
|
29
|
+
required: true,
|
|
30
|
+
options: ['input', 'evidence', 'deliverable'],
|
|
31
|
+
description: 'input (forwarded into every future Run), evidence (supports an Update or Result), or deliverable (the media is the product)',
|
|
32
|
+
}),
|
|
33
|
+
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
34
|
+
};
|
|
35
|
+
async run() {
|
|
36
|
+
this.requireAuth();
|
|
37
|
+
const { args, flags } = await this.parse(TasksAttachmentsSetRole);
|
|
38
|
+
let attachment;
|
|
39
|
+
try {
|
|
40
|
+
attachment = await data_provider_1.dataService.setTaskAttachmentRole({
|
|
41
|
+
taskId: args.id,
|
|
42
|
+
attachmentId: args.attachmentId,
|
|
43
|
+
role: flags.role,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
this.handleApiError(err);
|
|
48
|
+
}
|
|
49
|
+
if (flags.json) {
|
|
50
|
+
this.log(JSON.stringify(attachment, null, 2));
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const name = attachment.originalName || attachment.id;
|
|
54
|
+
const effect = attachment.role === 'input'
|
|
55
|
+
? ' It will be sent into every future Run of this task.'
|
|
56
|
+
: ' It is no longer sent into Runs.';
|
|
57
|
+
this.log(`${name} is now ${attachment.role}.${effect}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
exports.default = TasksAttachmentsSetRole;
|
|
@@ -8,6 +8,7 @@ export default class TasksAttachmentsUpload extends BaseCommand {
|
|
|
8
8
|
static flags: {
|
|
9
9
|
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
10
10
|
file: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
11
|
+
role: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
11
12
|
};
|
|
12
13
|
run(): Promise<void>;
|
|
13
14
|
}
|
|
@@ -1,50 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
const fs = __importStar(require("node:fs"));
|
|
37
|
-
const path = __importStar(require("node:path"));
|
|
38
|
-
const node_buffer_1 = require("node:buffer");
|
|
39
3
|
const core_1 = require("@oclif/core");
|
|
40
|
-
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
41
4
|
const base_command_1 = require("../../../base-command");
|
|
42
|
-
const
|
|
5
|
+
const task_asset_upload_1 = require("../../../lib/task-asset-upload");
|
|
43
6
|
class TasksAttachmentsUpload extends base_command_1.BaseCommand {
|
|
44
7
|
static description = 'Upload a file attachment to a task';
|
|
45
8
|
static examples = [
|
|
46
9
|
'<%= config.bin %> tasks attachments upload <task-id> --file ./report.pdf',
|
|
47
10
|
'<%= config.bin %> tasks attachments upload <task-id> --file ./screenshot.png --json',
|
|
11
|
+
'<%= config.bin %> tasks attachments upload <task-id> --file ./demo.mp4 --role deliverable',
|
|
48
12
|
];
|
|
49
13
|
static args = {
|
|
50
14
|
id: core_1.Args.string({ description: 'Task ID', required: true, ignoreStdin: true }),
|
|
@@ -52,32 +16,34 @@ class TasksAttachmentsUpload extends base_command_1.BaseCommand {
|
|
|
52
16
|
static flags = {
|
|
53
17
|
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
54
18
|
file: core_1.Flags.string({ description: 'Path to the file to upload', required: true }),
|
|
19
|
+
role: core_1.Flags.string({
|
|
20
|
+
description: 'Asset role: evidence (supports an Update/Result), deliverable (the media is the product), or input (forwarded into every future Run — only a person may add one; a person promotes an agent upload with `attachments set-role`). Defaults to evidence when an agent uploads, input when a person does.',
|
|
21
|
+
options: ['input', 'evidence', 'deliverable'],
|
|
22
|
+
}),
|
|
55
23
|
};
|
|
56
24
|
async run() {
|
|
57
25
|
this.requireAuth();
|
|
58
26
|
const { args, flags } = await this.parse(TasksAttachmentsUpload);
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
const buf = fs.readFileSync(filePath);
|
|
64
|
-
const filename = path.basename(filePath);
|
|
65
|
-
const fd = new FormData();
|
|
66
|
-
const mimeType = (0, file_mime_1.mimeTypeForFilename)(filename);
|
|
67
|
-
fd.append('file', new node_buffer_1.Blob([buf], { type: mimeType }), filename);
|
|
68
|
-
let result;
|
|
27
|
+
// The pipeline — buffered vs direct, session vs generic — lives in
|
|
28
|
+
// task-asset-upload.ts so `--attach` on updates/result/complete/comments
|
|
29
|
+
// makes the same routing decisions byte for byte (OSK-9863).
|
|
30
|
+
let asset;
|
|
69
31
|
try {
|
|
70
|
-
|
|
32
|
+
asset = await (0, task_asset_upload_1.uploadTaskAssetFile)({
|
|
33
|
+
taskId: args.id,
|
|
34
|
+
filePath: flags.file,
|
|
35
|
+
role: flags.role,
|
|
36
|
+
});
|
|
71
37
|
}
|
|
72
38
|
catch (err) {
|
|
73
39
|
this.handleApiError(err);
|
|
74
40
|
}
|
|
75
41
|
if (flags.json) {
|
|
76
|
-
this.log(JSON.stringify(
|
|
42
|
+
this.log(JSON.stringify(asset, null, 2));
|
|
77
43
|
return;
|
|
78
44
|
}
|
|
79
|
-
const
|
|
80
|
-
this.log(`Uploaded ${filename}
|
|
45
|
+
const dedup = asset.deduplicated ? ' (deduplicated — already on the task)' : '';
|
|
46
|
+
this.log(`Uploaded ${asset.filename} → attachment ${asset.id}${dedup}`);
|
|
81
47
|
}
|
|
82
48
|
}
|
|
83
49
|
exports.default = TasksAttachmentsUpload;
|
|
@@ -16,6 +16,7 @@ export default class TasksCommentsAdd extends BaseCommand {
|
|
|
16
16
|
'parent-comment': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
17
17
|
'anchor-mark-id': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
18
18
|
'anchor-quote': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
19
|
+
attach: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
19
20
|
};
|
|
20
21
|
run(): Promise<void>;
|
|
21
22
|
/**
|
|
@@ -1,4 +1,37 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
36
|
const node_crypto_1 = require("node:crypto");
|
|
4
37
|
const core_1 = require("@oclif/core");
|
|
@@ -55,6 +88,11 @@ class TasksCommentsAdd extends base_command_1.BaseCommand {
|
|
|
55
88
|
'anchor-quote': core_1.Flags.string({
|
|
56
89
|
description: 'Captured quote for the anchor (≤1000 chars; truncated to 500 to match the editor). Enables inline-comment mode when used without --anchor-mark-id.',
|
|
57
90
|
}),
|
|
91
|
+
attach: core_1.Flags.string({
|
|
92
|
+
multiple: true,
|
|
93
|
+
description: 'Upload a file as a Task asset and reference it in the comment body ' +
|
|
94
|
+
'(``, resolved to a signed URL at read time). Repeatable.',
|
|
95
|
+
}),
|
|
58
96
|
};
|
|
59
97
|
async run() {
|
|
60
98
|
this.requireAuth();
|
|
@@ -107,9 +145,36 @@ class TasksCommentsAdd extends base_command_1.BaseCommand {
|
|
|
107
145
|
// mentionedAgentIds, reopen, and interrupt are preserved. Boolean flags
|
|
108
146
|
// default to false; only pass them through when actually set so they
|
|
109
147
|
// don't clobber a `true` value from the JSON file.
|
|
148
|
+
// --attach: upload first, then append `task-asset:` references to the
|
|
149
|
+
// body — comments store stable asset ids, not URLs (OSK-9856/9863).
|
|
150
|
+
let attachSuffix = '';
|
|
151
|
+
if (flags.attach?.length) {
|
|
152
|
+
const { uploadTaskAssetFile, taskAssetMarkdownRef } = await Promise.resolve().then(() => __importStar(require('../../../lib/task-asset-upload')));
|
|
153
|
+
const refs = [];
|
|
154
|
+
for (const filePath of flags.attach) {
|
|
155
|
+
try {
|
|
156
|
+
const asset = await uploadTaskAssetFile({
|
|
157
|
+
taskId: task.id,
|
|
158
|
+
filePath,
|
|
159
|
+
role: 'evidence',
|
|
160
|
+
});
|
|
161
|
+
refs.push(taskAssetMarkdownRef(asset));
|
|
162
|
+
}
|
|
163
|
+
catch (err) {
|
|
164
|
+
this.error(`--attach failed: ${err.message}`, { exit: 1 });
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
if (refs.length)
|
|
168
|
+
attachSuffix = `\n\n${refs.join('\n')}`;
|
|
169
|
+
}
|
|
110
170
|
const mentionedFromFlag = flags['mention-agent'];
|
|
171
|
+
const baseBody = flags.body ?? (typeof commentBody.body === 'string' ? commentBody.body : undefined);
|
|
111
172
|
const data = (0, prompt_1.mergeDefined)(commentBody, {
|
|
112
|
-
body:
|
|
173
|
+
body: baseBody
|
|
174
|
+
? `${baseBody}${attachSuffix}`
|
|
175
|
+
: attachSuffix
|
|
176
|
+
? attachSuffix.trimStart()
|
|
177
|
+
: undefined,
|
|
113
178
|
mentionedAgentIds: Array.isArray(mentionedFromFlag) && mentionedFromFlag.length > 0
|
|
114
179
|
? mentionedFromFlag
|
|
115
180
|
: undefined,
|
|
@@ -163,7 +228,7 @@ class TasksCommentsAdd extends base_command_1.BaseCommand {
|
|
|
163
228
|
? await (0, api_fetch_1.apiFetch)(sessionPath, {
|
|
164
229
|
method: 'POST',
|
|
165
230
|
body: {
|
|
166
|
-
body:
|
|
231
|
+
body: data.body,
|
|
167
232
|
...(mentioned ? { mentionedAgentIds: mentioned } : {}),
|
|
168
233
|
},
|
|
169
234
|
headers: { 'X-Idempotency-Key': idempotencyKey },
|
|
@@ -26,6 +26,7 @@ export default class TasksComplete extends BaseCommand {
|
|
|
26
26
|
'structured-json': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
27
27
|
deliverable: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
28
28
|
evidence: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
29
|
+
attach: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
29
30
|
remaining: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
30
31
|
'source-run': import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
31
32
|
'run-id': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|