@skrr-ai/cli 0.1.8 → 0.1.10
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 +27 -0
- package/dist/base-command.js +83 -11
- package/dist/commands/agent/message/send.js +1 -1
- package/dist/commands/agents/chat.d.ts +1 -1
- package/dist/commands/agents/chat.js +1 -1
- package/dist/commands/browser/install.d.ts +1 -1
- package/dist/commands/browser/install.js +10 -2
- package/dist/commands/browser/mcp-config.js +3 -1
- package/dist/commands/browser/skill/show.js +1 -1
- package/dist/commands/browser/status.js +4 -1
- package/dist/commands/browser/uninstall.d.ts +1 -1
- package/dist/commands/browser/uninstall.js +10 -2
- package/dist/commands/browser.d.ts +1 -1
- package/dist/commands/browser.js +3 -3
- package/dist/commands/code/index.js +6 -3
- package/dist/commands/code/install.d.ts +61 -0
- package/dist/commands/code/install.js +247 -0
- package/dist/commands/code/oversky-agent.d.ts +2 -1
- package/dist/commands/code/oversky-agent.js +12 -8
- package/dist/commands/commands.js +1 -1
- package/dist/commands/context.js +1 -1
- package/dist/commands/create-token.js +1 -1
- package/dist/commands/daemon/byok.d.ts +1 -0
- package/dist/commands/daemon/byok.js +14 -1
- package/dist/commands/daemon/index.js +18 -7
- package/dist/commands/daemon/install.d.ts +1 -0
- package/dist/commands/daemon/install.js +22 -3
- package/dist/commands/daemon/logs.d.ts +1 -0
- package/dist/commands/daemon/logs.js +4 -0
- package/dist/commands/daemon/start.d.ts +1 -0
- package/dist/commands/daemon/start.js +15 -2
- package/dist/commands/daemon/status.d.ts +1 -0
- package/dist/commands/daemon/status.js +14 -1
- package/dist/commands/daemon/stop.d.ts +1 -0
- package/dist/commands/daemon/stop.js +14 -1
- package/dist/commands/daemon/uninstall.d.ts +1 -0
- package/dist/commands/daemon/uninstall.js +15 -2
- package/dist/commands/daemon/usage.d.ts +1 -0
- package/dist/commands/daemon/usage.js +5 -1
- package/dist/commands/doctor.js +2 -2
- package/dist/commands/github/allow-tools.d.ts +1 -0
- package/dist/commands/github/app/install.d.ts +1 -0
- package/dist/commands/github/app/status.d.ts +1 -0
- package/dist/commands/github/connect.d.ts +1 -0
- package/dist/commands/github/connections.d.ts +1 -0
- package/dist/commands/github/disconnect.d.ts +1 -0
- package/dist/commands/github/finalize.d.ts +1 -0
- package/dist/commands/github/reconnect.d.ts +1 -0
- package/dist/commands/github/run.d.ts +1 -0
- package/dist/commands/github/tools.d.ts +1 -0
- package/dist/commands/goals/create.js +2 -2
- package/dist/commands/goals/show.js +5 -0
- package/dist/commands/harnesses/list.js +14 -3
- package/dist/commands/harnesses/show.js +14 -0
- package/dist/commands/instructions/activate.js +1 -1
- package/dist/commands/instructions/archive-version.js +1 -1
- package/dist/commands/instructions/delete.js +1 -1
- package/dist/commands/instructions/diff.js +1 -1
- package/dist/commands/instructions/install.js +7 -1
- package/dist/commands/instructions/restore.js +1 -1
- package/dist/commands/instructions/show.js +17 -1
- package/dist/commands/instructions/update.js +1 -1
- package/dist/commands/integrations/connections/connect.d.ts +1 -0
- package/dist/commands/integrations/connections/disconnect.d.ts +1 -0
- package/dist/commands/integrations/connections/finalize.d.ts +1 -0
- package/dist/commands/integrations/connections/list.d.ts +1 -0
- package/dist/commands/integrations/connections/reconnect.d.ts +1 -0
- package/dist/commands/integrations/execute.d.ts +1 -0
- package/dist/commands/integrations/search.d.ts +1 -0
- package/dist/commands/integrations/toolkits.d.ts +1 -0
- package/dist/commands/integrations/tools/allow.d.ts +1 -0
- package/dist/commands/integrations/tools/list.d.ts +1 -0
- package/dist/commands/list-daemons.d.ts +2 -7
- package/dist/commands/list-daemons.js +13 -13
- package/dist/commands/login.js +78 -33
- package/dist/commands/logout.js +52 -1
- package/dist/commands/machines/hosted/start.js +1 -1
- package/dist/commands/pair.js +2 -2
- package/dist/commands/projects/create.js +6 -1
- package/dist/commands/projects/tasks.js +6 -1
- package/dist/commands/revoke-daemon.js +6 -2
- package/dist/commands/set-capabilities.js +6 -2
- package/dist/commands/skills/install.js +1 -1
- package/dist/commands/skills/library.js +2 -2
- package/dist/commands/spaces/create.js +6 -2
- package/dist/commands/tasks/complete.d.ts +1 -1
- package/dist/commands/tasks/complete.js +21 -8
- package/dist/commands/tasks/create.js +4 -1
- package/dist/commands/tasks/current.js +1 -1
- package/dist/commands/tasks/delete.d.ts +1 -0
- package/dist/commands/tasks/delete.js +9 -0
- package/dist/commands/tasks/export.js +5 -1
- package/dist/commands/tasks/follow-up.js +2 -1
- package/dist/commands/tasks/list.js +5 -1
- package/dist/commands/tasks/pr.js +1 -1
- package/dist/commands/tasks/show.js +10 -1
- package/dist/commands/tasks/triage.js +2 -1
- package/dist/commands/tasks/update.js +4 -1
- package/dist/commands/tasks/upsert.js +4 -1
- package/dist/commands/usage.js +1 -1
- package/dist/commands/whoami.js +4 -1
- package/dist/lib/agentic-stream.js +21 -1
- package/dist/lib/api-fetch.d.ts +1 -1
- package/dist/lib/api-fetch.js +1 -1
- package/dist/lib/auth-core-init.js +23 -3
- package/dist/lib/auth-storage.d.ts +0 -12
- package/dist/lib/auth-storage.js +37 -2
- package/dist/lib/config.d.ts +43 -3
- package/dist/lib/config.js +391 -31
- package/dist/lib/created-line.d.ts +22 -0
- package/dist/lib/created-line.js +25 -0
- package/dist/lib/daemon-binding.d.ts +29 -0
- package/dist/lib/daemon-binding.js +63 -0
- package/dist/lib/daemon-ref.d.ts +31 -0
- package/dist/lib/daemon-ref.js +47 -0
- package/dist/lib/daemonBroker.js +1 -1
- package/dist/lib/delegated-cli.js +3 -3
- package/dist/lib/exec-oversky.d.ts +18 -1
- package/dist/lib/exec-oversky.js +21 -4
- package/dist/lib/html-text.d.ts +15 -0
- package/dist/lib/html-text.js +40 -0
- package/dist/lib/keychain.d.ts +43 -0
- package/dist/lib/keychain.js +145 -4
- package/dist/lib/login.js +3 -3
- package/dist/lib/node-adapter.js +1 -1
- package/dist/lib/oauthLogin.js +17 -6
- package/dist/lib/sky-code-agent.d.ts +1 -1
- package/dist/lib/sky-code-agent.js +8 -8
- package/dist/lib/sky-code-broker.js +18 -2
- package/dist/lib/sky-code-doctor.js +120 -4
- package/dist/lib/sky-code-managed.d.ts +12 -0
- package/dist/lib/sky-code-managed.js +21 -7
- package/dist/lib/sky-code.d.ts +16 -1
- package/dist/lib/sky-code.js +110 -7
- package/dist/lib/task-execution.js +4 -11
- package/dist/lib/tasks.d.ts +1 -0
- package/dist/lib/tasks.js +9 -6
- package/dist/lib/update-check.js +1 -1
- package/dist/lib/usage-discovery.js +1 -1
- package/dist/lib/web-url.js +12 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/credentialResolver.d.ts +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/credentialResolver.js +2 -2
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.d.ts +1 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.js +13 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/kek/linux.js +16 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/legacyStatePreflight.d.ts +0 -9
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/legacyStatePreflight.js +18 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/loginLocalhost.js +3 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/messages.js +3 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/runtime.d.ts +7 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/skyCodeChannels.d.ts +96 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/skyCodeChannels.js +115 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/credentialResolver.d.ts +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/credentialResolver.js +2 -2
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.d.ts +1 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.js +1 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/kek/linux.js +16 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/legacyStatePreflight.d.ts +0 -9
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/legacyStatePreflight.js +18 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/loginLocalhost.js +3 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/messages.js +3 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/runtime.d.ts +7 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/skyCodeChannels.d.ts +96 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/skyCodeChannels.js +107 -0
- package/dist/node_modules/@skrr-ai/auth-core/package.json +1 -1
- package/dist/node_modules/@skrr-ai/data-provider/index.js +4206 -4191
- package/dist/node_modules/@skrr-ai/inference-broker/dist/cjs/managed-inference-broker.js +2 -2
- package/dist/node_modules/@skrr-ai/inference-broker/dist/esm/managed-inference-broker.js +2 -2
- package/oclif.manifest.json +7969 -1397
- package/package.json +22 -19
package/dist/base-command.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Command, Flags, type Interfaces } from '@oclif/core';
|
|
2
|
+
export { resolveProfileFromArgv } from './lib/keychain';
|
|
2
3
|
import { type AssigneeResolution, type MemberKind, type SpaceMember } from './lib/assignee-resolver';
|
|
3
4
|
import { type CliConfig } from './lib/config';
|
|
4
5
|
import { type OutboxMethod } from './lib/outbox';
|
|
@@ -56,6 +57,7 @@ export declare abstract class BaseCommand extends Command {
|
|
|
56
57
|
bare: Interfaces.BooleanFlag<boolean>;
|
|
57
58
|
token: Interfaces.OptionFlag<string | undefined, Interfaces.CustomOptions>;
|
|
58
59
|
workspace: Interfaces.OptionFlag<string | undefined, Interfaces.CustomOptions>;
|
|
60
|
+
profile: Interfaces.OptionFlag<string | undefined, Interfaces.CustomOptions>;
|
|
59
61
|
};
|
|
60
62
|
protected cliConfig: CliConfig;
|
|
61
63
|
/**
|
|
@@ -393,5 +395,30 @@ export declare function describeAssigneeNotInSpace(serverMessage: string | undef
|
|
|
393
395
|
*
|
|
394
396
|
* Exported for tests.
|
|
395
397
|
*/
|
|
398
|
+
/**
|
|
399
|
+
* What a 403 means, given whether the server said anything.
|
|
400
|
+
*
|
|
401
|
+
* Exported and pure so the wording is testable without an oclif runtime — the
|
|
402
|
+
* convention `isRetryableFailure` follows below.
|
|
403
|
+
*
|
|
404
|
+
* A 403 WITH a body is the API deciding, and it says why; we relay it. A 403
|
|
405
|
+
* with NO body did not come from the API — every application 403 in this
|
|
406
|
+
* codebase carries a message — so it is the edge refusing the request before it
|
|
407
|
+
* arrived, and the two must not share a sentence.
|
|
408
|
+
*
|
|
409
|
+
* This used to assert "your account does not have access to this resource" for
|
|
410
|
+
* both. For an edge refusal that names a cause this process never observed, and
|
|
411
|
+
* it is the expensive kind of wrong: it sends the user to audit their
|
|
412
|
+
* membership, their role and their token, which is the one place the problem is
|
|
413
|
+
* not. Dogfooded as OSK-263 — `skrr tasks create` refused a task description
|
|
414
|
+
* containing a dotted AWS-credentials path, in a project the same session had
|
|
415
|
+
* created a minute earlier, as an ADMIN who owned the space, and finding the
|
|
416
|
+
* real cause took a line-by-line bisect of the description body.
|
|
417
|
+
*
|
|
418
|
+
* The 404 branch has always done the honest thing (`bodyMessage || 'Not
|
|
419
|
+
* found.'`, which claims nothing); this brings 403 into line and adds the one
|
|
420
|
+
* lead worth having.
|
|
421
|
+
*/
|
|
422
|
+
export declare function describeForbidden(bodyMessage?: string | null): string;
|
|
396
423
|
export declare function isRetryableFailure(status: number | undefined, body: Record<string, unknown> | null): boolean;
|
|
397
424
|
export { Flags };
|
package/dist/base-command.js
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Flags = exports.BaseCommand = void 0;
|
|
3
|
+
exports.Flags = exports.BaseCommand = exports.resolveProfileFromArgv = void 0;
|
|
4
4
|
exports.assigneePayloadNeedsResolution = assigneePayloadNeedsResolution;
|
|
5
5
|
exports.parseGlobalFlags = parseGlobalFlags;
|
|
6
6
|
exports.withSubject = withSubject;
|
|
7
7
|
exports.describeHarnessUnavailable = describeHarnessUnavailable;
|
|
8
8
|
exports.describeAssigneeNotInSpace = describeAssigneeNotInSpace;
|
|
9
|
+
exports.describeForbidden = describeForbidden;
|
|
9
10
|
exports.isRetryableFailure = isRetryableFailure;
|
|
10
11
|
const core_1 = require("@oclif/core");
|
|
11
12
|
Object.defineProperty(exports, "Flags", { enumerable: true, get: function () { return core_1.Flags; } });
|
|
13
|
+
// Re-exported from its home in `lib/keychain`, beside the other profile
|
|
14
|
+
// functions. It lived here while `init()` was its only caller; a lib module
|
|
15
|
+
// needing it would otherwise have to import the command base class, and with
|
|
16
|
+
// it the whole auth stack, to read two strings out of argv.
|
|
17
|
+
var keychain_1 = require("./lib/keychain");
|
|
18
|
+
Object.defineProperty(exports, "resolveProfileFromArgv", { enumerable: true, get: function () { return keychain_1.resolveProfileFromArgv; } });
|
|
12
19
|
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
13
20
|
const auth_core_1 = require("@skrr-ai/auth-core");
|
|
14
21
|
const assignee_resolver_1 = require("./lib/assignee-resolver");
|
|
@@ -16,7 +23,7 @@ const task_ref_resolver_1 = require("./lib/task-ref-resolver");
|
|
|
16
23
|
const space_resolver_1 = require("./lib/space-resolver");
|
|
17
24
|
const projects_1 = require("./lib/projects");
|
|
18
25
|
const config_1 = require("./lib/config");
|
|
19
|
-
const
|
|
26
|
+
const keychain_2 = require("./lib/keychain");
|
|
20
27
|
const outbox_1 = require("./lib/outbox");
|
|
21
28
|
const node_adapter_1 = require("./lib/node-adapter");
|
|
22
29
|
const migrate_1 = require("./lib/migrate");
|
|
@@ -96,6 +103,10 @@ class BaseCommand extends core_1.Command {
|
|
|
96
103
|
workspace: core_1.Flags.string({
|
|
97
104
|
description: 'Workspace ID for workspace-scoped requests (also sets X-Workspace-Id).',
|
|
98
105
|
}),
|
|
106
|
+
profile: core_1.Flags.string({
|
|
107
|
+
description: 'Which stored session to use. Each profile keeps its own credential and deployment, ' +
|
|
108
|
+
'so signing into one does not sign you out of another. Also OVERSKY_PROFILE.',
|
|
109
|
+
}),
|
|
99
110
|
};
|
|
100
111
|
cliConfig;
|
|
101
112
|
/**
|
|
@@ -108,6 +119,19 @@ class BaseCommand extends core_1.Command {
|
|
|
108
119
|
bareMode = false;
|
|
109
120
|
async init() {
|
|
110
121
|
await super.init();
|
|
122
|
+
// The profile is resolved from raw argv, BEFORE oclif parses anything.
|
|
123
|
+
//
|
|
124
|
+
// It has to be. `parseBaseFlags()` runs far below, after migration and
|
|
125
|
+
// after the credential machinery has already read the keychain — and the
|
|
126
|
+
// profile decides WHICH keychain service and WHICH config file all of that
|
|
127
|
+
// touches. Waiting for the parser would mean choosing a profile after
|
|
128
|
+
// having already read the wrong one's credential.
|
|
129
|
+
//
|
|
130
|
+
// The daemon has the same constraint and solves it with commander's
|
|
131
|
+
// `preAction` hook; oclif has no equivalent that beats `init()`, so this
|
|
132
|
+
// scans argv itself. The flag is still declared in `baseFlags` above, which
|
|
133
|
+
// is what puts it in `--help` and keeps oclif from rejecting it.
|
|
134
|
+
(0, keychain_2.setActiveProfile)((0, keychain_2.resolveProfileFromArgv)(this.argv) ?? process.env.OVERSKY_PROFILE ?? '');
|
|
111
135
|
// A daemon-stamped autonomous process is a separate principal, not a
|
|
112
136
|
// convenient place to inherit the user's CLI login. Resolve this before
|
|
113
137
|
// touching migration, Keychain/file auth, refresh, or daemon auto-broker
|
|
@@ -119,7 +143,7 @@ class BaseCommand extends core_1.Command {
|
|
|
119
143
|
const delegatedCredential = await (0, delegated_cli_1.fetchDelegatedCliCredential)();
|
|
120
144
|
if (!delegatedCredential) {
|
|
121
145
|
this.failWithCliError({
|
|
122
|
-
message: 'Daemon delegated
|
|
146
|
+
message: 'Daemon delegated skrr credential is unavailable.',
|
|
123
147
|
code: 'DELEGATED_CLI_CREDENTIAL_UNAVAILABLE',
|
|
124
148
|
exit: 75,
|
|
125
149
|
retryable: true,
|
|
@@ -130,7 +154,7 @@ class BaseCommand extends core_1.Command {
|
|
|
130
154
|
}
|
|
131
155
|
catch (err) {
|
|
132
156
|
this.failWithCliError({
|
|
133
|
-
message: `Daemon delegated
|
|
157
|
+
message: `Daemon delegated skrr credential is unavailable: ${err.message}`,
|
|
134
158
|
code: 'DELEGATED_CLI_CREDENTIAL_UNAVAILABLE',
|
|
135
159
|
exit: 75,
|
|
136
160
|
retryable: true,
|
|
@@ -269,7 +293,7 @@ class BaseCommand extends core_1.Command {
|
|
|
269
293
|
// The user is about to see "Not signed in" — give them the
|
|
270
294
|
// exact fix. One stderr line so it doesn't pollute --json
|
|
271
295
|
// consumers on stdout.
|
|
272
|
-
process.stderr.write(`[
|
|
296
|
+
process.stderr.write(`[skrr] Local skrr runtime is logged in to ${autoResult.outcome.daemonServerUrl}, ` +
|
|
273
297
|
`but skrr is configured for ${this.cliConfig.baseURL}. ` +
|
|
274
298
|
`Run \`skrr login --base-url ${autoResult.outcome.daemonServerUrl}\` to use the daemon.\n`);
|
|
275
299
|
}
|
|
@@ -277,12 +301,12 @@ class BaseCommand extends core_1.Command {
|
|
|
277
301
|
}
|
|
278
302
|
if (!this.resolvedCredential.token && ignoredStoredCredential) {
|
|
279
303
|
if (ignoredStoredCredential.originStatus === 'mismatch') {
|
|
280
|
-
process.stderr.write(`[
|
|
304
|
+
process.stderr.write(`[skrr] Ignoring stored credentials issued by ${ignoredStoredCredential.storedServerOrigin}; ` +
|
|
281
305
|
`skrr is configured for ${this.cliConfig.baseURL}. Run \`skrr login --base-url ${this.cliConfig.baseURL}\` ` +
|
|
282
306
|
`or switch back to the issuing server.\n`);
|
|
283
307
|
}
|
|
284
308
|
else if (ignoredStoredCredential.originStatus === 'unbound') {
|
|
285
|
-
process.stderr.write(`[
|
|
309
|
+
process.stderr.write(`[skrr] Ignoring legacy credentials that are not bound to a server. ` +
|
|
286
310
|
`Run \`skrr login --base-url ${this.cliConfig.baseURL}\` once to bind a fresh session.\n`);
|
|
287
311
|
}
|
|
288
312
|
}
|
|
@@ -809,7 +833,7 @@ class BaseCommand extends core_1.Command {
|
|
|
809
833
|
this.failWithCliError({
|
|
810
834
|
message: say(presentedCiToken
|
|
811
835
|
? `Authentication failed: this is an \`osk_ci_*\` token, which only bootstraps a ` +
|
|
812
|
-
`daemon (\`OVERSKY_TOKEN=<token>
|
|
836
|
+
`daemon (\`OVERSKY_TOKEN=<token> skrrd start\`). ${this.config.bin} commands do ` +
|
|
813
837
|
`not accept it — sign in with \`${this.config.bin} login\` instead.`
|
|
814
838
|
: `Authentication failed. Run \`${this.config.bin} login\` to sign in again.`),
|
|
815
839
|
code: bodyCode || 'AUTHENTICATION_FAILED',
|
|
@@ -819,8 +843,24 @@ class BaseCommand extends core_1.Command {
|
|
|
819
843
|
});
|
|
820
844
|
}
|
|
821
845
|
else if (e.status === 403) {
|
|
846
|
+
// A 403 WITH a body is the API deciding; it says why, and we relay it.
|
|
847
|
+
//
|
|
848
|
+
// A 403 with NO body did not come from the API — every application 403
|
|
849
|
+
// here carries a message — so it is the edge refusing the request before
|
|
850
|
+
// it arrived. Asserting "your account does not have access" for that case
|
|
851
|
+
// is a cause this process never observed, and it is the expensive kind of
|
|
852
|
+
// wrong: it sends the user to audit their membership, their role and
|
|
853
|
+
// their token, which is the one place the problem is not.
|
|
854
|
+
//
|
|
855
|
+
// Dogfooded (OSK-263): `skrr tasks create` refused a task description
|
|
856
|
+
// containing a dotted AWS-credentials path, in a project the same
|
|
857
|
+
// session had created a minute earlier, as an ADMIN who owned the space.
|
|
858
|
+
// Finding it took a line-by-line bisect of the body, because the message
|
|
859
|
+
// named a cause and the cause was fiction. The 404 branch below has
|
|
860
|
+
// always done the honest thing — `bodyMessage || 'Not found.'`, which
|
|
861
|
+
// claims nothing.
|
|
822
862
|
this.failWithCliError({
|
|
823
|
-
message: say(bodyMessage
|
|
863
|
+
message: say(describeForbidden(bodyMessage)),
|
|
824
864
|
code: bodyCode || 'FORBIDDEN',
|
|
825
865
|
status: e.status,
|
|
826
866
|
exit: 3,
|
|
@@ -931,7 +971,7 @@ class BaseCommand extends core_1.Command {
|
|
|
931
971
|
*/
|
|
932
972
|
noteControlPlaneOutage(status) {
|
|
933
973
|
try {
|
|
934
|
-
(0, outbox_1.recordIncident)({ baseURL: this.cliConfig.baseURL, status }, (0,
|
|
974
|
+
(0, outbox_1.recordIncident)({ baseURL: this.cliConfig.baseURL, status }, (0, keychain_2.getActiveProfile)());
|
|
935
975
|
}
|
|
936
976
|
catch {
|
|
937
977
|
/* the surface is a convenience; never let it mask the real error */
|
|
@@ -987,7 +1027,7 @@ class BaseCommand extends core_1.Command {
|
|
|
987
1027
|
...(e.code ? { code: e.code } : {}),
|
|
988
1028
|
message: e.message || 'control plane unavailable',
|
|
989
1029
|
},
|
|
990
|
-
}, (0,
|
|
1030
|
+
}, (0, keychain_2.getActiveProfile)());
|
|
991
1031
|
queuedId = entry.id;
|
|
992
1032
|
}
|
|
993
1033
|
catch {
|
|
@@ -1216,6 +1256,38 @@ const TERMINAL_ERROR_CODES = new Set(['task_output_required', 'task_output_not_a
|
|
|
1216
1256
|
*
|
|
1217
1257
|
* Exported for tests.
|
|
1218
1258
|
*/
|
|
1259
|
+
/**
|
|
1260
|
+
* What a 403 means, given whether the server said anything.
|
|
1261
|
+
*
|
|
1262
|
+
* Exported and pure so the wording is testable without an oclif runtime — the
|
|
1263
|
+
* convention `isRetryableFailure` follows below.
|
|
1264
|
+
*
|
|
1265
|
+
* A 403 WITH a body is the API deciding, and it says why; we relay it. A 403
|
|
1266
|
+
* with NO body did not come from the API — every application 403 in this
|
|
1267
|
+
* codebase carries a message — so it is the edge refusing the request before it
|
|
1268
|
+
* arrived, and the two must not share a sentence.
|
|
1269
|
+
*
|
|
1270
|
+
* This used to assert "your account does not have access to this resource" for
|
|
1271
|
+
* both. For an edge refusal that names a cause this process never observed, and
|
|
1272
|
+
* it is the expensive kind of wrong: it sends the user to audit their
|
|
1273
|
+
* membership, their role and their token, which is the one place the problem is
|
|
1274
|
+
* not. Dogfooded as OSK-263 — `skrr tasks create` refused a task description
|
|
1275
|
+
* containing a dotted AWS-credentials path, in a project the same session had
|
|
1276
|
+
* created a minute earlier, as an ADMIN who owned the space, and finding the
|
|
1277
|
+
* real cause took a line-by-line bisect of the description body.
|
|
1278
|
+
*
|
|
1279
|
+
* The 404 branch has always done the honest thing (`bodyMessage || 'Not
|
|
1280
|
+
* found.'`, which claims nothing); this brings 403 into line and adds the one
|
|
1281
|
+
* lead worth having.
|
|
1282
|
+
*/
|
|
1283
|
+
function describeForbidden(bodyMessage) {
|
|
1284
|
+
if (bodyMessage)
|
|
1285
|
+
return bodyMessage;
|
|
1286
|
+
return ('Forbidden: the server refused this request and gave no reason. That usually means an ' +
|
|
1287
|
+
'edge rule rejected it before it reached the API rather than a permission you lack — if ' +
|
|
1288
|
+
'you can read this resource elsewhere, try again with less of the request body (a path ' +
|
|
1289
|
+
'or token-shaped string in your text is enough to trigger one).');
|
|
1290
|
+
}
|
|
1219
1291
|
function isRetryableFailure(status, body) {
|
|
1220
1292
|
const declared = body?.retryable;
|
|
1221
1293
|
if (typeof declared === 'boolean')
|
|
@@ -527,7 +527,7 @@ function messageSegmentationAdvisory({ destination, text, followingParts, }) {
|
|
|
527
527
|
return undefined;
|
|
528
528
|
if (text.length <= exports.OWNER_DM_SEGMENTATION_SOFT_LIMIT)
|
|
529
529
|
return undefined;
|
|
530
|
-
return (`[
|
|
530
|
+
return (`[skrr] Owner-DM message is ${text.length} characters. It may read better as 2–4 short thoughts: ` +
|
|
531
531
|
'use --part with one explicit --idempotency-key. This is only an advisory; ' +
|
|
532
532
|
'use --no-message-lint to suppress it.');
|
|
533
533
|
}
|
|
@@ -59,7 +59,7 @@ export default class AgentsChat extends BaseCommand {
|
|
|
59
59
|
/**
|
|
60
60
|
* OSK-2946 — a task reference sitting in the prompt with no binding.
|
|
61
61
|
*
|
|
62
|
-
* Both reported Codex sessions named
|
|
62
|
+
* Both reported Codex sessions named a skrr task UUID in the prompt, but
|
|
63
63
|
* the daemon environment exposed `OVERSKY_SESSION_TASK_CONTEXT=main_chat` with
|
|
64
64
|
* no `OVERSKY_SESSION_TASK_ID`, so `skrr tasks show` (no id) answered
|
|
65
65
|
* `TASK_CONTEXT_MISSING`. Both agents then spent large context on registry /
|
|
@@ -114,7 +114,7 @@ class AgentsChat extends base_command_1.BaseCommand {
|
|
|
114
114
|
/**
|
|
115
115
|
* OSK-2946 — a task reference sitting in the prompt with no binding.
|
|
116
116
|
*
|
|
117
|
-
* Both reported Codex sessions named
|
|
117
|
+
* Both reported Codex sessions named a skrr task UUID in the prompt, but
|
|
118
118
|
* the daemon environment exposed `OVERSKY_SESSION_TASK_CONTEXT=main_chat` with
|
|
119
119
|
* no `OVERSKY_SESSION_TASK_ID`, so `skrr tasks show` (no id) answered
|
|
120
120
|
* `TASK_CONTEXT_MISSING`. Both agents then spent large context on registry /
|
|
@@ -2,7 +2,7 @@ import { Command } from '@oclif/core';
|
|
|
2
2
|
export default class BrowserInstall extends Command {
|
|
3
3
|
static description: string;
|
|
4
4
|
static flags: {
|
|
5
|
-
harness: import("@oclif/core/lib/interfaces").OptionFlag<string
|
|
5
|
+
harness: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
6
6
|
config: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
7
7
|
'dry-run': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
8
8
|
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
@@ -3,9 +3,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const core_1 = require("@oclif/core");
|
|
4
4
|
const browser_1 = require("../browser");
|
|
5
5
|
class BrowserInstall extends core_1.Command {
|
|
6
|
-
static description = 'Add a sentinel-owned
|
|
6
|
+
static description = 'Add a sentinel-owned skrr Browser MCP entry without overwriting user configuration';
|
|
7
7
|
static flags = {
|
|
8
|
-
harness: core_1.Flags.string({
|
|
8
|
+
harness: core_1.Flags.string({
|
|
9
|
+
// The default and the --config exclusion are both enforced by the
|
|
10
|
+
// runtime this forwards to. Stating them only there meant a bare
|
|
11
|
+
// `skrr browser install` edited every detected harness config with
|
|
12
|
+
// nothing in this help to say so.
|
|
13
|
+
description: 'all, claude, codex, generic, or sky-code. `all` touches every detected ' +
|
|
14
|
+
'harness config and cannot be combined with --config.',
|
|
15
|
+
default: 'all',
|
|
16
|
+
}),
|
|
9
17
|
config: core_1.Flags.string({ description: 'Explicit config file for a generic harness' }),
|
|
10
18
|
'dry-run': core_1.Flags.boolean({ description: 'Show the intended edit without writing it' }),
|
|
11
19
|
json: core_1.Flags.boolean({ description: 'Output JSON' }),
|
|
@@ -3,7 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const core_1 = require("@oclif/core");
|
|
4
4
|
const browser_1 = require("../browser");
|
|
5
5
|
class BrowserMcpConfig extends core_1.Command {
|
|
6
|
-
static description = 'Print the copyable stdio MCP configuration for a generic harness'
|
|
6
|
+
static description = 'Print the copyable stdio MCP configuration for a generic harness. Paste it into that ' +
|
|
7
|
+
"harness's own MCP config; `skrr browser install` does this for the harnesses that " +
|
|
8
|
+
'have an adapter.';
|
|
7
9
|
async run() {
|
|
8
10
|
await this.parse(BrowserMcpConfig);
|
|
9
11
|
await (0, browser_1.forwardBrowserCommand)(this, ['mcp-config']);
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const core_1 = require("@oclif/core");
|
|
4
4
|
const browser_1 = require("../../browser");
|
|
5
5
|
class BrowserSkillShow extends core_1.Command {
|
|
6
|
-
static description = 'Print the version-matched
|
|
6
|
+
static description = 'Print the version-matched skrr Browser agent skill';
|
|
7
7
|
static args = {
|
|
8
8
|
name: core_1.Args.string({ description: 'Skill name (core)' }),
|
|
9
9
|
};
|
|
@@ -3,7 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const core_1 = require("@oclif/core");
|
|
4
4
|
const browser_1 = require("../browser");
|
|
5
5
|
class BrowserStatus extends core_1.Command {
|
|
6
|
-
static description =
|
|
6
|
+
static description =
|
|
7
|
+
// E2B is not a row of its own: it is the managed runtime's LOCATION, and
|
|
8
|
+
// listing it alongside the others promised a line the output never has.
|
|
9
|
+
'Show attached, managed (including its E2B location), and broker-bridge browser availability';
|
|
7
10
|
static flags = {
|
|
8
11
|
json: core_1.Flags.boolean({ description: 'Output JSON' }),
|
|
9
12
|
};
|
|
@@ -2,7 +2,7 @@ import { Command } from '@oclif/core';
|
|
|
2
2
|
export default class BrowserUninstall extends Command {
|
|
3
3
|
static description: string;
|
|
4
4
|
static flags: {
|
|
5
|
-
harness: import("@oclif/core/lib/interfaces").OptionFlag<string
|
|
5
|
+
harness: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
6
6
|
config: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
7
7
|
'dry-run': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
8
8
|
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
@@ -3,9 +3,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const core_1 = require("@oclif/core");
|
|
4
4
|
const browser_1 = require("../browser");
|
|
5
5
|
class BrowserUninstall extends core_1.Command {
|
|
6
|
-
static description = 'Remove only the
|
|
6
|
+
static description = 'Remove only the skrr Browser MCP entries owned by this installation';
|
|
7
7
|
static flags = {
|
|
8
|
-
harness: core_1.Flags.string({
|
|
8
|
+
harness: core_1.Flags.string({
|
|
9
|
+
// The default and the --config exclusion are both enforced by the
|
|
10
|
+
// runtime this forwards to. Stating them only there meant a bare
|
|
11
|
+
// `skrr browser uninstall` edited every detected harness config with
|
|
12
|
+
// nothing in this help to say so.
|
|
13
|
+
description: 'all, claude, codex, generic, or sky-code. `all` touches every detected ' +
|
|
14
|
+
'harness config and cannot be combined with --config.',
|
|
15
|
+
default: 'all',
|
|
16
|
+
}),
|
|
9
17
|
config: core_1.Flags.string({ description: 'Explicit config file for a generic harness' }),
|
|
10
18
|
'dry-run': core_1.Flags.boolean({ description: 'Show the intended removal without writing it' }),
|
|
11
19
|
json: core_1.Flags.boolean({ description: 'Output JSON' }),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Command } from '@oclif/core';
|
|
2
2
|
export declare function buildBrowserArgs(passthrough: readonly string[]): string[];
|
|
3
3
|
/**
|
|
4
|
-
* Forward one concrete
|
|
4
|
+
* Forward one concrete skrr Browser command to the daemon. Browser operations
|
|
5
5
|
* are implemented by the local daemon, not by the REST CLI, so every oclif
|
|
6
6
|
* leaf uses this one bridge and preserves the capability boundary.
|
|
7
7
|
*/
|
package/dist/commands/browser.js
CHANGED
|
@@ -8,7 +8,7 @@ function buildBrowserArgs(passthrough) {
|
|
|
8
8
|
return ['browser', ...passthrough];
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
11
|
-
* Forward one concrete
|
|
11
|
+
* Forward one concrete skrr Browser command to the daemon. Browser operations
|
|
12
12
|
* are implemented by the local daemon, not by the REST CLI, so every oclif
|
|
13
13
|
* leaf uses this one bridge and preserves the capability boundary.
|
|
14
14
|
*/
|
|
@@ -18,7 +18,7 @@ async function forwardBrowserCommand(command, passthrough) {
|
|
|
18
18
|
// releases. Probe the command list before forwarding so an install command
|
|
19
19
|
// cannot turn into a surprising service mutation.
|
|
20
20
|
if ((await (0, exec_oversky_1.overskySupportsSubcommand)('browser')) === false) {
|
|
21
|
-
command.error('The local `oversky` daemon does not support
|
|
21
|
+
command.error('The local `oversky` daemon does not support skrr Browser yet. Update or reinstall the daemon, then retry `skrr browser`.', { exit: 2 });
|
|
22
22
|
}
|
|
23
23
|
command.exit(await (0, exec_oversky_1.execOversky)(buildBrowserArgs(passthrough)));
|
|
24
24
|
}
|
|
@@ -36,7 +36,7 @@ async function forwardBrowserCommand(command, passthrough) {
|
|
|
36
36
|
* Chrome/profile handling or a second, divergent MCP implementation.
|
|
37
37
|
*/
|
|
38
38
|
class Browser extends core_1.Command {
|
|
39
|
-
static description = 'Install, diagnose, and configure capability-scoped
|
|
39
|
+
static description = 'Install, diagnose, and configure capability-scoped skrr Browser access for local and hosted harnesses';
|
|
40
40
|
static strict = false;
|
|
41
41
|
static examples = [
|
|
42
42
|
'<%= config.bin %> browser status',
|
|
@@ -17,12 +17,15 @@ const sky_code_managed_1 = require("../../lib/sky-code-managed");
|
|
|
17
17
|
* that parses successfully and is then silently dropped.
|
|
18
18
|
*/
|
|
19
19
|
class Code extends core_1.Command {
|
|
20
|
-
static description = 'Start the skrr Code interactive coding agent in this directory'
|
|
20
|
+
static description = 'Start the skrr Code interactive coding agent in this directory. Everything after ' +
|
|
21
|
+
`\`code\` is forwarded to the engine unchanged, so engine flags are not listed here — ` +
|
|
22
|
+
`run \`skrr code run --help\` for this wrapper, or the engine's own help for its ` +
|
|
23
|
+
`flags. ${sky_code_managed_1.SKRR_AGENT_FLAG} is the one flag this wrapper consumes itself.`;
|
|
21
24
|
static strict = false;
|
|
22
25
|
static examples = [
|
|
23
26
|
'<%= config.bin %> code',
|
|
24
27
|
'<%= config.bin %> code --model claude-opus-5',
|
|
25
|
-
`<%= config.bin %> code ${sky_code_managed_1.
|
|
28
|
+
`<%= config.bin %> code ${sky_code_managed_1.SKRR_AGENT_FLAG} Engineer`,
|
|
26
29
|
'<%= config.bin %> code run "fix the failing test"',
|
|
27
30
|
'<%= config.bin %> code doctor',
|
|
28
31
|
];
|
|
@@ -69,7 +72,7 @@ async function forwardToEngine(cmd, subcommand, passthrough, options = {}) {
|
|
|
69
72
|
// error at the other end.
|
|
70
73
|
const say = (line) => cmd.logToStderr(line);
|
|
71
74
|
if (agentRef && !options.managed) {
|
|
72
|
-
say(`${sky_code_managed_1.
|
|
75
|
+
say(`${sky_code_managed_1.SKRR_AGENT_FLAG} has no effect here — this command does not host a managed ` +
|
|
73
76
|
'session. It was removed from the arguments passed to the engine.');
|
|
74
77
|
}
|
|
75
78
|
const managed = options.managed
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base-command';
|
|
2
|
+
/**
|
|
3
|
+
* `skrr code install` — install the engine from the terminal.
|
|
4
|
+
*
|
|
5
|
+
* ── Why this command exists ────────────────────────────────────────────────
|
|
6
|
+
*
|
|
7
|
+
* `skrr code`'s not-installed message offered exactly two routes and neither
|
|
8
|
+
* worked without a browser: "In the web app: the runtime menu … → Install", or
|
|
9
|
+
* point `OVERSKY_SKY_CODE_PATH` at a build you already have — which is the thing
|
|
10
|
+
* you are trying to obtain, and the route that gives up provenance. So the
|
|
11
|
+
* ordinary case for a coding harness (a dev box over SSH, a CI runner, a cloud
|
|
12
|
+
* VM) had no way in (dogfood OSK-276).
|
|
13
|
+
*
|
|
14
|
+
* Nothing underneath was missing. The daemon has performed the verified install
|
|
15
|
+
* since 2026-08-08, and `POST /api/daemons/:id/cli-installers/:provider/install`
|
|
16
|
+
* has fronted it since June. The install was API-exposed and CLI-unreachable —
|
|
17
|
+
* the shape the root `CLAUDE.md` names under CLI ↔ API parity: "an endpoint the
|
|
18
|
+
* API exposes must be reachable from `skrr`."
|
|
19
|
+
*
|
|
20
|
+
* So this adds a SURFACE and no mechanism. Same route the web app posts, same
|
|
21
|
+
* daemon job, same signature verification. A second install path would be a
|
|
22
|
+
* second thing to keep in step with the first, and the first is the one that
|
|
23
|
+
* verifies the signed manifest.
|
|
24
|
+
*/
|
|
25
|
+
export default class CodeInstall extends BaseCommand {
|
|
26
|
+
static description: string;
|
|
27
|
+
static examples: string[];
|
|
28
|
+
static flags: {
|
|
29
|
+
daemon: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
30
|
+
wait: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
31
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
32
|
+
};
|
|
33
|
+
run(): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* Which daemon does the install.
|
|
36
|
+
*
|
|
37
|
+
* Refuses rather than guessing when several are active. Picking one would mean
|
|
38
|
+
* installing a hundred megabytes onto a machine the user was not thinking
|
|
39
|
+
* about, and the list this reads is the same one `skrr list-daemons` prints —
|
|
40
|
+
* so the error can name the exact values that work.
|
|
41
|
+
*/
|
|
42
|
+
private resolveDaemon;
|
|
43
|
+
/**
|
|
44
|
+
* What the daemon says about this provider, when it started no job.
|
|
45
|
+
*
|
|
46
|
+
* Read from the SAME list route the web app uses, so the CLI reports the
|
|
47
|
+
* daemon's own words rather than inventing an explanation for silence. Best
|
|
48
|
+
* effort: a failure here means falling back to the honest "does not say why",
|
|
49
|
+
* never to a guess.
|
|
50
|
+
*/
|
|
51
|
+
private installerNote;
|
|
52
|
+
/**
|
|
53
|
+
* Poll the job until it settles, printing each new log line.
|
|
54
|
+
*
|
|
55
|
+
* The daemon already writes a progress log — "Fetching the signed skrr Code
|
|
56
|
+
* release manifest", "Verified and installed …" — and it is the only account
|
|
57
|
+
* of a hundred-megabyte download the user is waiting on. Printing only the
|
|
58
|
+
* lines not yet seen keeps a poll loop from repeating the whole log.
|
|
59
|
+
*/
|
|
60
|
+
private followJob;
|
|
61
|
+
}
|