@skrr-ai/cli 0.1.116 → 0.1.117
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/base-command.d.ts +21 -0
- package/dist/base-command.js +95 -8
- package/dist/commands/actions/install.d.ts +1 -0
- package/dist/commands/actions/install.js +46 -1
- package/dist/commands/commitments/create.d.ts +21 -2
- package/dist/commands/commitments/create.js +74 -4
- package/dist/commands/convos/recovery.js +12 -4
- package/dist/commands/followups/plans/list.js +1 -1
- package/dist/commands/guide.d.ts +21 -0
- package/dist/commands/guide.js +46 -0
- package/dist/commands/instructions/guide.js +34 -52
- package/dist/commands/memory/maintain.js +1 -1
- package/dist/commands/skills/install.d.ts +1 -0
- package/dist/commands/skills/install.js +41 -2
- package/dist/commands/slack/send-as-agent.js +3 -3
- package/dist/commands/spaces/create.js +8 -2
- package/dist/commands/spaces/guide.d.ts +21 -0
- package/dist/commands/spaces/guide.js +40 -0
- package/dist/commands/spaces/index.d.ts +0 -1
- package/dist/commands/spaces/index.js +1 -6
- package/dist/commands/tasks/checkout.js +2 -3
- package/dist/commands/tasks/comments/add.js +3 -5
- package/dist/commands/tasks/complete.js +2 -3
- package/dist/commands/tasks/deliverable/add.d.ts +1 -1
- package/dist/commands/tasks/deliverable/add.js +4 -7
- package/dist/commands/tasks/expectations/assess.js +2 -2
- package/dist/commands/tasks/guide.d.ts +8 -0
- package/dist/commands/tasks/guide.js +23 -10
- package/dist/commands/tasks/report.js +9 -5
- package/dist/commands/tasks/resource/add.js +2 -3
- package/dist/commands/tasks/result/submit.js +2 -3
- package/dist/commands/tasks/resume/save.js +2 -3
- package/dist/commands/tasks/review.js +2 -3
- package/dist/commands/tasks/triage.js +2 -1
- package/dist/commands/tasks/updates/add.js +2 -3
- package/dist/generated/agent-guides.json +8290 -0
- package/dist/generated/managed-instruction-guides.json +1 -1
- package/dist/help.js +4 -3
- package/dist/hooks/command-not-found.js +1 -1
- package/dist/lib/agent-guide-reference-gate.d.ts +28 -0
- package/dist/lib/agent-guide-reference-gate.js +186 -0
- package/dist/lib/agent-guides.d.ts +51 -0
- package/dist/lib/agent-guides.js +170 -0
- package/dist/lib/command-miss.d.ts +13 -2
- package/dist/lib/command-miss.js +134 -8
- package/dist/lib/guide-pointer.d.ts +15 -0
- package/dist/lib/guide-pointer.js +51 -0
- package/dist/lib/lookbackPlans.d.ts +3 -1
- package/dist/lib/lookbackPlans.js +9 -0
- package/dist/lib/outbox.d.ts +0 -14
- package/dist/lib/outbox.js +0 -21
- package/dist/lib/roles.d.ts +1 -1
- package/dist/lib/task-batch.d.ts +10 -7
- package/dist/lib/task-batch.js +5 -20
- package/dist/lib/task-operations.d.ts +8 -20
- package/dist/lib/task-operations.js +9 -94
- package/dist/lib/task-preflight.js +70 -33
- package/dist/lib/usage-discovery.d.ts +4 -0
- package/dist/lib/usage-discovery.js +5 -0
- package/dist/lib/voice-call-intent.js +3 -1
- package/dist/node_modules/@skrr-ai/data-provider/index.js +6593 -6383
- package/oclif.manifest.json +228 -13
- package/package.json +4 -2
package/dist/base-command.d.ts
CHANGED
|
@@ -477,6 +477,12 @@ export interface ParsedGlobals {
|
|
|
477
477
|
workspace?: string;
|
|
478
478
|
}
|
|
479
479
|
export declare function parseGlobalFlags(argv: readonly string[]): ParsedGlobals;
|
|
480
|
+
/**
|
|
481
|
+
* The typed refusal code an API error body carries, wherever this codebase has
|
|
482
|
+
* put it: canonical `code` (or `errorType`) first, then the legacy
|
|
483
|
+
* code-spelled-in-`error` shape.
|
|
484
|
+
*/
|
|
485
|
+
export declare function refusalCodeOf(body: Record<string, unknown> | null | undefined): string | undefined;
|
|
480
486
|
/**
|
|
481
487
|
* The typed `code` and message an API refusal carried, read the way
|
|
482
488
|
* `handleApiError` reads them, for a command that answers one code itself
|
|
@@ -621,6 +627,21 @@ export declare function errorBodyMessage(body: unknown): string | undefined;
|
|
|
621
627
|
* from there, so no caller reads two places. A lifted `details.message` cannot replace it.
|
|
622
628
|
*/
|
|
623
629
|
export declare function envelopeDetails(body: Record<string, unknown> | null | undefined): unknown;
|
|
630
|
+
type UnsupportedFlagRemedyTarget = {
|
|
631
|
+
command: string;
|
|
632
|
+
flags: readonly string[];
|
|
633
|
+
};
|
|
634
|
+
type UnsupportedFlagRemedy = {
|
|
635
|
+
fix: string;
|
|
636
|
+
targets: readonly UnsupportedFlagRemedyTarget[];
|
|
637
|
+
};
|
|
638
|
+
/**
|
|
639
|
+
* Specific corrections for habitual flags that look plausible but do not belong
|
|
640
|
+
* to the command that received them. Keep the replacement command and every
|
|
641
|
+
* flag it names explicit: the spec checks this table against the shipped
|
|
642
|
+
* manifest, so a useful refusal cannot slowly point at a removed form.
|
|
643
|
+
*/
|
|
644
|
+
export declare const UNSUPPORTED_FLAG_REMEDIES: Readonly<Record<string, Readonly<Record<string, UnsupportedFlagRemedy>>>>;
|
|
624
645
|
/**
|
|
625
646
|
* The hint for a `Nonexistent flags:` refusal, or null. Two cases:
|
|
626
647
|
* - a flag retired from THIS command, which this command does not define again: where it went;
|
package/dist/base-command.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Flags = exports.BaseCommand = exports.resolveProfileFromArgv = void 0;
|
|
3
|
+
exports.Flags = exports.UNSUPPORTED_FLAG_REMEDIES = exports.BaseCommand = exports.resolveProfileFromArgv = void 0;
|
|
4
4
|
exports.assigneePayloadNeedsResolution = assigneePayloadNeedsResolution;
|
|
5
5
|
exports.parseGlobalFlags = parseGlobalFlags;
|
|
6
|
+
exports.refusalCodeOf = refusalCodeOf;
|
|
6
7
|
exports.apiRefusal = apiRefusal;
|
|
7
8
|
exports.withSubject = withSubject;
|
|
8
9
|
exports.describeHarnessUnavailable = describeHarnessUnavailable;
|
|
@@ -31,6 +32,7 @@ const json_mode_1 = require("./lib/json-mode");
|
|
|
31
32
|
const failed_lookup_1 = require("./lib/failed-lookup");
|
|
32
33
|
const internal_id_1 = require("./lib/internal-id");
|
|
33
34
|
const http_error_1 = require("./lib/http-error");
|
|
35
|
+
const guide_pointer_1 = require("./lib/guide-pointer");
|
|
34
36
|
// Re-exported from its home in `lib/keychain`, beside the other profile
|
|
35
37
|
// functions. It lived here while `init()` was its only caller; a lib module
|
|
36
38
|
// needing it would otherwise have to import the command base class, and with
|
|
@@ -1279,6 +1281,10 @@ class BaseCommand extends core_1.Command {
|
|
|
1279
1281
|
if (retiredHint) {
|
|
1280
1282
|
err.message = `${err.message}\n\n${retiredHint}`;
|
|
1281
1283
|
}
|
|
1284
|
+
const unsupportedFlagHint = unsupportedFlagRemedyForMessage(err.message || '', this.id);
|
|
1285
|
+
if (unsupportedFlagHint && !err.message.includes(unsupportedFlagHint.fix)) {
|
|
1286
|
+
err.message = `${err.message}\n\n${unsupportedFlagHint.fix}`;
|
|
1287
|
+
}
|
|
1282
1288
|
// Sibling domains spell one lifecycle differently (`in_progress` for a
|
|
1283
1289
|
// space, `active` for a goal), and oclif's enum refusal named neither the
|
|
1284
1290
|
// difference nor the value to use (OSK-9735).
|
|
@@ -1296,13 +1302,19 @@ class BaseCommand extends core_1.Command {
|
|
|
1296
1302
|
const httpBody = (0, http_error_1.httpBodyOf)(err);
|
|
1297
1303
|
const httpStatus = (0, http_error_1.httpStatusOf)(err);
|
|
1298
1304
|
if (httpBody && httpStatus !== undefined && httpStatus >= 400) {
|
|
1299
|
-
const bodyCode =
|
|
1305
|
+
const bodyCode = refusalCodeOf(httpBody);
|
|
1300
1306
|
const bodyMessage = stringProp(httpBody, 'message') || stringProp(httpBody, 'error');
|
|
1301
1307
|
err.code ??= bodyCode || `HTTP_${httpStatus}`;
|
|
1302
1308
|
if (bodyMessage && !err.message.includes(bodyMessage)) {
|
|
1303
1309
|
err.message = `${bodyMessage} — ${err.message}`;
|
|
1304
1310
|
}
|
|
1305
1311
|
}
|
|
1312
|
+
// A refusal a guide section explains points the reader at it (OSK-17977):
|
|
1313
|
+
// text gets a `Guide:` line as the message's last line, --json a `guide`
|
|
1314
|
+
// field. Resolved offline from the bundled registry — never a request on
|
|
1315
|
+
// an already-failing path — and absent for a code nothing explains.
|
|
1316
|
+
const code = err.code ?? parseCliErrorCode(err);
|
|
1317
|
+
const guide = (0, guide_pointer_1.agentGuidePointerFor)(code);
|
|
1306
1318
|
if (this.wantsJsonOutput()) {
|
|
1307
1319
|
const exit = err.exitCode ?? err.oclif?.exit ?? 1;
|
|
1308
1320
|
process.exitCode = exit;
|
|
@@ -1310,17 +1322,23 @@ class BaseCommand extends core_1.Command {
|
|
|
1310
1322
|
this.log(JSON.stringify(this.jsonOperationError({
|
|
1311
1323
|
ok: false,
|
|
1312
1324
|
error: {
|
|
1313
|
-
code
|
|
1325
|
+
code,
|
|
1314
1326
|
message: err.message || String(err),
|
|
1315
1327
|
retryable: err.retryable ?? false,
|
|
1316
1328
|
command: this.id ?? null,
|
|
1317
1329
|
server: this.cliConfig?.baseURL ?? null,
|
|
1318
1330
|
...parseErrorRemedy(err, this.id, this.config?.bin),
|
|
1331
|
+
...(guide ? { guide } : {}),
|
|
1319
1332
|
...(details ? { details } : {}),
|
|
1320
1333
|
},
|
|
1321
1334
|
}), null, 2));
|
|
1322
1335
|
return;
|
|
1323
1336
|
}
|
|
1337
|
+
if (guide) {
|
|
1338
|
+
const line = (0, guide_pointer_1.agentGuidePointerLine)(guide);
|
|
1339
|
+
if (!err.message.includes(line))
|
|
1340
|
+
err.message = `${err.message}\n\n${line}`;
|
|
1341
|
+
}
|
|
1324
1342
|
return super.catch(err);
|
|
1325
1343
|
}
|
|
1326
1344
|
error(input, options = {}) {
|
|
@@ -1390,7 +1408,7 @@ class BaseCommand extends core_1.Command {
|
|
|
1390
1408
|
this.lastApiRequestId = e.requestId;
|
|
1391
1409
|
this.lastRetryAfterMs = e.retryAfterMs;
|
|
1392
1410
|
const body = parseErrorBody(e.body);
|
|
1393
|
-
const bodyCode =
|
|
1411
|
+
const bodyCode = refusalCodeOf(body);
|
|
1394
1412
|
// A body path the person never typed is read back as the flag that wrote it (OSK-15313).
|
|
1395
1413
|
// The server answers every error with `message` (OSK-16986); `errorBodyMessage` keeps the
|
|
1396
1414
|
// older `error` string and the nested `/v1` shape as fallbacks for a server without it.
|
|
@@ -1987,6 +2005,9 @@ class BaseCommand extends core_1.Command {
|
|
|
1987
2005
|
/** E6: the server's `Retry-After` for the refused call, when it was a 429. */
|
|
1988
2006
|
lastRetryAfterMs;
|
|
1989
2007
|
writeJsonCliError({ message, code, status, exit, retryable, details, requestId, }) {
|
|
2008
|
+
// The guide section that explains this code, when one does — the `guide`
|
|
2009
|
+
// half of the `Guide:` line the text path appends.
|
|
2010
|
+
const guide = (0, guide_pointer_1.agentGuidePointerFor)(code);
|
|
1990
2011
|
this.log(JSON.stringify(this.jsonOperationError({
|
|
1991
2012
|
ok: false,
|
|
1992
2013
|
error: {
|
|
@@ -1996,6 +2017,7 @@ class BaseCommand extends core_1.Command {
|
|
|
1996
2017
|
retryable,
|
|
1997
2018
|
command: this.id ?? null,
|
|
1998
2019
|
server: this.cliConfig?.baseURL ?? null,
|
|
2020
|
+
...(guide ? { guide } : {}),
|
|
1999
2021
|
// The id the server logged this refusal against. Without it, a
|
|
2000
2022
|
// refused call can only be matched to a log line by guessing from
|
|
2001
2023
|
// timestamps — which, with several clients on one account,
|
|
@@ -2105,6 +2127,27 @@ function stringProp(obj, key) {
|
|
|
2105
2127
|
const value = obj?.[key];
|
|
2106
2128
|
return typeof value === 'string' && value.trim() ? value.trim() : undefined;
|
|
2107
2129
|
}
|
|
2130
|
+
/**
|
|
2131
|
+
* Lower_snake is how the scoped-Memory REST surface (and older routes like it)
|
|
2132
|
+
* spelled a refusal code in `error`, where the canonical envelope expects human
|
|
2133
|
+
* text (OSK-18250). A released server still answers that way, so a code-shaped
|
|
2134
|
+
* `error` is read as the code — reported in the upper-case spelling the code
|
|
2135
|
+
* vocabulary and `parseMemoryApiError` already use. Anything else in `error`
|
|
2136
|
+
* (a sentence, a bare word) is text and stays out of `code`.
|
|
2137
|
+
*/
|
|
2138
|
+
const LEGACY_ERROR_FIELD_CODE = /^[a-z][a-z0-9]*(?:_[a-z0-9]+)+$/;
|
|
2139
|
+
/**
|
|
2140
|
+
* The typed refusal code an API error body carries, wherever this codebase has
|
|
2141
|
+
* put it: canonical `code` (or `errorType`) first, then the legacy
|
|
2142
|
+
* code-spelled-in-`error` shape.
|
|
2143
|
+
*/
|
|
2144
|
+
function refusalCodeOf(body) {
|
|
2145
|
+
const direct = stringProp(body ?? null, 'code') || stringProp(body ?? null, 'errorType');
|
|
2146
|
+
if (direct)
|
|
2147
|
+
return direct;
|
|
2148
|
+
const legacy = stringProp(body ?? null, 'error');
|
|
2149
|
+
return legacy && LEGACY_ERROR_FIELD_CODE.test(legacy) ? legacy.toUpperCase() : undefined;
|
|
2150
|
+
}
|
|
2108
2151
|
/**
|
|
2109
2152
|
* The typed `code` and message an API refusal carried, read the way
|
|
2110
2153
|
* `handleApiError` reads them, for a command that answers one code itself
|
|
@@ -2115,7 +2158,7 @@ function apiRefusal(err) {
|
|
|
2115
2158
|
return {};
|
|
2116
2159
|
const body = parseErrorBody(err.body);
|
|
2117
2160
|
return {
|
|
2118
|
-
code:
|
|
2161
|
+
code: refusalCodeOf(body),
|
|
2119
2162
|
message: errorBodyMessage(body),
|
|
2120
2163
|
...(body ? { body } : {}),
|
|
2121
2164
|
};
|
|
@@ -2432,7 +2475,7 @@ function describeDaemonScopedCredential(bin, scope = 'daemon', source) {
|
|
|
2432
2475
|
function isTypedServerRefusal(body) {
|
|
2433
2476
|
if (!body || typeof body !== 'object')
|
|
2434
2477
|
return false;
|
|
2435
|
-
const code =
|
|
2478
|
+
const code = refusalCodeOf(body);
|
|
2436
2479
|
if (!code)
|
|
2437
2480
|
return false;
|
|
2438
2481
|
return (typeof body.cause === 'string' || typeof body.remedy === 'string' || body.retryable === false);
|
|
@@ -2455,7 +2498,7 @@ function isTypedServerRefusal(body) {
|
|
|
2455
2498
|
function isApplicationCodedUnavailable(status, body) {
|
|
2456
2499
|
if (status !== 502 && status !== 503 && status !== 504)
|
|
2457
2500
|
return false;
|
|
2458
|
-
return Boolean(
|
|
2501
|
+
return Boolean(refusalCodeOf(body));
|
|
2459
2502
|
}
|
|
2460
2503
|
/**
|
|
2461
2504
|
* The sentence `redactServerErrorResponses` substitutes for a 5xx message in
|
|
@@ -2470,7 +2513,7 @@ function isRetryableFailure(status, body) {
|
|
|
2470
2513
|
const declared = body?.retryable;
|
|
2471
2514
|
if (typeof declared === 'boolean')
|
|
2472
2515
|
return declared;
|
|
2473
|
-
const code =
|
|
2516
|
+
const code = refusalCodeOf(body);
|
|
2474
2517
|
if (code && TERMINAL_ERROR_CODES.has(code))
|
|
2475
2518
|
return false;
|
|
2476
2519
|
return status === 408 || status === 425 || status === 429 || !!(status && status >= 500);
|
|
@@ -2600,6 +2643,41 @@ function envelopeDetails(body) {
|
|
|
2600
2643
|
* "--outcome is now --summary" (OSK-16494). A rename is a fact about one command.
|
|
2601
2644
|
*/
|
|
2602
2645
|
const RETIRED_FLAG_COMMANDS = new Set(['tasks:complete', 'tasks:result:submit']);
|
|
2646
|
+
/**
|
|
2647
|
+
* Specific corrections for habitual flags that look plausible but do not belong
|
|
2648
|
+
* to the command that received them. Keep the replacement command and every
|
|
2649
|
+
* flag it names explicit: the spec checks this table against the shipped
|
|
2650
|
+
* manifest, so a useful refusal cannot slowly point at a removed form.
|
|
2651
|
+
*/
|
|
2652
|
+
exports.UNSUPPORTED_FLAG_REMEDIES = {
|
|
2653
|
+
'spaces:create': {
|
|
2654
|
+
agent: {
|
|
2655
|
+
fix: 'A Space is created for the authenticated caller. Add an Agent after creation with ' +
|
|
2656
|
+
'`skrr spaces members add <space-id> --agent <agent-id>`.',
|
|
2657
|
+
targets: [{ command: 'spaces:members:add', flags: ['agent'] }],
|
|
2658
|
+
},
|
|
2659
|
+
},
|
|
2660
|
+
'tasks:create': {
|
|
2661
|
+
agent: {
|
|
2662
|
+
fix: 'Assign the Task with `--assignee-agent <agent-id>`; `--agent` does not set Task assignees.',
|
|
2663
|
+
targets: [{ command: 'tasks:create', flags: ['assignee-agent'] }],
|
|
2664
|
+
},
|
|
2665
|
+
},
|
|
2666
|
+
'followups:checkin': {
|
|
2667
|
+
check: {
|
|
2668
|
+
fix: 'A check-in is only a timed return. To check a condition, use ' +
|
|
2669
|
+
'`skrr followups watch --check <check> --success <condition> --abort <condition> --wait <kind>`.',
|
|
2670
|
+
targets: [{ command: 'followups:watch', flags: ['check', 'success', 'abort', 'wait'] }],
|
|
2671
|
+
},
|
|
2672
|
+
},
|
|
2673
|
+
};
|
|
2674
|
+
function unsupportedFlagRemedy(commandId, flag) {
|
|
2675
|
+
return commandId ? exports.UNSUPPORTED_FLAG_REMEDIES[commandId]?.[flag] : undefined;
|
|
2676
|
+
}
|
|
2677
|
+
function unsupportedFlagRemedyForMessage(message, commandId) {
|
|
2678
|
+
const match = /Nonexistent flag[s]?:?\s*(-{1,2}[\w-]+)/i.exec(message);
|
|
2679
|
+
return match ? unsupportedFlagRemedy(commandId, match[1].replace(/^-+/, '')) : undefined;
|
|
2680
|
+
}
|
|
2603
2681
|
/**
|
|
2604
2682
|
* The hint for a `Nonexistent flags:` refusal, or null. Two cases:
|
|
2605
2683
|
* - a flag retired from THIS command, which this command does not define again: where it went;
|
|
@@ -2651,6 +2729,15 @@ function parseErrorRemedy(err, commandId, bin = 'skrr') {
|
|
|
2651
2729
|
};
|
|
2652
2730
|
}
|
|
2653
2731
|
const nonexistent = /Nonexistent flag[s]?:?\s*(-{1,2}[\w-]+)(?:[ =]([^\s,][^,\n]*))?/i.exec(message);
|
|
2732
|
+
const unsupportedFlagHint = nonexistent
|
|
2733
|
+
? unsupportedFlagRemedy(commandId, nonexistent[1].replace(/^-+/, ''))
|
|
2734
|
+
: undefined;
|
|
2735
|
+
if (unsupportedFlagHint) {
|
|
2736
|
+
return {
|
|
2737
|
+
flag: nonexistent[1].replace(/^-+/, ''),
|
|
2738
|
+
fix: unsupportedFlagHint.fix,
|
|
2739
|
+
};
|
|
2740
|
+
}
|
|
2654
2741
|
if (nonexistent?.[2]) {
|
|
2655
2742
|
// `"--outcome failed"` arrived as ONE argument: the flag may well exist, so
|
|
2656
2743
|
// "remove it" would be wrong advice. Same case retiredFlagHint explains in text.
|
|
@@ -8,6 +8,7 @@ export default class ActionsInstall extends BaseCommand {
|
|
|
8
8
|
static flags: {
|
|
9
9
|
agent: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
10
|
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
11
|
+
yes: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
11
12
|
};
|
|
12
13
|
run(): Promise<void>;
|
|
13
14
|
}
|
|
@@ -3,11 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const core_1 = require("@oclif/core");
|
|
4
4
|
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
5
5
|
const base_command_1 = require("../../base-command");
|
|
6
|
+
const prompt_1 = require("../../lib/prompt");
|
|
6
7
|
const agent_actions_1 = require("../../lib/agent-actions");
|
|
7
8
|
class ActionsInstall extends base_command_1.BaseCommand {
|
|
8
|
-
static description = 'Install an action listing into an agent';
|
|
9
|
+
static description = 'Install an action listing into an agent. A paid listing shows its price and asks you to confirm first.';
|
|
9
10
|
static examples = [
|
|
10
11
|
'<%= config.bin %> actions install <listing-id> --agent <agent-id>',
|
|
12
|
+
'<%= config.bin %> actions install <listing-id> --agent <agent-id> --yes',
|
|
11
13
|
'<%= config.bin %> actions install <listing-id> --agent <agent-id> --json',
|
|
12
14
|
];
|
|
13
15
|
static args = {
|
|
@@ -16,15 +18,58 @@ class ActionsInstall extends base_command_1.BaseCommand {
|
|
|
16
18
|
static flags = {
|
|
17
19
|
agent: core_1.Flags.string({ description: 'Target agent ID', required: true }),
|
|
18
20
|
json: core_1.Flags.boolean({ description: 'Output install response as JSON' }),
|
|
21
|
+
yes: core_1.Flags.boolean({
|
|
22
|
+
char: 'y',
|
|
23
|
+
description: 'Confirm a paid install without prompting. The price is still printed.',
|
|
24
|
+
}),
|
|
19
25
|
};
|
|
20
26
|
async run() {
|
|
21
27
|
this.requireAuth();
|
|
22
28
|
const { args, flags } = await this.parse(ActionsInstall);
|
|
29
|
+
// What installing would charge NOW, read before the install sends it.
|
|
30
|
+
// A paid listing shows its price and asks first; the install then pins
|
|
31
|
+
// what was shown, so a listing whose price moved in between is refused
|
|
32
|
+
// rather than charged (OSK-18042 — same convention as `store install`,
|
|
33
|
+
// OSK-12240).
|
|
34
|
+
let listing;
|
|
35
|
+
try {
|
|
36
|
+
listing = await data_provider_1.dataService.getActionListing(args.id);
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
this.handleApiError(err);
|
|
40
|
+
}
|
|
41
|
+
let charge = Number(listing.price) || 0;
|
|
42
|
+
if (charge > 0 && String(listing.author) === (await this.resolveCurrentUserId())) {
|
|
43
|
+
// Installing a listing you published is never charged — pin what the
|
|
44
|
+
// server would actually charge, not the sticker price.
|
|
45
|
+
charge = 0;
|
|
46
|
+
}
|
|
47
|
+
if (charge > 0) {
|
|
48
|
+
const name = listing.displayName || listing.name || args.id;
|
|
49
|
+
// Printed before any prompt and even with --yes, so a scripted purchase
|
|
50
|
+
// still leaves the price it agreed to in its own output.
|
|
51
|
+
this.logToStderr(`${name} is a paid action.`);
|
|
52
|
+
this.logToStderr(` Price: ${(0, data_provider_1.formatStoreAcquisitionPrice)(charge)} USD`);
|
|
53
|
+
if (listing.offerVersionId) {
|
|
54
|
+
this.logToStderr(` Offer: ${listing.offerVersionId}`);
|
|
55
|
+
}
|
|
56
|
+
const confirmed = await (0, prompt_1.confirmDestructive)(`Buy ${name} for ${(0, data_provider_1.formatStoreAcquisitionPrice)(charge)}?`, flags.yes).catch((err) => this.error(err.message, { exit: err.exit ?? 1 }));
|
|
57
|
+
if (!confirmed) {
|
|
58
|
+
this.log('Cancelled. Nothing was bought.');
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
23
62
|
let response;
|
|
24
63
|
try {
|
|
25
64
|
response = await data_provider_1.dataService.installActionListing({
|
|
26
65
|
listingId: args.id,
|
|
27
66
|
targetAgentId: flags.agent,
|
|
67
|
+
// Pin what the person was shown: the charge always, the offer when
|
|
68
|
+
// there is one to charge under.
|
|
69
|
+
expectedPrice: charge,
|
|
70
|
+
...(charge > 0 && listing.offerVersionId
|
|
71
|
+
? { expectedOfferVersionId: listing.offerVersionId }
|
|
72
|
+
: {}),
|
|
28
73
|
});
|
|
29
74
|
}
|
|
30
75
|
catch (err) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { BaseCommand } from '../../base-command';
|
|
2
|
+
import { type AgentGuidePointer } from '../../lib/guide-pointer';
|
|
2
3
|
/**
|
|
3
4
|
* True only when the authored create body can materialize at least one event
|
|
4
5
|
* binding. A polling-only source must not make `--event-driven` look successful
|
|
@@ -26,13 +27,30 @@ export declare function createCadenceFromFlags({ eventDriven, cadence: cadenceIn
|
|
|
26
27
|
* be said out loud at the CLI boundary; otherwise a successful create response
|
|
27
28
|
* reads like the requested autonomy is live when something else is running.
|
|
28
29
|
*/
|
|
30
|
+
/**
|
|
31
|
+
* A refused `--activate` leaves a draft, and the draft's id is the answer the
|
|
32
|
+
* caller needs — so the refusal is reported on the result, never thrown over
|
|
33
|
+
* it. `{code, reason, fix}` mirrors the MCP surface's refusal; `guide` points
|
|
34
|
+
* at the section that explains the code when one does (resolved offline).
|
|
35
|
+
*/
|
|
36
|
+
export declare function commitmentActivationRefusal(err: unknown, { id, bin }: {
|
|
37
|
+
id: string;
|
|
38
|
+
bin: string;
|
|
39
|
+
}): {
|
|
40
|
+
code: string;
|
|
41
|
+
reason: string;
|
|
42
|
+
fix: string;
|
|
43
|
+
guide?: AgentGuidePointer;
|
|
44
|
+
};
|
|
29
45
|
/**
|
|
30
46
|
* `skrr commitments create` — author a durable commitment contract.
|
|
31
47
|
*
|
|
32
48
|
* A Commitment is a standing commitment ("hold this outcome true"), watched on a
|
|
33
49
|
* cadence by its own control loop — not a task. Create it `draft` first and
|
|
34
|
-
* activate once the contract reads right
|
|
35
|
-
*
|
|
50
|
+
* activate once the contract reads right — or pass `--activate` to turn it on
|
|
51
|
+
* in the same call (the same resume + Preflight boundary `commitments resume`
|
|
52
|
+
* runs; a refusal keeps the draft and says why). An `active` commitment with a
|
|
53
|
+
* non-manual cadence starts spending compute on every check.
|
|
36
54
|
*
|
|
37
55
|
* For a natural-language draft instead of flags, use `skrr commitments plan`.
|
|
38
56
|
*/
|
|
@@ -51,6 +69,7 @@ export default class CommitmentsCreate extends BaseCommand {
|
|
|
51
69
|
'agent-directive-file': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
52
70
|
goal: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
53
71
|
status: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
72
|
+
activate: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
54
73
|
deadline: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
55
74
|
criterion: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
56
75
|
evaluator: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
@@ -3,9 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.hasEventCapableWatchedSource = hasEventCapableWatchedSource;
|
|
4
4
|
exports.assertEventDrivenWatchedSource = assertEventDrivenWatchedSource;
|
|
5
5
|
exports.createCadenceFromFlags = createCadenceFromFlags;
|
|
6
|
+
exports.commitmentActivationRefusal = commitmentActivationRefusal;
|
|
6
7
|
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
7
8
|
const core_1 = require("@oclif/core");
|
|
8
9
|
const base_command_1 = require("../../base-command");
|
|
10
|
+
const guide_pointer_1 = require("../../lib/guide-pointer");
|
|
9
11
|
const web_url_1 = require("../../lib/web-url");
|
|
10
12
|
const prompt_1 = require("../../lib/prompt");
|
|
11
13
|
const triggers_1 = require("../../lib/triggers");
|
|
@@ -145,13 +147,37 @@ function createCadenceFromFlags({ eventDriven, cadence: cadenceInput, cadenceMod
|
|
|
145
147
|
* be said out loud at the CLI boundary; otherwise a successful create response
|
|
146
148
|
* reads like the requested autonomy is live when something else is running.
|
|
147
149
|
*/
|
|
150
|
+
/**
|
|
151
|
+
* A refused `--activate` leaves a draft, and the draft's id is the answer the
|
|
152
|
+
* caller needs — so the refusal is reported on the result, never thrown over
|
|
153
|
+
* it. `{code, reason, fix}` mirrors the MCP surface's refusal; `guide` points
|
|
154
|
+
* at the section that explains the code when one does (resolved offline).
|
|
155
|
+
*/
|
|
156
|
+
function commitmentActivationRefusal(err, { id, bin }) {
|
|
157
|
+
const refusal = (0, base_command_1.apiRefusal)(err);
|
|
158
|
+
const errorField = refusal.body?.error;
|
|
159
|
+
const code = refusal.code ||
|
|
160
|
+
(typeof errorField === 'string' && /^[A-Za-z][A-Za-z0-9_]*$/.test(errorField)
|
|
161
|
+
? errorField
|
|
162
|
+
: undefined) ||
|
|
163
|
+
'COMMITMENT_ACTIVATION_REFUSED';
|
|
164
|
+
const guide = (0, guide_pointer_1.agentGuidePointerFor)(code);
|
|
165
|
+
return {
|
|
166
|
+
code,
|
|
167
|
+
reason: refusal.message || (err instanceof Error ? err.message : 'Activation was refused.'),
|
|
168
|
+
fix: (0, data_provider_1.describeCommitmentActivationFix)(code === 'COMMITMENT_ACTIVATION_REFUSED' ? undefined : code, { turnOn: `run \`${bin} commitments resume ${id}\`` }),
|
|
169
|
+
...(guide ? { guide } : {}),
|
|
170
|
+
};
|
|
171
|
+
}
|
|
148
172
|
/**
|
|
149
173
|
* `skrr commitments create` — author a durable commitment contract.
|
|
150
174
|
*
|
|
151
175
|
* A Commitment is a standing commitment ("hold this outcome true"), watched on a
|
|
152
176
|
* cadence by its own control loop — not a task. Create it `draft` first and
|
|
153
|
-
* activate once the contract reads right
|
|
154
|
-
*
|
|
177
|
+
* activate once the contract reads right — or pass `--activate` to turn it on
|
|
178
|
+
* in the same call (the same resume + Preflight boundary `commitments resume`
|
|
179
|
+
* runs; a refusal keeps the draft and says why). An `active` commitment with a
|
|
180
|
+
* non-manual cadence starts spending compute on every check.
|
|
155
181
|
*
|
|
156
182
|
* For a natural-language draft instead of flags, use `skrr commitments plan`.
|
|
157
183
|
*/
|
|
@@ -159,7 +185,7 @@ class CommitmentsCreate extends base_command_1.BaseCommand {
|
|
|
159
185
|
static description = 'Create a commitment (a durable agent contract). Its cadence is manual, an interval or daily clock times; ' +
|
|
160
186
|
'it has no weekday, holiday, business-day or trading-calendar fields';
|
|
161
187
|
static examples = [
|
|
162
|
-
'<%= config.bin %> commitments create --agent <agent-id> --title "Ship v2" --outcome "v2 is live for all users" --cadence 6h',
|
|
188
|
+
'<%= config.bin %> commitments create --agent <agent-id> --title "Ship v2" --outcome "v2 is live for all users" --cadence 6h --activate',
|
|
163
189
|
'<%= config.bin %> commitments create --agent <agent-id> --title "Hiring loop" --outcome "Every candidate hears back in 48h" --watch tasks --watch email --cadence 12h',
|
|
164
190
|
'<%= config.bin %> commitments create --agent <agent-id> --title "SLA" --outcome "p95 under 200ms" --criterion "p95 latency confirmed" --evaluator metric --measure <measure-id>',
|
|
165
191
|
'<%= config.bin %> commitments create --agent <agent-id> --title "AWS cost watch" --outcome "Cost regressions are investigated" --agent-directive-file ./aws-cost-policy.md',
|
|
@@ -218,6 +244,11 @@ JSON
|
|
|
218
244
|
description: 'Create as a draft (default); activate later with commitments resume',
|
|
219
245
|
options: ['draft'],
|
|
220
246
|
}),
|
|
247
|
+
activate: core_1.Flags.boolean({
|
|
248
|
+
description: 'Turn the commitment on right after creating it — the same resume + Preflight boundary ' +
|
|
249
|
+
"as `commitments resume`. A refused activation keeps the draft and reports the refusal's " +
|
|
250
|
+
'code, reason and fix.',
|
|
251
|
+
}),
|
|
221
252
|
deadline: core_1.Flags.string({ description: 'ISO-8601 deadline for an `achieve` commitment' }),
|
|
222
253
|
criterion: core_1.Flags.string({
|
|
223
254
|
description: 'Success criterion label (repeatable). Evaluated manually unless --evaluator/--measure is set.',
|
|
@@ -457,17 +488,56 @@ JSON
|
|
|
457
488
|
catch (err) {
|
|
458
489
|
this.handleApiError(err);
|
|
459
490
|
}
|
|
491
|
+
// `--activate` is the same resume + Preflight boundary `commitments
|
|
492
|
+
// resume` runs, composed onto the create so the caller gets one answer.
|
|
493
|
+
// A refusal is reported on the result — never thrown over the draft's id.
|
|
494
|
+
let activation = null;
|
|
495
|
+
if (flags.activate) {
|
|
496
|
+
try {
|
|
497
|
+
commitment = await commitments_1.commitmentApi.resume(String(commitment.id));
|
|
498
|
+
activation = { activated: true };
|
|
499
|
+
}
|
|
500
|
+
catch (err) {
|
|
501
|
+
activation = {
|
|
502
|
+
activated: false,
|
|
503
|
+
refusal: commitmentActivationRefusal(err, {
|
|
504
|
+
id: String(commitment.id),
|
|
505
|
+
bin: this.config.bin,
|
|
506
|
+
}),
|
|
507
|
+
};
|
|
508
|
+
// Report the row as it now is: a failed materialization rolls the
|
|
509
|
+
// activation back to paused, and printing the create-time snapshot
|
|
510
|
+
// would claim "draft" of a paused Commitment.
|
|
511
|
+
try {
|
|
512
|
+
const live = await commitments_1.commitmentApi.get(String(commitment.id));
|
|
513
|
+
if (live?.commitment)
|
|
514
|
+
commitment = live.commitment;
|
|
515
|
+
}
|
|
516
|
+
catch {
|
|
517
|
+
/* the refusal is the news; the create-time row is the fallback */
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
}
|
|
460
521
|
const warnings = (0, commitments_1.commitmentWriteWarnings)(commitment, { payload });
|
|
461
522
|
if (flags.json) {
|
|
462
523
|
this.log(JSON.stringify((0, web_url_1.withCommitmentUrl)(this.cliConfig.baseURL, {
|
|
463
524
|
...commitment,
|
|
525
|
+
...(activation ?? {}),
|
|
464
526
|
...(warnings.length ? { warnings } : {}),
|
|
465
527
|
}), null, 2));
|
|
466
528
|
return;
|
|
467
529
|
}
|
|
468
|
-
this.log('Created commitment:');
|
|
530
|
+
this.log(activation?.activated ? 'Created and activated commitment:' : 'Created commitment:');
|
|
469
531
|
(0, commitments_1.renderCommitmentSummary)(commitment, (line) => this.log(line));
|
|
470
532
|
(0, commitments_1.renderCommitmentWriteWarnings)(warnings, (line) => this.warn(line));
|
|
533
|
+
if (activation && !activation.activated) {
|
|
534
|
+
const { refusal } = activation;
|
|
535
|
+
this.warn(`Activation refused (${refusal.code}): ${refusal.reason}`);
|
|
536
|
+
if (refusal.fix)
|
|
537
|
+
this.warn(`Fix: ${refusal.fix}`);
|
|
538
|
+
if (refusal.guide)
|
|
539
|
+
this.warn(`Guide: ${refusal.guide.command}`);
|
|
540
|
+
}
|
|
471
541
|
}
|
|
472
542
|
}
|
|
473
543
|
exports.default = CommitmentsCreate;
|
|
@@ -7,7 +7,11 @@ class ConvosRecovery extends base_command_1.BaseCommand {
|
|
|
7
7
|
static description = 'Inspect interrupted native work, continue once, or dismiss its recovery offer';
|
|
8
8
|
static args = {
|
|
9
9
|
id: core_1.Args.string({ description: 'Conversation ID', required: true, ignoreStdin: true }),
|
|
10
|
-
action: core_1.Args.string({
|
|
10
|
+
action: core_1.Args.string({
|
|
11
|
+
options: ['list', 'continue', 'dismiss'],
|
|
12
|
+
default: 'list',
|
|
13
|
+
ignoreStdin: true,
|
|
14
|
+
}),
|
|
11
15
|
};
|
|
12
16
|
static flags = {
|
|
13
17
|
json: core_1.Flags.boolean({ description: 'Output JSON' }),
|
|
@@ -27,11 +31,15 @@ class ConvosRecovery extends base_command_1.BaseCommand {
|
|
|
27
31
|
try {
|
|
28
32
|
const path = `/api/convos/${encodeURIComponent(args.id)}/recovery`;
|
|
29
33
|
if (args.action === 'continue') {
|
|
30
|
-
result = await (0, api_fetch_1.apiFetch)('/api/agentic/chat', {
|
|
31
|
-
|
|
34
|
+
result = await (0, api_fetch_1.apiFetch)('/api/agentic/chat', {
|
|
35
|
+
method: 'POST',
|
|
36
|
+
body: { conversationId: args.id, recoveryOfferId: flags.offer },
|
|
37
|
+
});
|
|
32
38
|
}
|
|
33
39
|
else if (args.action === 'dismiss') {
|
|
34
|
-
result = await (0, api_fetch_1.apiFetch)(`${path}/${encodeURIComponent(flags.offer)}/dismiss`, {
|
|
40
|
+
result = await (0, api_fetch_1.apiFetch)(`${path}/${encodeURIComponent(flags.offer)}/dismiss`, {
|
|
41
|
+
method: 'POST',
|
|
42
|
+
});
|
|
35
43
|
}
|
|
36
44
|
else {
|
|
37
45
|
result = await (0, api_fetch_1.apiFetch)(path);
|
|
@@ -34,7 +34,7 @@ class LookbackPlansList extends base_command_1.BaseCommand {
|
|
|
34
34
|
return;
|
|
35
35
|
}
|
|
36
36
|
if (!result.plans.length) {
|
|
37
|
-
this.log(
|
|
37
|
+
this.log((0, lookbackPlans_1.lookbackPlansEmptyMessage)(result.scope));
|
|
38
38
|
return;
|
|
39
39
|
}
|
|
40
40
|
for (const plan of result.plans)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
export default class Guide extends Command {
|
|
3
|
+
static baseFlags: {
|
|
4
|
+
bare: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
5
|
+
token: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
6
|
+
workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
raw: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
9
|
+
};
|
|
10
|
+
static description: string;
|
|
11
|
+
static args: {
|
|
12
|
+
id: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
13
|
+
section: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
14
|
+
};
|
|
15
|
+
static flags: {
|
|
16
|
+
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
17
|
+
offline: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
18
|
+
};
|
|
19
|
+
static examples: string[];
|
|
20
|
+
run(): Promise<void>;
|
|
21
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
5
|
+
const base_command_1 = require("../base-command");
|
|
6
|
+
const agent_guides_1 = require("../lib/agent-guides");
|
|
7
|
+
// Documentation stays available when a daemon-issued Agent credential is
|
|
8
|
+
// unavailable. Do not run BaseCommand's mandatory credential initialization.
|
|
9
|
+
class Guide extends core_1.Command {
|
|
10
|
+
static baseFlags = base_command_1.BaseCommand.baseFlags;
|
|
11
|
+
static description = 'Read Skrr operation guides on demand';
|
|
12
|
+
static args = {
|
|
13
|
+
id: core_1.Args.string({ description: 'Guide id', ignoreStdin: true }),
|
|
14
|
+
section: core_1.Args.string({ description: 'Section id', ignoreStdin: true }),
|
|
15
|
+
};
|
|
16
|
+
static flags = {
|
|
17
|
+
json: core_1.Flags.boolean({ description: 'Output the guide and source provenance as JSON' }),
|
|
18
|
+
offline: core_1.Flags.boolean({
|
|
19
|
+
description: 'Read the bundled release guides without checking credentials or the server',
|
|
20
|
+
}),
|
|
21
|
+
};
|
|
22
|
+
static examples = [
|
|
23
|
+
'<%= config.bin %> guide',
|
|
24
|
+
'<%= config.bin %> guide tasks',
|
|
25
|
+
'<%= config.bin %> guide tasks updates --offline',
|
|
26
|
+
];
|
|
27
|
+
async run() {
|
|
28
|
+
const { args, flags } = await this.parse(Guide);
|
|
29
|
+
const request = {
|
|
30
|
+
...(args.id ? { id: args.id } : {}),
|
|
31
|
+
...(args.section ? { section: args.section } : {}),
|
|
32
|
+
};
|
|
33
|
+
const read = await (0, agent_guides_1.readAgentGuide)(request, flags);
|
|
34
|
+
if (!read.found)
|
|
35
|
+
return (0, agent_guides_1.writeAgentGuideMiss)(this, read.miss, flags.json);
|
|
36
|
+
if (flags.json) {
|
|
37
|
+
process.stdout.write((0, agent_guides_1.agentGuideJson)(read));
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const notice = (0, agent_guides_1.agentGuideFallbackNotice)(read);
|
|
41
|
+
if (notice)
|
|
42
|
+
process.stderr.write(`${notice}\n`);
|
|
43
|
+
process.stdout.write((0, data_provider_1.renderAgentGuideText)(read.response));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
exports.default = Guide;
|