@skrr-ai/cli 0.1.13 → 0.1.15
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 +12 -36
- package/dist/base-command.js +96 -11
- package/dist/commands/agents/create.d.ts +1 -0
- package/dist/commands/agents/create.js +6 -1
- package/dist/commands/agents/instructions/add.d.ts +21 -0
- package/dist/commands/agents/instructions/add.js +115 -0
- package/dist/commands/agents/instructions/disable.d.ts +13 -0
- package/dist/commands/agents/instructions/disable.js +50 -0
- package/dist/commands/agents/instructions/edit.d.ts +16 -0
- package/dist/commands/agents/instructions/edit.js +79 -0
- package/dist/commands/agents/instructions/enable.d.ts +13 -0
- package/dist/commands/agents/instructions/enable.js +50 -0
- package/dist/commands/agents/instructions/move.d.ts +15 -0
- package/dist/commands/agents/instructions/move.js +61 -0
- package/dist/commands/agents/instructions/preview.d.ts +13 -0
- package/dist/commands/agents/instructions/preview.js +59 -0
- package/dist/commands/agents/instructions/remove.d.ts +13 -0
- package/dist/commands/agents/instructions/remove.js +49 -0
- package/dist/commands/agents/instructions/set.d.ts +17 -0
- package/dist/commands/agents/instructions/set.js +79 -0
- package/dist/commands/agents/instructions/show.d.ts +15 -0
- package/dist/commands/agents/instructions/show.js +76 -0
- package/dist/commands/agents/instructions/upgrade.d.ts +16 -0
- package/dist/commands/agents/instructions/upgrade.js +77 -0
- package/dist/commands/agents/list.d.ts +10 -0
- package/dist/commands/agents/list.js +16 -1
- package/dist/commands/agents/show.js +5 -0
- package/dist/commands/agents/triggers/policy.js +8 -2
- package/dist/commands/agents/update.d.ts +1 -0
- package/dist/commands/agents/update.js +8 -2
- package/dist/commands/browser.js +5 -5
- package/dist/commands/commitments/create.d.ts +2 -0
- package/dist/commands/commitments/create.js +30 -13
- package/dist/commands/commitments/update.d.ts +2 -0
- package/dist/commands/commitments/update.js +24 -4
- package/dist/commands/daemon/byok.js +5 -5
- package/dist/commands/daemon/index.js +5 -3
- package/dist/commands/daemon/install.js +8 -5
- package/dist/commands/daemon/login.js +5 -5
- package/dist/commands/daemon/logs.js +5 -5
- package/dist/commands/daemon/recover-offline-queue.d.ts +9 -0
- package/dist/commands/daemon/recover-offline-queue.js +24 -0
- package/dist/commands/daemon/restart.js +5 -5
- package/dist/commands/daemon/start.js +34 -6
- package/dist/commands/daemon/status.js +5 -5
- package/dist/commands/daemon/stop.js +5 -5
- package/dist/commands/daemon/uninstall.js +5 -5
- package/dist/commands/daemon/unlock.js +5 -5
- package/dist/commands/daemon/usage.js +6 -6
- package/dist/commands/instruction-blocks/create.d.ts +19 -0
- package/dist/commands/instruction-blocks/create.js +94 -0
- package/dist/commands/instruction-blocks/delete.d.ts +13 -0
- package/dist/commands/instruction-blocks/delete.js +35 -0
- package/dist/commands/instruction-blocks/list.d.ts +13 -0
- package/dist/commands/instruction-blocks/list.js +71 -0
- package/dist/commands/instruction-blocks/show.d.ts +12 -0
- package/dist/commands/instruction-blocks/show.js +35 -0
- package/dist/commands/instruction-blocks/update.d.ts +23 -0
- package/dist/commands/instruction-blocks/update.js +94 -0
- package/dist/commands/login.js +7 -2
- package/dist/commands/spaces/auto-executor/preview.d.ts +1 -0
- package/dist/commands/spaces/auto-executor/preview.js +62 -3
- package/dist/commands/spaces/auto-executor/update.d.ts +4 -0
- package/dist/commands/spaces/auto-executor/update.js +78 -7
- package/dist/commands/spaces/capacity.js +14 -2
- package/dist/commands/spaces/list.d.ts +13 -0
- package/dist/commands/spaces/list.js +20 -1
- package/dist/commands/spaces/update.d.ts +4 -0
- package/dist/commands/spaces/update.js +49 -2
- package/dist/commands/tasks/complete.d.ts +12 -5
- package/dist/commands/tasks/complete.js +50 -28
- package/dist/commands/tasks/continue-ready.js +9 -1
- package/dist/commands/tasks/create.d.ts +1 -0
- package/dist/commands/tasks/create.js +25 -1
- package/dist/commands/tasks/deliverable/add.d.ts +23 -0
- package/dist/commands/tasks/deliverable/add.js +70 -0
- package/dist/commands/tasks/events/append.d.ts +1 -1
- package/dist/commands/tasks/events/append.js +4 -4
- package/dist/commands/tasks/expectations.d.ts +12 -0
- package/dist/commands/tasks/expectations.js +92 -0
- package/dist/commands/tasks/judge.d.ts +29 -0
- package/dist/commands/tasks/judge.js +68 -0
- package/dist/commands/tasks/list.d.ts +11 -0
- package/dist/commands/tasks/list.js +82 -11
- package/dist/commands/tasks/report.d.ts +1 -1
- package/dist/commands/tasks/report.js +3 -3
- package/dist/commands/tasks/update.d.ts +1 -0
- package/dist/commands/tasks/update.js +34 -4
- package/dist/commands/tasks/waive.d.ts +25 -0
- package/dist/commands/tasks/waive.js +58 -0
- package/dist/commands/wiki/cat.js +2 -1
- package/dist/commands/wiki/mv.js +5 -1
- package/dist/commands/wiki/write.js +5 -1
- package/dist/lib/agent-config.js +5 -0
- package/dist/lib/agent-instructions.d.ts +15 -0
- package/dist/lib/agent-instructions.js +55 -0
- package/dist/lib/api-fetch.d.ts +2 -1
- package/dist/lib/api-fetch.js +9 -2
- package/dist/lib/command-hygiene.d.ts +6 -1
- package/dist/lib/command-hygiene.js +49 -29
- package/dist/lib/commitments.d.ts +44 -0
- package/dist/lib/commitments.js +123 -0
- package/dist/lib/daemon-binding.d.ts +3 -4
- package/dist/lib/daemon-binding.js +11 -10
- package/dist/lib/daemon-handoff-opt-out.d.ts +8 -0
- package/dist/lib/daemon-handoff-opt-out.js +17 -0
- package/dist/lib/daemon-installer.d.ts +1 -1
- package/dist/lib/daemon-installer.js +2 -2
- package/dist/lib/daemon-setup.js +13 -7
- package/dist/lib/daemonHandoff.d.ts +1 -1
- package/dist/lib/daemonHandoff.js +20 -7
- package/dist/lib/delegated-cli.d.ts +0 -9
- package/dist/lib/delegated-cli.js +149 -6
- package/dist/lib/{exec-oversky.d.ts → exec-runtime-binary.d.ts} +28 -4
- package/dist/lib/{exec-oversky.js → exec-runtime-binary.js} +138 -37
- package/dist/lib/git-task.d.ts +37 -0
- package/dist/lib/git-task.js +151 -0
- package/dist/lib/instruction-blocks.d.ts +29 -0
- package/dist/lib/instruction-blocks.js +159 -0
- package/dist/lib/node-adapter.js +6 -0
- package/dist/lib/runtime-start-verification.d.ts +49 -0
- package/dist/lib/runtime-start-verification.js +108 -0
- package/dist/lib/sky-code.d.ts +1 -1
- package/dist/lib/sky-code.js +1 -1
- package/dist/lib/task-execution.d.ts +18 -2
- package/dist/lib/task-execution.js +19 -14
- package/dist/lib/task-transcript.js +1 -1
- package/dist/lib/tasks.d.ts +50 -0
- package/dist/lib/tasks.js +66 -1
- package/dist/lib/usage-discovery.js +1 -1
- package/dist/lib/web-url.d.ts +16 -0
- package/dist/lib/web-url.js +25 -0
- package/dist/node_modules/@skrr-ai/data-provider/index.js +4075 -3905
- package/dist/node_modules/@skrr-ai/inference-broker/package.json +1 -1
- package/oclif.manifest.json +12364 -10488
- package/package.json +4 -1
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base-command';
|
|
2
|
+
/**
|
|
3
|
+
* `skrr tasks waive <task> <expectation-id> --reason "<why>"`
|
|
4
|
+
*
|
|
5
|
+
* Drop a requirement, on the record. The expectation is KEPT and marked, never
|
|
6
|
+
* deleted: deleting it expresses the same decision while destroying the only
|
|
7
|
+
* evidence that it was ever owed, which is what someone asking "why wasn't this
|
|
8
|
+
* done?" needs to read.
|
|
9
|
+
*
|
|
10
|
+
* The reason is required for the same purpose — a waiver without one is
|
|
11
|
+
* indistinguishable from having forgotten.
|
|
12
|
+
*/
|
|
13
|
+
export default class TasksWaive extends BaseCommand {
|
|
14
|
+
static description: string;
|
|
15
|
+
static examples: string[];
|
|
16
|
+
static args: {
|
|
17
|
+
task: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
18
|
+
expectation: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
19
|
+
};
|
|
20
|
+
static flags: {
|
|
21
|
+
reason: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
22
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
23
|
+
};
|
|
24
|
+
run(): Promise<void>;
|
|
25
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
5
|
+
const base_command_1 = require("../../base-command");
|
|
6
|
+
/**
|
|
7
|
+
* `skrr tasks waive <task> <expectation-id> --reason "<why>"`
|
|
8
|
+
*
|
|
9
|
+
* Drop a requirement, on the record. The expectation is KEPT and marked, never
|
|
10
|
+
* deleted: deleting it expresses the same decision while destroying the only
|
|
11
|
+
* evidence that it was ever owed, which is what someone asking "why wasn't this
|
|
12
|
+
* done?" needs to read.
|
|
13
|
+
*
|
|
14
|
+
* The reason is required for the same purpose — a waiver without one is
|
|
15
|
+
* indistinguishable from having forgotten.
|
|
16
|
+
*/
|
|
17
|
+
class TasksWaive extends base_command_1.BaseCommand {
|
|
18
|
+
static description = 'Waive an expectation, with a stated reason';
|
|
19
|
+
static examples = [
|
|
20
|
+
'<%= config.bin %> tasks waive <task-id> c1 --reason "superseded by OSK-7000"',
|
|
21
|
+
];
|
|
22
|
+
static args = {
|
|
23
|
+
task: core_1.Args.string({ description: 'Task id or ref', required: true, ignoreStdin: true }),
|
|
24
|
+
expectation: core_1.Args.string({
|
|
25
|
+
description: 'Expectation id (see `tasks show`)',
|
|
26
|
+
required: true,
|
|
27
|
+
ignoreStdin: true,
|
|
28
|
+
}),
|
|
29
|
+
};
|
|
30
|
+
static flags = {
|
|
31
|
+
reason: core_1.Flags.string({
|
|
32
|
+
description: 'Why this is no longer required. Required — it is the record.',
|
|
33
|
+
required: true,
|
|
34
|
+
}),
|
|
35
|
+
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
36
|
+
};
|
|
37
|
+
async run() {
|
|
38
|
+
this.requireAuth();
|
|
39
|
+
const { args, flags } = await this.parse(TasksWaive);
|
|
40
|
+
let result;
|
|
41
|
+
try {
|
|
42
|
+
result = await data_provider_1.dataService.waiveTaskExpectation(args.task, {
|
|
43
|
+
expectationId: args.expectation,
|
|
44
|
+
reason: flags.reason,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
this.handleApiError(err);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (flags.json) {
|
|
52
|
+
this.log(JSON.stringify(result, null, 2));
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
this.log(`Waived ${args.expectation}: ${flags.reason}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
exports.default = TasksWaive;
|
|
@@ -3,6 +3,7 @@ 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 web_url_1 = require("../../lib/web-url");
|
|
6
7
|
class WikiCat extends base_command_1.BaseCommand {
|
|
7
8
|
static description = 'Print a wiki page (Markdown by default)';
|
|
8
9
|
static examples = [
|
|
@@ -41,7 +42,7 @@ class WikiCat extends base_command_1.BaseCommand {
|
|
|
41
42
|
this.handleApiError(err);
|
|
42
43
|
}
|
|
43
44
|
if (flags.json) {
|
|
44
|
-
this.log(JSON.stringify(page, null, 2));
|
|
45
|
+
this.log(JSON.stringify((0, web_url_1.withWikiPageUrl)(this.cliConfig.baseURL, page), null, 2));
|
|
45
46
|
return;
|
|
46
47
|
}
|
|
47
48
|
// Body only — so `skrr wiki cat ... > page.md` produces a clean file and
|
package/dist/commands/wiki/mv.js
CHANGED
|
@@ -6,6 +6,7 @@ const core_1 = require("@oclif/core");
|
|
|
6
6
|
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
7
7
|
const base_command_1 = require("../../base-command");
|
|
8
8
|
const http_error_1 = require("../../lib/http-error");
|
|
9
|
+
const web_url_1 = require("../../lib/web-url");
|
|
9
10
|
const wiki_1 = require("../../lib/wiki");
|
|
10
11
|
const write_1 = require("./write");
|
|
11
12
|
/**
|
|
@@ -231,7 +232,10 @@ class WikiMv extends base_command_1.BaseCommand {
|
|
|
231
232
|
});
|
|
232
233
|
}
|
|
233
234
|
if (flags.json) {
|
|
234
|
-
this.log(JSON.stringify({
|
|
235
|
+
this.log(JSON.stringify({
|
|
236
|
+
kind: 'page',
|
|
237
|
+
...(0, web_url_1.withWikiPageUrl)(this.cliConfig.baseURL, moved),
|
|
238
|
+
}, null, 2));
|
|
235
239
|
return;
|
|
236
240
|
}
|
|
237
241
|
this.log(`Moved page ${source} → ${moved.path ?? args.destination}.`);
|
|
@@ -8,6 +8,7 @@ const core_1 = require("@oclif/core");
|
|
|
8
8
|
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
9
9
|
const base_command_1 = require("../../base-command");
|
|
10
10
|
const http_error_1 = require("../../lib/http-error");
|
|
11
|
+
const web_url_1 = require("../../lib/web-url");
|
|
11
12
|
const wiki_1 = require("../../lib/wiki");
|
|
12
13
|
/**
|
|
13
14
|
* The page lookup below goes through `dataService`, whose adapter throws a
|
|
@@ -248,8 +249,9 @@ class WikiWrite extends base_command_1.BaseCommand {
|
|
|
248
249
|
`it creates. Retitle it with \`${this.config.bin} wiki update ${args.space} ${page.path ?? args.path} ` +
|
|
249
250
|
`--title ${JSON.stringify(flags.title)}\` (the slug is kept, so stored paths stay valid).`);
|
|
250
251
|
}
|
|
252
|
+
const withUrl = (0, web_url_1.withWikiPageUrl)(this.cliConfig.baseURL, page);
|
|
251
253
|
if (flags.json) {
|
|
252
|
-
this.log(JSON.stringify(
|
|
254
|
+
this.log(JSON.stringify(withUrl, null, 2));
|
|
253
255
|
return;
|
|
254
256
|
}
|
|
255
257
|
// Report what actually happened, not what we set out to do — a write that
|
|
@@ -260,6 +262,8 @@ class WikiWrite extends base_command_1.BaseCommand {
|
|
|
260
262
|
verb = flags.append ? 'Appended to' : 'Updated';
|
|
261
263
|
}
|
|
262
264
|
this.log(`${verb} ${page.path ?? args.path} (${page.pageId}).`);
|
|
265
|
+
if (withUrl.url)
|
|
266
|
+
this.log(`URL: ${withUrl.url}`);
|
|
263
267
|
}
|
|
264
268
|
}
|
|
265
269
|
exports.default = WikiWrite;
|
package/dist/lib/agent-config.js
CHANGED
|
@@ -48,5 +48,10 @@ function mergeAgentConfigFlags(body, flags) {
|
|
|
48
48
|
}
|
|
49
49
|
if (flags['recursion-limit'] !== undefined)
|
|
50
50
|
parsed.recursion_limit = flags['recursion-limit'];
|
|
51
|
+
// Cross-Space Task execution ceiling. `0` means unlimited, matching the
|
|
52
|
+
// Space limits' convention so a user learns one spelling of "no cap".
|
|
53
|
+
if (flags['max-concurrent-task-executions'] !== undefined) {
|
|
54
|
+
parsed.maxConcurrentTaskExecutions = flags['max-concurrent-task-executions'];
|
|
55
|
+
}
|
|
51
56
|
return (0, prompt_1.mergeDefined)(body, parsed);
|
|
52
57
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { dataService, type AgentPromptComposition } from '@skrr-ai/data-provider';
|
|
2
|
+
/** Positional and --agent forms agree with the existing `agents tone` UX. */
|
|
3
|
+
export declare function resolveInstructionAgentId(argument?: string, flag?: string): Promise<string>;
|
|
4
|
+
/** Fetch the edit-gated Agent projection used by the web composer. */
|
|
5
|
+
export declare function loadAgentInstructions(agentId: string): Promise<{
|
|
6
|
+
agent: Awaited<ReturnType<typeof dataService.getExpandedAgentById>>;
|
|
7
|
+
composition: AgentPromptComposition;
|
|
8
|
+
}>;
|
|
9
|
+
/**
|
|
10
|
+
* The Agent controller is intentionally the only persistence boundary. It
|
|
11
|
+
* resolves library versions, verifies bindings and materializes legacy
|
|
12
|
+
* `instructions` atomically, so a CLI never tries to compile a prompt itself.
|
|
13
|
+
*/
|
|
14
|
+
export declare function saveAgentInstructions(agentId: string, composition: AgentPromptComposition): Promise<import("@skrr-ai/data-provider").Agent>;
|
|
15
|
+
export declare function renderCompositionLines(composition: AgentPromptComposition): string[];
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveInstructionAgentId = resolveInstructionAgentId;
|
|
4
|
+
exports.loadAgentInstructions = loadAgentInstructions;
|
|
5
|
+
exports.saveAgentInstructions = saveAgentInstructions;
|
|
6
|
+
exports.renderCompositionLines = renderCompositionLines;
|
|
7
|
+
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
8
|
+
const agent_resolver_1 = require("./agent-resolver");
|
|
9
|
+
const instruction_blocks_1 = require("./instruction-blocks");
|
|
10
|
+
/** Positional and --agent forms agree with the existing `agents tone` UX. */
|
|
11
|
+
async function resolveInstructionAgentId(argument, flag) {
|
|
12
|
+
return (0, agent_resolver_1.resolveAgentId)((0, agent_resolver_1.mergeExplicitAgentInputs)([
|
|
13
|
+
{ label: 'argument', value: argument },
|
|
14
|
+
{ label: '--agent', value: flag },
|
|
15
|
+
]));
|
|
16
|
+
}
|
|
17
|
+
/** Fetch the edit-gated Agent projection used by the web composer. */
|
|
18
|
+
async function loadAgentInstructions(agentId) {
|
|
19
|
+
const agent = await data_provider_1.dataService.getExpandedAgentById({ agent_id: agentId });
|
|
20
|
+
return { agent, composition: (0, instruction_blocks_1.compositionForAgent)(agent) };
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The Agent controller is intentionally the only persistence boundary. It
|
|
24
|
+
* resolves library versions, verifies bindings and materializes legacy
|
|
25
|
+
* `instructions` atomically, so a CLI never tries to compile a prompt itself.
|
|
26
|
+
*/
|
|
27
|
+
async function saveAgentInstructions(agentId, composition) {
|
|
28
|
+
return data_provider_1.dataService.updateAgent({
|
|
29
|
+
agent_id: agentId,
|
|
30
|
+
data: { promptComposition: composition },
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
function renderCompositionLines(composition) {
|
|
34
|
+
if (!composition.entries.length)
|
|
35
|
+
return ['(No custom instruction blocks.)'];
|
|
36
|
+
return composition.entries.flatMap((entry, index) => {
|
|
37
|
+
const state = entry.enabled ? 'on' : 'off';
|
|
38
|
+
if (entry.source.kind === 'inline') {
|
|
39
|
+
const preview = entry.source.body.trim().replace(/\s+/g, ' ').slice(0, 140);
|
|
40
|
+
return [
|
|
41
|
+
`${index + 1}. ${state.padEnd(3)} inline ${entry.source.title} (${entry.instanceId})`,
|
|
42
|
+
` ${preview || '(empty)'}`,
|
|
43
|
+
];
|
|
44
|
+
}
|
|
45
|
+
const label = entry.resolved?.name || entry.source.blockId;
|
|
46
|
+
const bindings = entry.bindings && Object.keys(entry.bindings).length
|
|
47
|
+
? ` · bindings: ${Object.entries(entry.bindings)
|
|
48
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
49
|
+
.join(', ')}`
|
|
50
|
+
: '';
|
|
51
|
+
return [
|
|
52
|
+
`${index + 1}. ${state.padEnd(3)} library ${label} · v${entry.source.version} (${entry.instanceId})${bindings}`,
|
|
53
|
+
];
|
|
54
|
+
});
|
|
55
|
+
}
|
package/dist/lib/api-fetch.d.ts
CHANGED
|
@@ -29,7 +29,8 @@ export declare class ApiFetchError extends Error {
|
|
|
29
29
|
readonly status: number;
|
|
30
30
|
readonly body?: string;
|
|
31
31
|
readonly code?: string;
|
|
32
|
-
|
|
32
|
+
readonly method?: string;
|
|
33
|
+
constructor(message: string, status: number, body?: string, code?: string, method?: string);
|
|
33
34
|
}
|
|
34
35
|
/**
|
|
35
36
|
* Call a skrr API endpoint with the current credential. Throws
|
package/dist/lib/api-fetch.js
CHANGED
|
@@ -46,12 +46,19 @@ class ApiFetchError extends Error {
|
|
|
46
46
|
status;
|
|
47
47
|
body;
|
|
48
48
|
code;
|
|
49
|
-
|
|
49
|
+
// The HTTP method of the failing request. The 403 branch of
|
|
50
|
+
// `handleApiError` needs to know whether the request even HAD a body before
|
|
51
|
+
// it can advise the user to "try again with less of the request body"
|
|
52
|
+
// (OSK-6765): `agents show` is a GET and had no body, and the advice was
|
|
53
|
+
// impossible to follow.
|
|
54
|
+
method;
|
|
55
|
+
constructor(message, status, body, code, method) {
|
|
50
56
|
super(message);
|
|
51
57
|
this.name = 'ApiFetchError';
|
|
52
58
|
this.status = status;
|
|
53
59
|
this.body = body;
|
|
54
60
|
this.code = code;
|
|
61
|
+
this.method = method;
|
|
55
62
|
}
|
|
56
63
|
}
|
|
57
64
|
exports.ApiFetchError = ApiFetchError;
|
|
@@ -189,7 +196,7 @@ async function apiFetch(pathOrUrl, opts = {}) {
|
|
|
189
196
|
catch {
|
|
190
197
|
/* ignore body read failures */
|
|
191
198
|
}
|
|
192
|
-
throw new ApiFetchError(`HTTP ${res.status} ${res.statusText} — ${method} ${pathOrUrl}`, res.status, text, code);
|
|
199
|
+
throw new ApiFetchError(`HTTP ${res.status} ${res.statusText} — ${method} ${pathOrUrl}`, res.status, text, code, method);
|
|
193
200
|
}
|
|
194
201
|
// 204/205 carry no body by definition; an empty body has no content-type
|
|
195
202
|
// worth judging. Neither is an error.
|
|
@@ -30,5 +30,10 @@ export type CommandHygieneReport = {
|
|
|
30
30
|
};
|
|
31
31
|
export declare function auditCommands({ rootDir, manifest, }: {
|
|
32
32
|
rootDir: string;
|
|
33
|
-
|
|
33
|
+
/**
|
|
34
|
+
* The generated oclif catalogue is not present in a source checkout. Such
|
|
35
|
+
* callers can still run source-level checks, but cannot make claims about
|
|
36
|
+
* what a generated manifest contains.
|
|
37
|
+
*/
|
|
38
|
+
manifest?: CommandManifest;
|
|
34
39
|
}): CommandHygieneReport;
|
|
@@ -46,13 +46,14 @@ const AGENT_CRITICAL_COMMANDS = [
|
|
|
46
46
|
];
|
|
47
47
|
function auditCommands({ rootDir, manifest, }) {
|
|
48
48
|
const issues = [];
|
|
49
|
-
const commands = manifest
|
|
49
|
+
const commands = manifest?.commands ?? {};
|
|
50
50
|
const commandIds = Object.keys(commands);
|
|
51
|
+
const manifestForCatalog = manifest ?? {};
|
|
51
52
|
// The command manifest is the only catalogue. The progressive `skrr usage`
|
|
52
53
|
// surfaces are useful precisely because they do not make an agent load that
|
|
53
54
|
// whole catalogue at once, so audit every generated continuation page too.
|
|
54
|
-
const overview = (0, usage_discovery_1.buildUsageOverview)(
|
|
55
|
-
const usageBudgetIssues = (0, usage_discovery_1.auditUsageBudgets)(
|
|
55
|
+
const overview = (0, usage_discovery_1.buildUsageOverview)(manifestForCatalog);
|
|
56
|
+
const usageBudgetIssues = (0, usage_discovery_1.auditUsageBudgets)(manifestForCatalog);
|
|
56
57
|
for (const issue of usageBudgetIssues) {
|
|
57
58
|
issues.push({
|
|
58
59
|
code: 'USAGE_DISCOVERY_TOKEN_BUDGET_EXCEEDED',
|
|
@@ -62,14 +63,31 @@ function auditCommands({ rootDir, manifest, }) {
|
|
|
62
63
|
`uses ${issue.estimatedTokens} estimated tokens; budget is ${issue.tokenBudget}.`,
|
|
63
64
|
});
|
|
64
65
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
66
|
+
if (!manifest) {
|
|
67
|
+
// Absence is a distinct answer from "missing", and it should be audible.
|
|
68
|
+
//
|
|
69
|
+
// Skipping silently means a source-only run reports a clean bill of health
|
|
70
|
+
// for a check it never performed. That is the shape that makes an audit
|
|
71
|
+
// untrustworthy — worse than a noisy one, because a green result stops
|
|
72
|
+
// meaning anything. A warning keeps the run green while saying which claim
|
|
73
|
+
// it is NOT making, and names the command that would let it.
|
|
74
|
+
issues.push({
|
|
75
|
+
code: 'AGENT_CRITICAL_COMMANDS_UNCHECKED',
|
|
76
|
+
severity: 'warning',
|
|
77
|
+
message: 'No command manifest was available, so the agent-critical command check did not run. ' +
|
|
78
|
+
'Build the CLI (`npx tsc -p tsconfig.build.json && npx oclif manifest` in cli/) to audit it.',
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
if (manifest) {
|
|
82
|
+
for (const id of AGENT_CRITICAL_COMMANDS) {
|
|
83
|
+
if (!commands[id]) {
|
|
84
|
+
issues.push({
|
|
85
|
+
code: 'AGENT_CRITICAL_COMMAND_MISSING',
|
|
86
|
+
severity: 'error',
|
|
87
|
+
command: id,
|
|
88
|
+
message: `Agent-critical command is missing from the manifest: ${id}`,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
73
91
|
}
|
|
74
92
|
}
|
|
75
93
|
let sourceAvailable = false;
|
|
@@ -129,23 +147,25 @@ function auditCommands({ rootDir, manifest, }) {
|
|
|
129
147
|
message: 'Source command files are unavailable; source-level hygiene checks were skipped.',
|
|
130
148
|
});
|
|
131
149
|
}
|
|
132
|
-
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
150
|
+
if (manifest) {
|
|
151
|
+
for (const id of commandIds) {
|
|
152
|
+
const command = commands[id];
|
|
153
|
+
if (!command?.description?.trim()) {
|
|
154
|
+
issues.push({
|
|
155
|
+
code: 'COMMAND_DESCRIPTION_MISSING',
|
|
156
|
+
severity: 'warning',
|
|
157
|
+
command: id,
|
|
158
|
+
message: 'Command is missing a description in the manifest.',
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
if (!hasJsonFlag(command?.flags) && isMachineRelevantCommand(id)) {
|
|
162
|
+
issues.push({
|
|
163
|
+
code: 'JSON_SUCCESS_OUTPUT_MISSING',
|
|
164
|
+
severity: 'warning',
|
|
165
|
+
command: id,
|
|
166
|
+
message: 'Machine-relevant command has no --json success-output flag. Keep human-only commands intentional.',
|
|
167
|
+
});
|
|
168
|
+
}
|
|
149
169
|
}
|
|
150
170
|
}
|
|
151
171
|
const errors = issues.filter((issue) => issue.severity === 'error').length;
|
|
@@ -167,7 +187,7 @@ function auditCommands({ rootDir, manifest, }) {
|
|
|
167
187
|
usage: {
|
|
168
188
|
overviewTokenBudget: overview.tokenBudget,
|
|
169
189
|
overviewEstimatedTokens: overview.estimatedTokens,
|
|
170
|
-
domains: (0, usage_discovery_1.usageDomains)(
|
|
190
|
+
domains: (0, usage_discovery_1.usageDomains)(manifestForCatalog).length,
|
|
171
191
|
budgetErrors: usageBudgetIssues.length,
|
|
172
192
|
},
|
|
173
193
|
issues,
|
|
@@ -362,6 +362,29 @@ export declare const COMMITMENT_CREATE_KEYS: readonly ["agentId", "kind", "compa
|
|
|
362
362
|
*/
|
|
363
363
|
export declare function normalizeCreateBody(input: Record<string, unknown>): Record<string, unknown>;
|
|
364
364
|
export declare function parseIntervalToMs(input: string): number;
|
|
365
|
+
/**
|
|
366
|
+
* Assemble the `watchedSources` array from CLI flags — one place, so `create`
|
|
367
|
+
* and `update` agree on which flags carry what.
|
|
368
|
+
*
|
|
369
|
+
* The `space` and `monitor` sources need a scope id (`config.spaceId` /
|
|
370
|
+
* `config.monitorId`) that the flat `--watch` enum cannot carry. The API
|
|
371
|
+
* rejects the whole write when one is missing (`SPACE_SOURCE_SCOPE_REQUIRED` /
|
|
372
|
+
* `INVALID_MONITOR_REFERENCE`) — the same shape that made this a finding: the
|
|
373
|
+
* CLI advertised the source but had no way to satisfy it.
|
|
374
|
+
*
|
|
375
|
+
* The companion flags (`--watch-space`, `--watch-monitor`) fill that gap and
|
|
376
|
+
* implicitly opt the source in, so the enum and its config cannot disagree.
|
|
377
|
+
* Space refs must be RESOLVED to canonical ids by the caller — this helper
|
|
378
|
+
* does not do the network round trip, so it is unit-testable on its own.
|
|
379
|
+
*/
|
|
380
|
+
export type WatchFlagInputs = {
|
|
381
|
+
watch?: string[];
|
|
382
|
+
metricKey?: string[];
|
|
383
|
+
/** Already resolved to canonical space ids by the caller. */
|
|
384
|
+
spaceIds?: string[];
|
|
385
|
+
monitorIds?: string[];
|
|
386
|
+
};
|
|
387
|
+
export declare function buildWatchedSources(inputs: WatchFlagInputs): Array<Record<string, unknown>> | undefined;
|
|
365
388
|
/** The evidence-health shape carried on a check's `inputs`. */
|
|
366
389
|
export type EvidenceHealthView = {
|
|
367
390
|
state?: string | null;
|
|
@@ -429,6 +452,27 @@ export declare function effectiveAutonomyMode(check?: {
|
|
|
429
452
|
policyTrace?: Array<Record<string, unknown>>;
|
|
430
453
|
} | null;
|
|
431
454
|
} | null): string | undefined;
|
|
455
|
+
/**
|
|
456
|
+
* A `commitment_standstill` policyTrace entry, extracted from the latest
|
|
457
|
+
* check's decision. The arbiter appends it whenever a quiet posture is the
|
|
458
|
+
* ANSWER to "why nothing is happening" (`CommitmentControl/index.js` around
|
|
459
|
+
* the `record_only`/empty-action-plan branch). Every field except `reason` is
|
|
460
|
+
* optional, and old checks lack the entry entirely — so a missing entry means
|
|
461
|
+
* "the loop had nothing standstill-worthy to say", not "we don't know".
|
|
462
|
+
*
|
|
463
|
+
* Exported for tests.
|
|
464
|
+
*/
|
|
465
|
+
export declare function extractStandstillFromCheck(check?: {
|
|
466
|
+
decision?: {
|
|
467
|
+
policyTrace?: Array<Record<string, unknown>>;
|
|
468
|
+
} | null;
|
|
469
|
+
} | null): {
|
|
470
|
+
reason: string;
|
|
471
|
+
layer?: string;
|
|
472
|
+
owner?: string;
|
|
473
|
+
fix?: string;
|
|
474
|
+
alsoConstrained?: Array<Record<string, unknown>>;
|
|
475
|
+
} | null;
|
|
432
476
|
/**
|
|
433
477
|
* The `Autonomy:` line — the stated mode, annotated when the latest check
|
|
434
478
|
* actually ran at a STRICTER one (OSK-4881). Without the caveat, a commitment
|
package/dist/lib/commitments.js
CHANGED
|
@@ -3,12 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.COMMITMENT_CLI_EVALUATORS = exports.COMMITMENT_CREATE_KEYS = exports.COMMITMENT_REMEDIATION_ACTIONS = exports.COMMITMENT_FEEDBACK_KINDS = exports.commitmentApi = exports.commitmentPackApi = exports.MAX_COMMITMENT_INTERVAL_MS = exports.MIN_COMMITMENT_INTERVAL_MS = exports.COMMITMENT_AUTONOMY_MODES = exports.COMMITMENT_STATUSES = exports.COMMITMENT_CADENCE_MAX_TIMES = exports.COMMITMENT_CADENCE_TIME_PATTERN = exports.COMMITMENT_CADENCE_MODES = exports.COMMITMENT_TEMPLATE_IDS = exports.COMMITMENT_WATCHED_SOURCES = void 0;
|
|
4
4
|
exports.normalizeCreateBody = normalizeCreateBody;
|
|
5
5
|
exports.parseIntervalToMs = parseIntervalToMs;
|
|
6
|
+
exports.buildWatchedSources = buildWatchedSources;
|
|
6
7
|
exports.describeEvidenceHealth = describeEvidenceHealth;
|
|
7
8
|
exports.describeIntervalMs = describeIntervalMs;
|
|
8
9
|
exports.buildSuccessCriteria = buildSuccessCriteria;
|
|
9
10
|
exports.cadenceLabel = cadenceLabel;
|
|
10
11
|
exports.renderCommitmentList = renderCommitmentList;
|
|
11
12
|
exports.effectiveAutonomyMode = effectiveAutonomyMode;
|
|
13
|
+
exports.extractStandstillFromCheck = extractStandstillFromCheck;
|
|
12
14
|
exports.describeAutonomyLine = describeAutonomyLine;
|
|
13
15
|
exports.renderCommitmentSummary = renderCommitmentSummary;
|
|
14
16
|
exports.describeWakeDecision = describeWakeDecision;
|
|
@@ -316,6 +318,66 @@ function parseIntervalToMs(input) {
|
|
|
316
318
|
}
|
|
317
319
|
return ms;
|
|
318
320
|
}
|
|
321
|
+
function buildWatchedSources(inputs) {
|
|
322
|
+
const watched = (inputs.watch ?? []).filter(Boolean);
|
|
323
|
+
const metricKeys = (inputs.metricKey ?? []).filter(Boolean);
|
|
324
|
+
const spaceIds = (inputs.spaceIds ?? []).filter(Boolean);
|
|
325
|
+
const monitorIds = (inputs.monitorIds ?? []).filter(Boolean);
|
|
326
|
+
const effective = new Set(watched);
|
|
327
|
+
if (spaceIds.length)
|
|
328
|
+
effective.add('space');
|
|
329
|
+
if (monitorIds.length)
|
|
330
|
+
effective.add('monitor');
|
|
331
|
+
if (effective.has('space') && spaceIds.length === 0) {
|
|
332
|
+
throw new Error('--watch space needs at least one --watch-space <space-id-or-ref>. ' +
|
|
333
|
+
'The `space` source requires a scope id, which the enum on its own cannot carry.');
|
|
334
|
+
}
|
|
335
|
+
if (effective.has('monitor') && monitorIds.length === 0) {
|
|
336
|
+
throw new Error('--watch monitor needs at least one --watch-monitor <monitor-id>. ' +
|
|
337
|
+
'The `monitor` source requires a scope id, which the enum on its own cannot carry.');
|
|
338
|
+
}
|
|
339
|
+
if (metricKeys.length && !effective.has('metrics')) {
|
|
340
|
+
throw new Error('--metric-key requires --watch metrics.');
|
|
341
|
+
}
|
|
342
|
+
if (effective.size === 0)
|
|
343
|
+
return undefined;
|
|
344
|
+
// Preserve caller order: --watch entries first (deduped), then any source
|
|
345
|
+
// that was only implied by a companion flag.
|
|
346
|
+
const orderedSources = [];
|
|
347
|
+
const seen = new Set();
|
|
348
|
+
for (const s of watched) {
|
|
349
|
+
if (!seen.has(s)) {
|
|
350
|
+
orderedSources.push(s);
|
|
351
|
+
seen.add(s);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
for (const implied of ['space', 'monitor']) {
|
|
355
|
+
if (effective.has(implied) && !seen.has(implied)) {
|
|
356
|
+
orderedSources.push(implied);
|
|
357
|
+
seen.add(implied);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
const rows = [];
|
|
361
|
+
for (const source of orderedSources) {
|
|
362
|
+
if (source === 'space') {
|
|
363
|
+
for (const spaceId of spaceIds) {
|
|
364
|
+
rows.push({ source, enabled: true, config: { spaceId } });
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
else if (source === 'monitor') {
|
|
368
|
+
for (const monitorId of monitorIds) {
|
|
369
|
+
rows.push({ source, enabled: true, config: { monitorId } });
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
else if (source === 'metrics' && metricKeys.length) {
|
|
373
|
+
rows.push({ source, enabled: true, config: { metricKeys } });
|
|
374
|
+
}
|
|
375
|
+
else {
|
|
376
|
+
rows.push({ source, enabled: true });
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
return rows;
|
|
380
|
+
}
|
|
319
381
|
/**
|
|
320
382
|
* One line an author can act on, or nothing.
|
|
321
383
|
*
|
|
@@ -480,6 +542,41 @@ function effectiveAutonomyMode(check) {
|
|
|
480
542
|
}
|
|
481
543
|
return undefined;
|
|
482
544
|
}
|
|
545
|
+
/**
|
|
546
|
+
* A `commitment_standstill` policyTrace entry, extracted from the latest
|
|
547
|
+
* check's decision. The arbiter appends it whenever a quiet posture is the
|
|
548
|
+
* ANSWER to "why nothing is happening" (`CommitmentControl/index.js` around
|
|
549
|
+
* the `record_only`/empty-action-plan branch). Every field except `reason` is
|
|
550
|
+
* optional, and old checks lack the entry entirely — so a missing entry means
|
|
551
|
+
* "the loop had nothing standstill-worthy to say", not "we don't know".
|
|
552
|
+
*
|
|
553
|
+
* Exported for tests.
|
|
554
|
+
*/
|
|
555
|
+
function extractStandstillFromCheck(check) {
|
|
556
|
+
const trace = check?.decision?.policyTrace;
|
|
557
|
+
if (!Array.isArray(trace))
|
|
558
|
+
return null;
|
|
559
|
+
for (const entry of trace) {
|
|
560
|
+
if (!entry || typeof entry !== 'object')
|
|
561
|
+
continue;
|
|
562
|
+
const e = entry;
|
|
563
|
+
if (e.rule !== 'commitment_standstill')
|
|
564
|
+
continue;
|
|
565
|
+
const reason = typeof e.reason === 'string' ? e.reason : '';
|
|
566
|
+
if (!reason)
|
|
567
|
+
continue;
|
|
568
|
+
return {
|
|
569
|
+
reason,
|
|
570
|
+
layer: typeof e.layer === 'string' ? e.layer : undefined,
|
|
571
|
+
owner: typeof e.owner === 'string' ? e.owner : undefined,
|
|
572
|
+
fix: typeof e.fix === 'string' ? e.fix : undefined,
|
|
573
|
+
alsoConstrained: Array.isArray(e.alsoConstrained)
|
|
574
|
+
? e.alsoConstrained
|
|
575
|
+
: undefined,
|
|
576
|
+
};
|
|
577
|
+
}
|
|
578
|
+
return null;
|
|
579
|
+
}
|
|
483
580
|
/**
|
|
484
581
|
* The `Autonomy:` line — the stated mode, annotated when the latest check
|
|
485
582
|
* actually ran at a STRICTER one (OSK-4881). Without the caveat, a commitment
|
|
@@ -538,6 +635,32 @@ latestCheck) {
|
|
|
538
635
|
if (typeof commitment.state?.consecutiveUnresolvedChecks === 'number') {
|
|
539
636
|
log(`Unresolved checks in a row:${` ${commitment.state.consecutiveUnresolvedChecks}`}`);
|
|
540
637
|
}
|
|
638
|
+
// The load-bearing signal on a commitment that "reports active but never
|
|
639
|
+
// acts": the arbiter names WHY every recent check decided to do nothing, but
|
|
640
|
+
// that entry sat only in `policyTrace` on each check and was never rendered.
|
|
641
|
+
// Read at check time, unrolled here so a person reading the header sees the
|
|
642
|
+
// same conclusion the check already reached — and the `fix` string that was
|
|
643
|
+
// already written for them.
|
|
644
|
+
const standstill = extractStandstillFromCheck(latestCheck);
|
|
645
|
+
if (standstill) {
|
|
646
|
+
const streak = commitment.state?.consecutiveUnresolvedChecks;
|
|
647
|
+
const streakClause = typeof streak === 'number' && streak >= 2 ? `${streak} checks in a row: ` : '';
|
|
648
|
+
log(`Standstill:${` ${streakClause}${standstill.reason}`}`);
|
|
649
|
+
if (standstill.fix)
|
|
650
|
+
log(` Fix: ${standstill.fix}`);
|
|
651
|
+
if (standstill.alsoConstrained?.length) {
|
|
652
|
+
const also = standstill.alsoConstrained
|
|
653
|
+
.map((entry) => {
|
|
654
|
+
if (!entry || typeof entry !== 'object')
|
|
655
|
+
return null;
|
|
656
|
+
const reason = entry.reason;
|
|
657
|
+
return typeof reason === 'string' ? reason : null;
|
|
658
|
+
})
|
|
659
|
+
.filter((r) => Boolean(r));
|
|
660
|
+
if (also.length)
|
|
661
|
+
log(` Also constrained: ${also.join(', ')}`);
|
|
662
|
+
}
|
|
663
|
+
}
|
|
541
664
|
const sources = (commitment.watchedSources || [])
|
|
542
665
|
.filter((s) => s.enabled !== false)
|
|
543
666
|
.map((s) => s.source);
|
|
@@ -21,9 +21,8 @@
|
|
|
21
21
|
/** Whether `argv` already carries `--name` or `--name=value` (or `-alias`). */
|
|
22
22
|
export declare function hasFlag(argv: readonly string[], name: string, alias?: string): boolean;
|
|
23
23
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* while the CLI sits on dev.
|
|
24
|
+
* Fill `--server` / `--profile` from the CLI's own session when the caller did
|
|
25
|
+
* not pass them. The runtime's profile is global, so normalize it before the
|
|
26
|
+
* subcommand even when the caller supplied it after one.
|
|
28
27
|
*/
|
|
29
28
|
export declare function bindToCliSession(argv: readonly string[]): string[];
|