@skrr-ai/cli 0.1.44 → 0.1.46
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 +13 -1
- package/dist/base-command.js +37 -3
- package/dist/commands/agents/actions/create.js +11 -4
- package/dist/commands/agents/chat.js +3 -4
- package/dist/commands/browser/cloud-agents.d.ts +20 -0
- package/dist/commands/browser/cloud-agents.js +43 -0
- package/dist/commands/code/handover.d.ts +11 -0
- package/dist/commands/code/handover.js +105 -1
- package/dist/commands/commitments/handover.d.ts +29 -0
- package/dist/commands/commitments/handover.js +99 -0
- package/dist/commands/followups/list.js +1 -1
- package/dist/commands/followups/watch.js +40 -5
- package/dist/commands/initiatives/list.d.ts +1 -0
- package/dist/commands/initiatives/list.js +11 -2
- package/dist/commands/labels/list.d.ts +28 -0
- package/dist/commands/labels/list.js +50 -32
- package/dist/commands/tasks/fork.d.ts +32 -0
- package/dist/commands/tasks/fork.js +171 -0
- package/dist/commands/tasks/handover.d.ts +23 -0
- package/dist/commands/tasks/handover.js +205 -0
- package/dist/commands/tasks/promote.d.ts +23 -0
- package/dist/commands/tasks/promote.js +82 -0
- package/dist/commands/tasks/runs.d.ts +16 -0
- package/dist/commands/tasks/runs.js +46 -1
- package/dist/commands/tasks/show.d.ts +23 -0
- package/dist/commands/tasks/show.js +59 -0
- package/dist/lib/agentic-stream.js +41 -2
- package/dist/lib/api-fetch.d.ts +7 -1
- package/dist/lib/api-fetch.js +9 -2
- package/dist/lib/auth-core-init.js +11 -4
- package/dist/lib/code-handover.d.ts +60 -0
- package/dist/lib/code-handover.js +120 -0
- package/dist/lib/commitments.d.ts +22 -0
- package/dist/lib/commitments.js +42 -0
- package/dist/lib/dedicated-wait.js +22 -1
- package/dist/lib/followups.d.ts +18 -0
- package/dist/lib/followups.js +44 -0
- package/dist/lib/initiatives.d.ts +15 -3
- package/dist/lib/label-ref.d.ts +2 -0
- package/dist/lib/node-adapter.js +6 -0
- package/dist/lib/task-extras.d.ts +44 -0
- package/dist/lib/task-extras.js +73 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/credentialEnvelopeBridge.d.ts +29 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/credentialEnvelopeBridge.js +169 -23
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/deviceIdentityBridge.js +91 -5
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarness.d.ts +8 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarness.js +7 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessHome.js +45 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/harnessSkillLayout.d.ts +65 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/harnessSkillLayout.js +99 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.d.ts +3 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.js +26 -2
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/loginLocalhost.js +177 -26
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/profileStateDir.d.ts +119 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/profileStateDir.js +346 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/credentialEnvelopeBridge.d.ts +29 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/credentialEnvelopeBridge.js +169 -24
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/deviceIdentityBridge.js +93 -7
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarness.d.ts +8 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarness.js +7 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessHome.js +45 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/harnessSkillLayout.d.ts +65 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/harnessSkillLayout.js +94 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.d.ts +3 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.js +10 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/loginLocalhost.js +177 -26
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/profileStateDir.d.ts +119 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/profileStateDir.js +333 -0
- package/dist/node_modules/@skrr-ai/auth-core/package.json +11 -1
- package/dist/node_modules/@skrr-ai/data-provider/index.js +2746 -2711
- package/dist/node_modules/@skrr-ai/inference-broker/package.json +1 -1
- package/oclif.manifest.json +34300 -33843
- package/package.json +2 -2
package/dist/base-command.d.ts
CHANGED
|
@@ -311,14 +311,26 @@ export declare abstract class BaseCommand extends Command {
|
|
|
311
311
|
body: unknown;
|
|
312
312
|
idempotencyKey: string;
|
|
313
313
|
}): never;
|
|
314
|
-
protected failWithCliError({ message, code, status, exit, retryable, details, }: {
|
|
314
|
+
protected failWithCliError({ message, code, status, exit, retryable, details, requestId, }: {
|
|
315
315
|
message: string;
|
|
316
316
|
code: string;
|
|
317
317
|
status?: number;
|
|
318
318
|
exit: number;
|
|
319
319
|
retryable: boolean;
|
|
320
320
|
details?: unknown;
|
|
321
|
+
/** The server's `X-Request-ID` for the refused call, when there was one. */
|
|
322
|
+
requestId?: string;
|
|
321
323
|
}): never;
|
|
324
|
+
/**
|
|
325
|
+
* The server's `X-Request-ID` for the most recent refused API call.
|
|
326
|
+
*
|
|
327
|
+
* The CLI prints its own refusals but not the id the server logged them
|
|
328
|
+
* against, so matching one to a log line meant guessing from timestamps. On
|
|
329
|
+
* an account with several clients that misattributes: a 409 raised by
|
|
330
|
+
* another session's concurrent image update was nearly filed as a CLI retry
|
|
331
|
+
* bug (2026-09-18).
|
|
332
|
+
*/
|
|
333
|
+
private lastApiRequestId?;
|
|
322
334
|
private writeJsonCliError;
|
|
323
335
|
protected wantsJsonOutput(): boolean;
|
|
324
336
|
}
|
package/dist/base-command.js
CHANGED
|
@@ -853,9 +853,26 @@ class BaseCommand extends core_1.Command {
|
|
|
853
853
|
* envelope carry the same identifying text.
|
|
854
854
|
*/
|
|
855
855
|
handleApiError(err, { subject } = {}) {
|
|
856
|
+
// An error this command already raised for the user is not an API failure
|
|
857
|
+
// to translate. `this.error()` throws a CLIError carrying `oclif.exit`, and
|
|
858
|
+
// under --json it is the ExitError thrown AFTER `writeJsonCliError` already
|
|
859
|
+
// printed the envelope. When the raise sits inside the try whose catch is
|
|
860
|
+
// this call, re-wrapping it printed a SECOND envelope (`--json` saw the
|
|
861
|
+
// real message followed by `EEXIT: 1`) and rewrote the caller's exit code
|
|
862
|
+
// to 1 — `agents actions create --prompt ""` did exactly that. Pass it
|
|
863
|
+
// through so `catch()` renders it once, with its code and exit intact.
|
|
864
|
+
if (err instanceof Error) {
|
|
865
|
+
const raised = err;
|
|
866
|
+
if (isOclifExitError(raised) || typeof raised.oclif?.exit === 'number') {
|
|
867
|
+
throw err;
|
|
868
|
+
}
|
|
869
|
+
}
|
|
856
870
|
const say = (message) => withSubject(subject, message);
|
|
857
871
|
if (err instanceof Error) {
|
|
858
872
|
const e = err;
|
|
873
|
+
// Remembered once here rather than threaded through every branch below:
|
|
874
|
+
// each one ends in `failWithCliError`, and the id belongs on all of them.
|
|
875
|
+
this.lastApiRequestId = e.requestId;
|
|
859
876
|
const body = parseErrorBody(e.body);
|
|
860
877
|
const bodyCode = stringProp(body, 'code') || stringProp(body, 'errorType');
|
|
861
878
|
const bodyMessage = stringProp(body, 'message') || stringProp(body, 'error');
|
|
@@ -1242,9 +1259,9 @@ class BaseCommand extends core_1.Command {
|
|
|
1242
1259
|
details: { outboxId: queuedId, idempotencyKey: write.idempotencyKey },
|
|
1243
1260
|
});
|
|
1244
1261
|
}
|
|
1245
|
-
failWithCliError({ message, code, status, exit, retryable, details, }) {
|
|
1262
|
+
failWithCliError({ message, code, status, exit, retryable, details, requestId, }) {
|
|
1246
1263
|
if (this.wantsJsonOutput()) {
|
|
1247
|
-
this.writeJsonCliError({ message, code, status, exit, retryable, details });
|
|
1264
|
+
this.writeJsonCliError({ message, code, status, exit, retryable, details, requestId });
|
|
1248
1265
|
}
|
|
1249
1266
|
// Human path. Deliberately stderr-only: stdout is the SUCCESS channel, so
|
|
1250
1267
|
// `id=$(skrr tasks start "$x")` and `sky ... | jq` are never fed error
|
|
@@ -1277,7 +1294,17 @@ class BaseCommand extends core_1.Command {
|
|
|
1277
1294
|
...(suggestion ? { suggestions: [suggestion] } : {}),
|
|
1278
1295
|
});
|
|
1279
1296
|
}
|
|
1280
|
-
|
|
1297
|
+
/**
|
|
1298
|
+
* The server's `X-Request-ID` for the most recent refused API call.
|
|
1299
|
+
*
|
|
1300
|
+
* The CLI prints its own refusals but not the id the server logged them
|
|
1301
|
+
* against, so matching one to a log line meant guessing from timestamps. On
|
|
1302
|
+
* an account with several clients that misattributes: a 409 raised by
|
|
1303
|
+
* another session's concurrent image update was nearly filed as a CLI retry
|
|
1304
|
+
* bug (2026-09-18).
|
|
1305
|
+
*/
|
|
1306
|
+
lastApiRequestId;
|
|
1307
|
+
writeJsonCliError({ message, code, status, exit, retryable, details, requestId, }) {
|
|
1281
1308
|
this.log(JSON.stringify({
|
|
1282
1309
|
ok: false,
|
|
1283
1310
|
error: {
|
|
@@ -1287,6 +1314,13 @@ class BaseCommand extends core_1.Command {
|
|
|
1287
1314
|
retryable,
|
|
1288
1315
|
command: this.id ?? null,
|
|
1289
1316
|
server: this.cliConfig?.baseURL ?? null,
|
|
1317
|
+
// The id the server logged this refusal against. Without it, a
|
|
1318
|
+
// refused call can only be matched to a log line by guessing from
|
|
1319
|
+
// timestamps — which, with several clients on one account,
|
|
1320
|
+
// attributes another session's request to yours.
|
|
1321
|
+
...(requestId || this.lastApiRequestId
|
|
1322
|
+
? { requestId: requestId ?? this.lastApiRequestId }
|
|
1323
|
+
: {}),
|
|
1290
1324
|
...(details ? { details } : {}),
|
|
1291
1325
|
},
|
|
1292
1326
|
}, null, 2));
|
|
@@ -81,8 +81,11 @@ class AgentsActionsCreate extends base_command_1.BaseCommand {
|
|
|
81
81
|
let replayed = false;
|
|
82
82
|
try {
|
|
83
83
|
const title = typeof body.title === 'string' ? body.title.trim() : '';
|
|
84
|
-
if (!title)
|
|
85
|
-
this.error(
|
|
84
|
+
if (!title) {
|
|
85
|
+
this.error(typeof body.title === 'string'
|
|
86
|
+
? 'The action title was provided but is empty. Pass non-empty text to --title or title in --from-json.'
|
|
87
|
+
: 'Action title is required. Pass --title or include title.', { exit: 1 });
|
|
88
|
+
}
|
|
86
89
|
const kind = body.kind === 'builtin' ? 'builtin' : 'prompt';
|
|
87
90
|
// No read of the library: position is assigned by the server at the
|
|
88
91
|
// moment of the append, so it cannot be computed from a stale copy. An
|
|
@@ -97,7 +100,9 @@ class AgentsActionsCreate extends base_command_1.BaseCommand {
|
|
|
97
100
|
if (kind === 'builtin') {
|
|
98
101
|
const builtinType = body.builtinType;
|
|
99
102
|
if (!agent_actions_1.BUILTIN_ACTION_TYPES.includes(builtinType)) {
|
|
100
|
-
this.error(
|
|
103
|
+
this.error(builtinType === undefined
|
|
104
|
+
? '--builtin-type is required for built-in actions.'
|
|
105
|
+
: `Invalid --builtin-type "${String(builtinType)}" — expected one of ${agent_actions_1.BUILTIN_ACTION_TYPES.join(', ')}.`, { exit: 1 });
|
|
101
106
|
}
|
|
102
107
|
created = (0, agent_actions_1.makeBuiltinAction)({
|
|
103
108
|
scope,
|
|
@@ -118,7 +123,9 @@ class AgentsActionsCreate extends base_command_1.BaseCommand {
|
|
|
118
123
|
else {
|
|
119
124
|
const prompt = typeof body.prompt === 'string' ? body.prompt : '';
|
|
120
125
|
if (!prompt.trim()) {
|
|
121
|
-
this.error(
|
|
126
|
+
this.error(typeof body.prompt === 'string'
|
|
127
|
+
? 'The prompt was provided but is empty. Pass non-empty text to --prompt or prompt in --from-json.'
|
|
128
|
+
: 'Prompt actions require --prompt or prompt in --from-json.', { exit: 1 });
|
|
122
129
|
}
|
|
123
130
|
// Embedded built-in actions (chip source of truth). The prompt keeps the
|
|
124
131
|
// inline `[[action:refId]]` tokens (positional); the server expands each
|
|
@@ -235,7 +235,9 @@ class AgentsChat extends base_command_1.BaseCommand {
|
|
|
235
235
|
description: 'Emit the final one-shot response as JSON (use with --no-stream)',
|
|
236
236
|
}),
|
|
237
237
|
'approve-tools': core_1.Flags.boolean({
|
|
238
|
-
description: '
|
|
238
|
+
description: 'Allow this turn to use permission-gated tools. In a terminal it asks per call; ' +
|
|
239
|
+
'with no terminal the flag itself is the approval for this turn, and each one is ' +
|
|
240
|
+
'reported on the stream. Without it every such call is denied.',
|
|
239
241
|
}),
|
|
240
242
|
'local-skill': core_1.Flags.string({
|
|
241
243
|
description: 'Invoke a skill on your machine on this turn, as `skrr skills local` lists it: its ' +
|
|
@@ -333,9 +335,6 @@ class AgentsChat extends base_command_1.BaseCommand {
|
|
|
333
335
|
this.error('--local-skill has no meaning with --quick: the persona-only summarizer runs no ' +
|
|
334
336
|
'runtime, so no skill on your machine can load. Drop --quick for a real turn.', { exit: 2 });
|
|
335
337
|
}
|
|
336
|
-
if (flags['approve-tools'] && !process.stdin.isTTY) {
|
|
337
|
-
this.error('--approve-tools requires an interactive terminal.', { exit: 2 });
|
|
338
|
-
}
|
|
339
338
|
if (flags.conversation && flags['thread-root']) {
|
|
340
339
|
this.error('--conversation and --thread-root are mutually exclusive.', { exit: 2 });
|
|
341
340
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
/**
|
|
3
|
+
* Whether a cloud agent may drive the browser on THIS computer (OSK-10285).
|
|
4
|
+
*
|
|
5
|
+
* The setting lives in the daemon's own config on this computer, so it is
|
|
6
|
+
* forwarded to the daemon rather than sent to the API: consent to a cloud agent
|
|
7
|
+
* using a signed-in browser belongs to the person at the machine, and a request
|
|
8
|
+
* from the cloud must not be able to grant it.
|
|
9
|
+
*/
|
|
10
|
+
export default class BrowserCloudAgents extends Command {
|
|
11
|
+
static description: string;
|
|
12
|
+
static examples: string[];
|
|
13
|
+
static args: {
|
|
14
|
+
action: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
15
|
+
};
|
|
16
|
+
static flags: {
|
|
17
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
18
|
+
};
|
|
19
|
+
run(): Promise<void>;
|
|
20
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const browser_1 = require("../browser");
|
|
5
|
+
/**
|
|
6
|
+
* Whether a cloud agent may drive the browser on THIS computer (OSK-10285).
|
|
7
|
+
*
|
|
8
|
+
* The setting lives in the daemon's own config on this computer, so it is
|
|
9
|
+
* forwarded to the daemon rather than sent to the API: consent to a cloud agent
|
|
10
|
+
* using a signed-in browser belongs to the person at the machine, and a request
|
|
11
|
+
* from the cloud must not be able to grant it.
|
|
12
|
+
*/
|
|
13
|
+
class BrowserCloudAgents extends core_1.Command {
|
|
14
|
+
static description = 'Allow, deny, or show whether cloud agents may drive the browser on this computer (off by default)';
|
|
15
|
+
static examples = [
|
|
16
|
+
'<%= config.bin %> browser cloud-agents status',
|
|
17
|
+
'<%= config.bin %> browser cloud-agents allow',
|
|
18
|
+
'<%= config.bin %> browser cloud-agents deny',
|
|
19
|
+
];
|
|
20
|
+
static args = {
|
|
21
|
+
action: core_1.Args.string({
|
|
22
|
+
description: 'allow, deny, or status',
|
|
23
|
+
required: true,
|
|
24
|
+
options: ['allow', 'deny', 'status'],
|
|
25
|
+
// Without this oclif reads stdin for a missing positional, so the command
|
|
26
|
+
// hangs when run from a pipe or a non-tty instead of refusing. Enforced
|
|
27
|
+
// by ARG_IMPLICIT_STDIN_ENABLED in the command-hygiene audit.
|
|
28
|
+
ignoreStdin: true,
|
|
29
|
+
}),
|
|
30
|
+
};
|
|
31
|
+
static flags = {
|
|
32
|
+
json: core_1.Flags.boolean({ description: 'Output JSON' }),
|
|
33
|
+
};
|
|
34
|
+
async run() {
|
|
35
|
+
const { args, flags } = await this.parse(BrowserCloudAgents);
|
|
36
|
+
await (0, browser_1.forwardBrowserCommand)(this, [
|
|
37
|
+
'cloud-agents',
|
|
38
|
+
args.action,
|
|
39
|
+
...(flags.json ? ['--json'] : []),
|
|
40
|
+
]);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
exports.default = BrowserCloudAgents;
|
|
@@ -21,6 +21,15 @@ import { BaseCommand } from '../../base-command';
|
|
|
21
21
|
* code in the cloud (`skrr machines hosted start --repo` is the second, and stays the
|
|
22
22
|
* right choice when you want a persistent machine instead of a one-shot job).
|
|
23
23
|
*
|
|
24
|
+
* ── `--carry-session` ──────────────────────────────────────────────────────
|
|
25
|
+
*
|
|
26
|
+
* The transcript CAN travel once the engine implements the session-export
|
|
27
|
+
* contract (docs/architecture/sky-code-session-export-contract-2026-08-21.md):
|
|
28
|
+
* `sky-code session export <id> --format json` writes a versioned envelope to
|
|
29
|
+
* stdout. This flag runs exactly that contract and folds the export into the
|
|
30
|
+
* prompt — the endpoint's only carrier. An engine that predates the contract
|
|
31
|
+
* is a clean refusal, never a silent fallback to brief-only.
|
|
32
|
+
*
|
|
24
33
|
* ── The safety gate is the point ───────────────────────────────────────────
|
|
25
34
|
*
|
|
26
35
|
* The runtime CLONES FROM GITHUB at `--base`. Uncommitted or unpushed work is
|
|
@@ -38,6 +47,8 @@ export default class CodeHandover extends BaseCommand {
|
|
|
38
47
|
base: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
39
48
|
'allow-dirty': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
40
49
|
browser: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
50
|
+
'carry-session': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
51
|
+
session: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
41
52
|
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
42
53
|
};
|
|
43
54
|
/** Run git, returning null rather than throwing — every caller has a fallback. */
|
|
@@ -6,6 +6,7 @@ const node_crypto_1 = require("node:crypto");
|
|
|
6
6
|
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
7
7
|
const base_command_1 = require("../../base-command");
|
|
8
8
|
const code_handover_1 = require("../../lib/code-handover");
|
|
9
|
+
const first_party_harness_1 = require("../../lib/first-party-harness");
|
|
9
10
|
/**
|
|
10
11
|
* `skrr code handover` — hand the work in this directory to an agent running on
|
|
11
12
|
* a cloud runtime.
|
|
@@ -28,6 +29,15 @@ const code_handover_1 = require("../../lib/code-handover");
|
|
|
28
29
|
* code in the cloud (`skrr machines hosted start --repo` is the second, and stays the
|
|
29
30
|
* right choice when you want a persistent machine instead of a one-shot job).
|
|
30
31
|
*
|
|
32
|
+
* ── `--carry-session` ──────────────────────────────────────────────────────
|
|
33
|
+
*
|
|
34
|
+
* The transcript CAN travel once the engine implements the session-export
|
|
35
|
+
* contract (docs/architecture/sky-code-session-export-contract-2026-08-21.md):
|
|
36
|
+
* `sky-code session export <id> --format json` writes a versioned envelope to
|
|
37
|
+
* stdout. This flag runs exactly that contract and folds the export into the
|
|
38
|
+
* prompt — the endpoint's only carrier. An engine that predates the contract
|
|
39
|
+
* is a clean refusal, never a silent fallback to brief-only.
|
|
40
|
+
*
|
|
31
41
|
* ── The safety gate is the point ───────────────────────────────────────────
|
|
32
42
|
*
|
|
33
43
|
* The runtime CLONES FROM GITHUB at `--base`. Uncommitted or unpushed work is
|
|
@@ -36,11 +46,13 @@ const code_handover_1 = require("../../lib/code-handover");
|
|
|
36
46
|
* the pull request. This refuses by default and says what to do.
|
|
37
47
|
*/
|
|
38
48
|
class CodeHandover extends base_command_1.BaseCommand {
|
|
39
|
-
static description = 'Hand the work in this directory to an agent on a cloud runtime'
|
|
49
|
+
static description = 'Hand the work in this directory to an agent on a cloud runtime ' +
|
|
50
|
+
'(--carry-session also carries the engine session transcript, when the engine supports export)';
|
|
40
51
|
static examples = [
|
|
41
52
|
'<%= config.bin %> code handover --to "Frontend Agent" --brief "finish the bundle-size fix"',
|
|
42
53
|
'<%= config.bin %> code handover --to agent_abc --brief "continue the parser refactor" --base main',
|
|
43
54
|
'<%= config.bin %> code handover --to "Engineer" --brief "..." --allow-dirty --json',
|
|
55
|
+
'<%= config.bin %> code handover --to "Engineer" --brief "..." --carry-session --session <engine-session-id>',
|
|
44
56
|
];
|
|
45
57
|
static flags = {
|
|
46
58
|
to: core_1.Flags.string({
|
|
@@ -64,6 +76,17 @@ class CodeHandover extends base_command_1.BaseCommand {
|
|
|
64
76
|
browser: core_1.Flags.boolean({
|
|
65
77
|
description: 'Give the receiving agent a browser. Refused where the deployment has no browser runtime, never run without one.',
|
|
66
78
|
}),
|
|
79
|
+
'carry-session': core_1.Flags.boolean({
|
|
80
|
+
description: 'Export the engine session transcript (`sky-code session export`) and carry it into the ' +
|
|
81
|
+
'handover. Opt-in because carrying a whole session is a cost the user should choose. ' +
|
|
82
|
+
'Refused outright when the engine predates the export contract — there is no silent ' +
|
|
83
|
+
'fallback to brief-only.',
|
|
84
|
+
default: false,
|
|
85
|
+
}),
|
|
86
|
+
session: core_1.Flags.string({
|
|
87
|
+
description: 'Engine session id to export with --carry-session (default: the session id the engine ' +
|
|
88
|
+
'exports to its environment — SKRR_CODE_SESSION_ID or SKY_CODE_SESSION_ID)',
|
|
89
|
+
}),
|
|
67
90
|
json: core_1.Flags.boolean({ description: 'Output the created task as JSON' }),
|
|
68
91
|
};
|
|
69
92
|
/** Run git, returning null rather than throwing — every caller has a fallback. */
|
|
@@ -105,6 +128,78 @@ class CodeHandover extends base_command_1.BaseCommand {
|
|
|
105
128
|
if (!safety.safe && !flags['allow-dirty']) {
|
|
106
129
|
this.error((0, code_handover_1.formatUnsafeHandover)(gitState, safety));
|
|
107
130
|
}
|
|
131
|
+
if (flags.session && !flags['carry-session']) {
|
|
132
|
+
this.warn('--session has no effect without --carry-session.');
|
|
133
|
+
}
|
|
134
|
+
// ── Optional: carry the engine session. A refused export is terminal —
|
|
135
|
+
// the flag promised the transcript would travel, so dispatching without it
|
|
136
|
+
// would silently deliver a different product than the one asked for. ────
|
|
137
|
+
let sessionExport = null;
|
|
138
|
+
let carriedSessionId = null;
|
|
139
|
+
if (flags['carry-session']) {
|
|
140
|
+
const { path: engineBin } = (0, first_party_harness_1.resolveEngine)();
|
|
141
|
+
if (!engineBin)
|
|
142
|
+
this.error((0, first_party_harness_1.notInstalledMessage)());
|
|
143
|
+
// `--session` wins; otherwise the variable the engine stamps into
|
|
144
|
+
// processes it spawns (current namespace, then the legacy spelling).
|
|
145
|
+
const sessionId = flags.session ||
|
|
146
|
+
process.env.SKRR_CODE_SESSION_ID?.trim() ||
|
|
147
|
+
process.env.SKY_CODE_SESSION_ID?.trim();
|
|
148
|
+
if (!sessionId) {
|
|
149
|
+
this.error('--carry-session needs the engine session to carry. Pass --session <engine-session-id>, ' +
|
|
150
|
+
'or run inside a session that exports SKRR_CODE_SESSION_ID.');
|
|
151
|
+
}
|
|
152
|
+
carriedSessionId = sessionId;
|
|
153
|
+
let stdout;
|
|
154
|
+
try {
|
|
155
|
+
stdout = (0, node_child_process_1.execFileSync)(engineBin, ['session', 'export', sessionId, '--format', 'json'], {
|
|
156
|
+
encoding: 'utf8',
|
|
157
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
158
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
catch (err) {
|
|
162
|
+
const e = err;
|
|
163
|
+
const failure = (0, code_handover_1.classifySessionExportError)(e);
|
|
164
|
+
if (failure.kind === 'unknown-session') {
|
|
165
|
+
this.error(`No engine session "${sessionId}" — the engine found nothing to carry.\n` +
|
|
166
|
+
` ${failure.detail}`);
|
|
167
|
+
}
|
|
168
|
+
this.error('This engine does not support session export — --carry-session requires a sky-code ' +
|
|
169
|
+
'engine implementing the session-export contract ' +
|
|
170
|
+
'(docs/architecture/sky-code-session-export-contract-2026-08-21.md).\n' +
|
|
171
|
+
` ${failure.detail}\n` +
|
|
172
|
+
' Re-run without --carry-session to hand over the situation only, or upgrade the engine.');
|
|
173
|
+
}
|
|
174
|
+
const envelope = (0, code_handover_1.parseSessionExportEnvelope)(stdout);
|
|
175
|
+
if (!envelope) {
|
|
176
|
+
// Exit 0 but no contract envelope is a deviation, not a success: the
|
|
177
|
+
// one shape this side may depend on (C2) did not arrive, so attaching
|
|
178
|
+
// the output anyway would be guessing with someone else's session.
|
|
179
|
+
this.error('The engine ran `session export` but did not produce the contract envelope ' +
|
|
180
|
+
'({version, sessionId, messages[], truncated}) — this build predates or deviates from ' +
|
|
181
|
+
'the export contract, so nothing was attached.');
|
|
182
|
+
}
|
|
183
|
+
// The endpoint's prompt cap is 50000 chars; the transcript gets what the
|
|
184
|
+
// brief and the git context leave behind.
|
|
185
|
+
const budget = 50000 -
|
|
186
|
+
(0, code_handover_1.composeHandoverPrompt)({
|
|
187
|
+
brief: flags.brief,
|
|
188
|
+
repoFullName,
|
|
189
|
+
branch,
|
|
190
|
+
headSha: this.git(['rev-parse', '--short', 'HEAD']),
|
|
191
|
+
recentCommits: this.git(['log', '--oneline', '-5']),
|
|
192
|
+
localWorkNotCarried: safety.localWorkNotCarried,
|
|
193
|
+
}).length -
|
|
194
|
+
128;
|
|
195
|
+
sessionExport = (0, code_handover_1.renderSessionTranscript)(envelope, Math.max(0, budget));
|
|
196
|
+
if (sessionExport.totalCount > 0 && sessionExport.carriedCount === 0) {
|
|
197
|
+
// A "carried" block containing zero messages is a lie about what moved.
|
|
198
|
+
// The brief --brief plus git context already consumed the prompt budget.
|
|
199
|
+
this.error('The session transcript does not fit the 50000-character task prompt alongside this ' +
|
|
200
|
+
'brief — nothing would be carried. Shorten --brief, or re-run without --carry-session.');
|
|
201
|
+
}
|
|
202
|
+
}
|
|
108
203
|
// ── Target agent: id or name, from the agents this user can see. ────────
|
|
109
204
|
let agents = [];
|
|
110
205
|
try {
|
|
@@ -145,6 +240,7 @@ class CodeHandover extends base_command_1.BaseCommand {
|
|
|
145
240
|
headSha: this.git(['rev-parse', '--short', 'HEAD']),
|
|
146
241
|
recentCommits: this.git(['log', '--oneline', '-5']),
|
|
147
242
|
localWorkNotCarried: safety.localWorkNotCarried,
|
|
243
|
+
sessionTranscript: sessionExport?.text,
|
|
148
244
|
});
|
|
149
245
|
let result;
|
|
150
246
|
try {
|
|
@@ -173,6 +269,14 @@ class CodeHandover extends base_command_1.BaseCommand {
|
|
|
173
269
|
const url = task.previewUrl ?? task.prUrl;
|
|
174
270
|
if (url)
|
|
175
271
|
this.log(` ${String(url)}`);
|
|
272
|
+
if (sessionExport) {
|
|
273
|
+
const qualifiers = [
|
|
274
|
+
sessionExport.engineTruncated ? 'engine-truncated' : null,
|
|
275
|
+
sessionExport.clipped ? 'clipped to fit' : null,
|
|
276
|
+
].filter(Boolean);
|
|
277
|
+
this.log(` session ${carriedSessionId} — ${sessionExport.carriedCount}/${sessionExport.totalCount} ` +
|
|
278
|
+
`messages carried${qualifiers.length ? ` (${qualifiers.join(', ')})` : ''}`);
|
|
279
|
+
}
|
|
176
280
|
if (safety.localWorkNotCarried) {
|
|
177
281
|
this.log(' note local uncommitted/unpushed work was not carried over.');
|
|
178
282
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base-command';
|
|
2
|
+
/**
|
|
3
|
+
* `skrr commitments handover` — rebind a commitment's executor to a different
|
|
4
|
+
* agent.
|
|
5
|
+
*
|
|
6
|
+
* `commitment.agentId` is single-valued by design, so this is NOT a patch: the
|
|
7
|
+
* server records the move on the commitment's audit trail (`executorHandovers`)
|
|
8
|
+
* with who initiated it and why (impl contract B4, design doc P4). The
|
|
9
|
+
* canonical case is a commitment whose agent's execution targets are all
|
|
10
|
+
* quota-blocked — this is the "reassign" half of "executor cannot run until
|
|
11
|
+
* <date> — reassign or add a fallback target".
|
|
12
|
+
*
|
|
13
|
+
* Only the WHO moves: the contract, cadence, watched sources and audit trail
|
|
14
|
+
* are unchanged, and the new executor's own execution policy decides WHERE the
|
|
15
|
+
* next check runs.
|
|
16
|
+
*/
|
|
17
|
+
export default class CommitmentsHandover extends BaseCommand {
|
|
18
|
+
static description: string;
|
|
19
|
+
static examples: string[];
|
|
20
|
+
static args: {
|
|
21
|
+
id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
22
|
+
};
|
|
23
|
+
static flags: {
|
|
24
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
25
|
+
to: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
26
|
+
reason: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
27
|
+
};
|
|
28
|
+
run(): Promise<void>;
|
|
29
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
5
|
+
const base_command_1 = require("../../base-command");
|
|
6
|
+
const commitments_1 = require("../../lib/commitments");
|
|
7
|
+
const web_url_1 = require("../../lib/web-url");
|
|
8
|
+
const code_handover_1 = require("../../lib/code-handover");
|
|
9
|
+
/**
|
|
10
|
+
* `skrr commitments handover` — rebind a commitment's executor to a different
|
|
11
|
+
* agent.
|
|
12
|
+
*
|
|
13
|
+
* `commitment.agentId` is single-valued by design, so this is NOT a patch: the
|
|
14
|
+
* server records the move on the commitment's audit trail (`executorHandovers`)
|
|
15
|
+
* with who initiated it and why (impl contract B4, design doc P4). The
|
|
16
|
+
* canonical case is a commitment whose agent's execution targets are all
|
|
17
|
+
* quota-blocked — this is the "reassign" half of "executor cannot run until
|
|
18
|
+
* <date> — reassign or add a fallback target".
|
|
19
|
+
*
|
|
20
|
+
* Only the WHO moves: the contract, cadence, watched sources and audit trail
|
|
21
|
+
* are unchanged, and the new executor's own execution policy decides WHERE the
|
|
22
|
+
* next check runs.
|
|
23
|
+
*/
|
|
24
|
+
class CommitmentsHandover extends base_command_1.BaseCommand {
|
|
25
|
+
static description = 'Reassign a commitment to a different executor agent';
|
|
26
|
+
static examples = [
|
|
27
|
+
'<%= config.bin %> commitments handover <commitment-id> --to "Backup Agent"',
|
|
28
|
+
'<%= config.bin %> commitments handover <id> --to agent_abc --reason "claude quota exhausted until Sep 19"',
|
|
29
|
+
'<%= config.bin %> commitments handover <id> --to agent_abc --json',
|
|
30
|
+
];
|
|
31
|
+
static args = {
|
|
32
|
+
id: core_1.Args.string({ description: 'Commitment ID', required: true, ignoreStdin: true }),
|
|
33
|
+
};
|
|
34
|
+
static flags = {
|
|
35
|
+
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
36
|
+
to: core_1.Flags.string({
|
|
37
|
+
description: 'Agent that takes over the commitment — id or name',
|
|
38
|
+
required: true,
|
|
39
|
+
}),
|
|
40
|
+
reason: core_1.Flags.string({
|
|
41
|
+
description: 'Why the executor is changing — recorded on the audit trail',
|
|
42
|
+
}),
|
|
43
|
+
};
|
|
44
|
+
async run() {
|
|
45
|
+
this.requireAuth();
|
|
46
|
+
const { args, flags } = await this.parse(CommitmentsHandover);
|
|
47
|
+
// ── Target agent: id or name, resolved like `code handover --to`. ──────
|
|
48
|
+
let agents = [];
|
|
49
|
+
try {
|
|
50
|
+
const resp = await data_provider_1.dataService.listAgents({ requiredPermission: data_provider_1.PermissionBits.VIEW });
|
|
51
|
+
agents = (resp?.data ?? []).filter(Boolean);
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
this.handleApiError(err);
|
|
55
|
+
}
|
|
56
|
+
const matched = (0, code_handover_1.matchAgent)(flags.to, agents);
|
|
57
|
+
if (matched.kind === 'none') {
|
|
58
|
+
this.error(`No agent matches "${flags.to}". Run \`${this.config.bin} agents list\` to see the agents you can use.`);
|
|
59
|
+
}
|
|
60
|
+
if (matched.kind === 'ambiguous') {
|
|
61
|
+
this.error(`"${flags.to}" matches ${matched.candidates.length} agents. Pass the agent id instead:\n` +
|
|
62
|
+
matched.candidates.map((a) => ` ${a.id} ${a.name ?? ''}`).join('\n'));
|
|
63
|
+
}
|
|
64
|
+
const target = matched.agent;
|
|
65
|
+
let result;
|
|
66
|
+
try {
|
|
67
|
+
result = await commitments_1.commitmentApi.setExecutor(args.id, {
|
|
68
|
+
agentId: target.id,
|
|
69
|
+
...(flags.reason ? { reason: flags.reason } : {}),
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
this.handleApiError(err, { subject: `Commitment ${args.id}` });
|
|
74
|
+
}
|
|
75
|
+
if (flags.json) {
|
|
76
|
+
this.log(JSON.stringify(result, null, 2));
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
const agentLabel = target.name ? `${target.name} (${target.id})` : target.id;
|
|
80
|
+
this.log(`Handed commitment ${args.id} over to ${agentLabel}`);
|
|
81
|
+
// The audit entry the server appended — echo it so "from whom" is answered
|
|
82
|
+
// without a second call. Absent on a server that predates the trail.
|
|
83
|
+
const commitment = result?.commitment ??
|
|
84
|
+
result;
|
|
85
|
+
const handovers = commitment?.executorHandovers;
|
|
86
|
+
if (Array.isArray(handovers) && handovers.length > 0) {
|
|
87
|
+
const last = handovers[handovers.length - 1];
|
|
88
|
+
if (typeof last?.fromAgentId === 'string' && typeof last?.toAgentId === 'string') {
|
|
89
|
+
this.log(` executor ${last.fromAgentId} → ${last.toAgentId}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (commitment) {
|
|
93
|
+
const withUrl = (0, web_url_1.withCommitmentUrl)(this.cliConfig.baseURL, commitment);
|
|
94
|
+
if (withUrl.url)
|
|
95
|
+
this.log(` ${withUrl.url}`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
exports.default = CommitmentsHandover;
|
|
@@ -14,7 +14,7 @@ const agent_resolver_1 = require("../../lib/agent-resolver");
|
|
|
14
14
|
* obligations and start reasoning about them.
|
|
15
15
|
*/
|
|
16
16
|
class FollowupsList extends base_command_1.BaseCommand {
|
|
17
|
-
static description = 'List follow-ups — armed, proposed, paused, or settled';
|
|
17
|
+
static description = 'List follow-ups — armed, proposed, paused, settling, or settled';
|
|
18
18
|
static examples = [
|
|
19
19
|
'<%= config.bin %> followups list',
|
|
20
20
|
'<%= config.bin %> followups list --agent agent_1 --kind watch --state armed',
|
|
@@ -30,6 +30,7 @@ class FollowupsWatch extends base_command_1.BaseCommand {
|
|
|
30
30
|
'<%= config.bin %> followups watch --subject task:OSK-42 --why "deploy still running" --url https://ci.example.com/api/build/9 --until \'{"path":"status","op":"equals","value":"done"}\' --deadline 6h',
|
|
31
31
|
'<%= config.bin %> followups watch --subject task:OSK-42 --why "pr review" --check "gh pr view 42 --json state" --success "state == MERGED" --abort "state == CLOSED" --wait event --wait-entity github --wait-event pull_request_merged --wait-fallback 2h',
|
|
32
32
|
'<%= config.bin %> followups watch --subject conversation:abc --why "vendor reply" --check "check inbox" --success "reply arrived" --abort "3 days" --wait clock --wait-at 2026-09-20T09:00:00Z',
|
|
33
|
+
'<%= config.bin %> followups watch --subject task:OSK-42 --why "deploy tail" --check "release-status says live" --success "live" --abort "6h" --wait clock --wait-at 45m',
|
|
33
34
|
];
|
|
34
35
|
static flags = {
|
|
35
36
|
subject: core_1.Flags.string({ description: 'Subject ref: type:externalKey', required: true }),
|
|
@@ -41,9 +42,15 @@ class FollowupsWatch extends base_command_1.BaseCommand {
|
|
|
41
42
|
description: 'Predicate tree as JSON (predicate form — the server evaluates it; no agent turn per check): a leaf {"path","op","value"} or {"all"|"any": [...]}. op is equals, not_equals, contains, starts_with, in, gt, lt, exists, … — an unknown op is refused with the full list',
|
|
42
43
|
}),
|
|
43
44
|
grant: core_1.Flags.string({ description: 'Grant id supplying the watch credentials' }),
|
|
44
|
-
deadline: core_1.Flags.string({
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
deadline: core_1.Flags.string({
|
|
46
|
+
description: 'When the watch must stop (predicate form, required — refused on a recipe watch, which ends through its --wait)',
|
|
47
|
+
}),
|
|
48
|
+
'check-every': core_1.Flags.string({
|
|
49
|
+
description: 'Observation interval (predicate form — refused on a recipe watch)',
|
|
50
|
+
}),
|
|
51
|
+
'max-checks': core_1.Flags.integer({
|
|
52
|
+
description: 'Observation cap (predicate form — refused on a recipe watch)',
|
|
53
|
+
}),
|
|
47
54
|
'root-path': core_1.Flags.string({ description: 'JSON root path inside the response' }),
|
|
48
55
|
'resume-prompt': core_1.Flags.string({ description: 'What to tell the settling turn' }),
|
|
49
56
|
// recipe form
|
|
@@ -53,10 +60,15 @@ class FollowupsWatch extends base_command_1.BaseCommand {
|
|
|
53
60
|
success: core_1.Flags.string({ description: 'What state means the wait resolved (recipe form)' }),
|
|
54
61
|
abort: core_1.Flags.string({ description: 'When to stop and escalate (recipe form)' }),
|
|
55
62
|
wait: core_1.Flags.string({
|
|
56
|
-
description: 'Wait kind (recipe form)',
|
|
63
|
+
description: 'Wait kind (recipe form, required)',
|
|
57
64
|
options: [...followups_1.WATCH_WAIT_KINDS],
|
|
58
65
|
}),
|
|
59
|
-
'wait-at': core_1.Flags.string({
|
|
66
|
+
'wait-at': core_1.Flags.string({
|
|
67
|
+
// Naming both shapes here and in the server's rejection, because the
|
|
68
|
+
// duration grammar is a shorthand and not ISO-8601: `PT45M` is refused
|
|
69
|
+
// (OSK-10392).
|
|
70
|
+
description: 'When --wait clock fires: an ISO-8601 instant, or a duration from now (45m, 2h, 3d, 1w)',
|
|
71
|
+
}),
|
|
60
72
|
'wait-entity': core_1.Flags.string({ description: 'Entity type for --wait event' }),
|
|
61
73
|
'wait-event': core_1.Flags.string({ description: 'Event type for --wait event' }),
|
|
62
74
|
'wait-filter-field': core_1.Flags.string({ description: 'Payload field for an event filter' }),
|
|
@@ -161,6 +173,19 @@ class FollowupsWatch extends base_command_1.BaseCommand {
|
|
|
161
173
|
});
|
|
162
174
|
}
|
|
163
175
|
}
|
|
176
|
+
const boundsRefusal = (0, followups_1.recipeWatchBoundsRefusal)(flags.wait, {
|
|
177
|
+
deadline: flags.deadline,
|
|
178
|
+
checkEvery: flags['check-every'],
|
|
179
|
+
maxChecks: flags['max-checks'],
|
|
180
|
+
});
|
|
181
|
+
if (boundsRefusal) {
|
|
182
|
+
this.failWithCliError({
|
|
183
|
+
message: boundsRefusal,
|
|
184
|
+
code: 'FOLLOWUP_INVALID_FIELD',
|
|
185
|
+
exit: 2,
|
|
186
|
+
retryable: false,
|
|
187
|
+
});
|
|
188
|
+
}
|
|
164
189
|
const wait = { kind: flags.wait };
|
|
165
190
|
if (flags.wait === 'clock') {
|
|
166
191
|
wait.at = flags['wait-at'];
|
|
@@ -188,6 +213,16 @@ class FollowupsWatch extends base_command_1.BaseCommand {
|
|
|
188
213
|
success: flags.success,
|
|
189
214
|
abort: flags.abort,
|
|
190
215
|
wait,
|
|
216
|
+
// Forwarded so the SERVER refuses them, rather than dropped here so
|
|
217
|
+
// nobody does (OSK-10407). These are predicate-only bounds; this branch
|
|
218
|
+
// used to assemble the five fields above and silently discard the rest,
|
|
219
|
+
// so `--deadline 7d` armed a watch and reported success having stored
|
|
220
|
+
// no deadline. The rule that answers now lives once, in
|
|
221
|
+
// `normalizeFollowUpInput`, so the CLI and the agent-facing paths
|
|
222
|
+
// cannot drift into disagreeing about which form owns a flag.
|
|
223
|
+
...(flags.deadline !== undefined ? { deadline: flags.deadline } : {}),
|
|
224
|
+
...(flags['check-every'] !== undefined ? { checkEvery: flags['check-every'] } : {}),
|
|
225
|
+
...(flags['max-checks'] !== undefined ? { maxChecks: flags['max-checks'] } : {}),
|
|
191
226
|
});
|
|
192
227
|
}
|
|
193
228
|
let response;
|
|
@@ -15,6 +15,7 @@ export default class InitiativesList extends BaseCommand {
|
|
|
15
15
|
state: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
16
16
|
pending: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
17
17
|
limit: import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
18
|
+
cursor: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
18
19
|
};
|
|
19
20
|
run(): Promise<void>;
|
|
20
21
|
}
|