@skrr-ai/cli 0.1.64 → 0.1.66
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/agents/visibility.d.ts +9 -0
- package/dist/commands/agents/visibility.js +30 -0
- package/dist/commands/goals/plan-now.d.ts +6 -0
- package/dist/commands/goals/plan-now.js +25 -0
- package/dist/commands/memory/approvals/issue.js +6 -3
- package/dist/commands/memory/mounts/resolve.js +1 -2
- package/dist/commands/memory/save.d.ts +1 -0
- package/dist/commands/memory/save.js +16 -55
- package/dist/commands/memory/stores/list.js +1 -2
- package/dist/commands/memory/stores/update.js +6 -3
- package/dist/commands/skills/visibility.d.ts +15 -0
- package/dist/commands/skills/visibility.js +49 -0
- package/dist/commands/store/admissions/approve.d.ts +1 -0
- package/dist/commands/store/admissions/approve.js +9 -3
- package/dist/commands/store/admissions/list.js +6 -0
- package/dist/commands/store/admissions/refuse.d.ts +1 -0
- package/dist/commands/store/admissions/refuse.js +9 -3
- package/dist/commands/store/artifacts/release.d.ts +3 -0
- package/dist/commands/store/artifacts/release.js +42 -0
- package/dist/commands/store/update.js +5 -1
- package/dist/commands/store/updates.d.ts +1 -1
- package/dist/commands/store/updates.js +3 -3
- package/dist/commands/tasks/comments/list.d.ts +10 -0
- package/dist/commands/tasks/comments/list.js +53 -9
- package/dist/commands/tasks/comments/react.js +3 -1
- package/dist/commands/tasks/deliverable/add.d.ts +1 -0
- package/dist/commands/tasks/deliverable/add.js +13 -2
- package/dist/commands/tasks/deliverable/list.js +15 -1
- package/dist/commands/tasks/lifecycle/transition.js +6 -3
- package/dist/commands/tasks/plan/run-update.js +1 -1
- package/dist/commands/tasks/result/submit.js +1 -1
- package/dist/commands/tasks/resume/save.js +6 -3
- package/dist/commands/tasks/updates/add.js +11 -1
- package/dist/lib/file-mime.js +1 -0
- package/dist/lib/prompt.d.ts +7 -0
- package/dist/lib/prompt.js +16 -0
- package/dist/lib/scoped-memory-command.d.ts +4 -2
- package/dist/lib/scoped-memory-command.js +27 -3
- package/dist/lib/task-asset-upload.d.ts +5 -0
- package/dist/lib/task-asset-upload.js +4 -0
- package/dist/lib/task-closure.d.ts +3 -1
- package/dist/lib/task-closure.js +14 -4
- package/dist/node_modules/@skrr-ai/data-provider/index.js +13 -5
- package/oclif.manifest.json +27743 -27621
- package/package.json +1 -1
|
@@ -14,7 +14,7 @@ const format_1 = require("../../lib/format");
|
|
|
14
14
|
*
|
|
15
15
|
* Three states, kept apart because they ask for three different things:
|
|
16
16
|
*
|
|
17
|
-
* ready a same-major release
|
|
17
|
+
* ready a same-major release is available; eligibility is checked on apply
|
|
18
18
|
* review one that could not be applied on its own — you and the publisher
|
|
19
19
|
* both changed the same field, the release widened capabilities, or
|
|
20
20
|
* the version your copy came from is unknown
|
|
@@ -82,7 +82,7 @@ class StoreUpdates extends base_command_1.BaseCommand {
|
|
|
82
82
|
channel: install.updatePolicy ?? 'manual',
|
|
83
83
|
have,
|
|
84
84
|
waiting: update.versionLabel ?? '-',
|
|
85
|
-
detail: '
|
|
85
|
+
detail: 'available; checked on apply',
|
|
86
86
|
});
|
|
87
87
|
}
|
|
88
88
|
if (install.stopReason) {
|
|
@@ -122,7 +122,7 @@ class StoreUpdates extends base_command_1.BaseCommand {
|
|
|
122
122
|
{ key: 'detail', header: 'WHY', maxWidth: 46 },
|
|
123
123
|
], (line) => this.log(line));
|
|
124
124
|
this.log('');
|
|
125
|
-
this.log('ready → skrr store update <agent>');
|
|
125
|
+
this.log('ready → available; checks run on apply: skrr store update <agent>');
|
|
126
126
|
this.log('review → skrr store update <agent> --strategy replace (takes the publisher version)');
|
|
127
127
|
this.log('widened → skrr store update <agent> --accept-capabilities (or --decline to keep yours)');
|
|
128
128
|
// No command: `store install` refuses a listing you already own, and
|
|
@@ -1,4 +1,14 @@
|
|
|
1
1
|
import { BaseCommand } from '../../../base-command';
|
|
2
|
+
/**
|
|
3
|
+
* Comments arrive flat. Re-thread them so a reply prints under its parent —
|
|
4
|
+
* the flattened order hid which remark a reply answered (OSK-12743). Each
|
|
5
|
+
* level keeps the page's own order; a reply whose parent is on another page
|
|
6
|
+
* (or deleted) keeps its position as a root rather than vanishing.
|
|
7
|
+
*/
|
|
8
|
+
export declare function threadComments(items: Array<Record<string, unknown>>): Array<{
|
|
9
|
+
c: Record<string, unknown>;
|
|
10
|
+
depth: number;
|
|
11
|
+
}>;
|
|
2
12
|
export default class TasksCommentsList extends BaseCommand {
|
|
3
13
|
static description: string;
|
|
4
14
|
static examples: string[];
|
|
@@ -1,11 +1,46 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.threadComments = threadComments;
|
|
3
4
|
const core_1 = require("@oclif/core");
|
|
4
5
|
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
5
6
|
const base_command_1 = require("../../../base-command");
|
|
6
7
|
const format_1 = require("../../../lib/format");
|
|
7
8
|
const principal_display_1 = require("../../../lib/principal-display");
|
|
8
9
|
const task_resolver_1 = require("../../../lib/task-resolver");
|
|
10
|
+
/**
|
|
11
|
+
* Comments arrive flat. Re-thread them so a reply prints under its parent —
|
|
12
|
+
* the flattened order hid which remark a reply answered (OSK-12743). Each
|
|
13
|
+
* level keeps the page's own order; a reply whose parent is on another page
|
|
14
|
+
* (or deleted) keeps its position as a root rather than vanishing.
|
|
15
|
+
*/
|
|
16
|
+
function threadComments(items) {
|
|
17
|
+
const byId = new Map(items.map((c) => [String(c.id ?? c._id), c]));
|
|
18
|
+
const children = new Map();
|
|
19
|
+
const roots = [];
|
|
20
|
+
for (const c of items) {
|
|
21
|
+
const parentId = c.parentCommentId ? String(c.parentCommentId) : null;
|
|
22
|
+
if (parentId && byId.has(parentId)) {
|
|
23
|
+
const siblings = children.get(parentId) ?? [];
|
|
24
|
+
siblings.push(c);
|
|
25
|
+
children.set(parentId, siblings);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
roots.push(c);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const threaded = [];
|
|
32
|
+
const emit = (c, depth) => {
|
|
33
|
+
threaded.push({ c, depth });
|
|
34
|
+
// The list arrives newest-first; inside a thread, oldest→newest reads as
|
|
35
|
+
// the conversation happened.
|
|
36
|
+
for (const child of (children.get(String(c.id ?? c._id)) ?? []).slice().reverse()) {
|
|
37
|
+
emit(child, depth + 1);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
for (const root of roots)
|
|
41
|
+
emit(root, 0);
|
|
42
|
+
return threaded;
|
|
43
|
+
}
|
|
9
44
|
class TasksCommentsList extends base_command_1.BaseCommand {
|
|
10
45
|
static description = 'List comments on a task';
|
|
11
46
|
static examples = [
|
|
@@ -72,15 +107,24 @@ class TasksCommentsList extends base_command_1.BaseCommand {
|
|
|
72
107
|
// space roster (or the caller's own record) can see them; ids that cannot
|
|
73
108
|
// resolve print unchanged.
|
|
74
109
|
const principalNames = await (0, principal_display_1.resolvePrincipalNames)(items.map((c) => c.authorAgentId ?? c.authorUserId ?? c.author));
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
110
|
+
const threaded = threadComments(items);
|
|
111
|
+
const rows = threaded.map(({ c, depth }) => {
|
|
112
|
+
const reactions = c.reactions
|
|
113
|
+
?.map((r) => `${r.emoji ?? ''}${r.count ?? ''}`)
|
|
114
|
+
.filter(Boolean)
|
|
115
|
+
.join(' ');
|
|
116
|
+
const state = c.status === 'resolved' || c.resolvedAt ? 'resolved' : undefined;
|
|
117
|
+
const suffix = [state, reactions].filter(Boolean).join(' · ');
|
|
118
|
+
return {
|
|
119
|
+
time: (0, format_1.localTime)(c.createdAt),
|
|
120
|
+
// The server enriches authors directly (_authorUserName/_authorAgentName);
|
|
121
|
+
// the roster lookup is the fallback for a deployment that predates it.
|
|
122
|
+
author: String(c._authorUserName ?? c._authorAgentName ?? '') ||
|
|
123
|
+
(0, principal_display_1.displayPrincipal)(c.authorAgentId ?? c.authorUserId ?? c.author, principalNames),
|
|
124
|
+
body: (0, format_1.truncate)(String(c.body ?? c.content ?? '-'), 60) + (suffix ? ` [${suffix}]` : ''),
|
|
125
|
+
id: `${depth > 0 ? ' '.repeat(depth) + '↳ ' : ''}${String(c.id ?? c._id ?? '-')}`,
|
|
126
|
+
};
|
|
127
|
+
});
|
|
84
128
|
(0, format_1.renderTable)(rows, [
|
|
85
129
|
{ key: 'time', header: 'TIME' },
|
|
86
130
|
{ key: 'author', header: 'AUTHOR', maxWidth: 30 },
|
|
@@ -14,7 +14,9 @@ class TasksCommentsReact extends base_command_1.BaseCommand {
|
|
|
14
14
|
commentId: core_1.Args.string({ description: 'Comment UUID', required: true, ignoreStdin: true }),
|
|
15
15
|
};
|
|
16
16
|
static flags = {
|
|
17
|
-
task: core_1.Flags.string({
|
|
17
|
+
task: core_1.Flags.string({
|
|
18
|
+
description: 'Task ID; required when not running inside a daemon task session (OSK-12742)',
|
|
19
|
+
}),
|
|
18
20
|
emoji: core_1.Flags.string({ description: 'Emoji reaction (up to 16 characters)', required: true }),
|
|
19
21
|
json: core_1.Flags.boolean({ description: 'Output the raw response as JSON' }),
|
|
20
22
|
};
|
|
@@ -33,6 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.defaultDeliverableIdempotencyKey = defaultDeliverableIdempotencyKey;
|
|
36
37
|
const fs = __importStar(require("node:fs"));
|
|
37
38
|
const path = __importStar(require("node:path"));
|
|
38
39
|
const core_1 = require("@oclif/core");
|
|
@@ -43,6 +44,11 @@ const outbox_1 = require("../../../lib/outbox");
|
|
|
43
44
|
const api_fetch_1 = require("../../../lib/api-fetch");
|
|
44
45
|
const session_task_endpoints_1 = require("../../../lib/session-task-endpoints");
|
|
45
46
|
const tasks_1 = require("../../../lib/tasks");
|
|
47
|
+
function defaultDeliverableIdempotencyKey(task, payload) {
|
|
48
|
+
// A retry of one exact observation keeps its key. A new version, provider,
|
|
49
|
+
// digest, or expectation binding is a different observation.
|
|
50
|
+
return (0, outbox_1.idempotencyKeyFor)('task-deliverable', task, JSON.stringify(payload));
|
|
51
|
+
}
|
|
46
52
|
/**
|
|
47
53
|
* `skrr tasks deliverable add <task> <kind>:<identity>[@<location>]`
|
|
48
54
|
*
|
|
@@ -155,6 +161,7 @@ class TasksDeliverableAdd extends base_command_1.BaseCommand {
|
|
|
155
161
|
taskId: args.task,
|
|
156
162
|
filePath: archivePath,
|
|
157
163
|
identity: parsed.value.identity,
|
|
164
|
+
kind: parsed.value.kind,
|
|
158
165
|
title: flags.title,
|
|
159
166
|
expectationIds: flags.expectation,
|
|
160
167
|
requestedStatus: status,
|
|
@@ -170,7 +177,7 @@ class TasksDeliverableAdd extends base_command_1.BaseCommand {
|
|
|
170
177
|
}
|
|
171
178
|
let result;
|
|
172
179
|
try {
|
|
173
|
-
const
|
|
180
|
+
const observation = {
|
|
174
181
|
...parsed.value,
|
|
175
182
|
...(status ? { status } : {}),
|
|
176
183
|
title: flags.title,
|
|
@@ -179,8 +186,11 @@ class TasksDeliverableAdd extends base_command_1.BaseCommand {
|
|
|
179
186
|
contentDigest: flags['content-digest'],
|
|
180
187
|
expectationIds: flags.expectation,
|
|
181
188
|
runId: flags['run-id'],
|
|
189
|
+
};
|
|
190
|
+
const payload = {
|
|
191
|
+
...observation,
|
|
182
192
|
idempotencyKey: flags['idempotency-key'] ||
|
|
183
|
-
(
|
|
193
|
+
defaultDeliverableIdempotencyKey(args.task, observation),
|
|
184
194
|
};
|
|
185
195
|
const sessionPath = await (0, session_task_endpoints_1.sessionScopedTaskPath)('deliverable');
|
|
186
196
|
result = sessionPath
|
|
@@ -249,6 +259,7 @@ class TasksDeliverableAdd extends base_command_1.BaseCommand {
|
|
|
249
259
|
role: 'deliverable',
|
|
250
260
|
ledger: {
|
|
251
261
|
identity: opts.identity,
|
|
262
|
+
kind: opts.kind,
|
|
252
263
|
title: opts.title,
|
|
253
264
|
expectationIds: opts.expectationIds,
|
|
254
265
|
},
|
|
@@ -23,6 +23,20 @@ function fidelityLabel(value) {
|
|
|
23
23
|
return value || 'unknown fidelity';
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* One coordinate CAN name several pinned versions — v1 and v2 of the same
|
|
28
|
+
* report share title and locator, so without a discriminator the rows look
|
|
29
|
+
* identical (OSK-12798). The content digest is the honest one when pinned;
|
|
30
|
+
* otherwise the version's own id suffix is the distinguisher.
|
|
31
|
+
*/
|
|
32
|
+
function versionLabel(item) {
|
|
33
|
+
if (item.contentDigest) {
|
|
34
|
+
const [algo, hex] = item.contentDigest.split(':');
|
|
35
|
+
return `digest ${algo}:${(hex || '').slice(0, 12)}`;
|
|
36
|
+
}
|
|
37
|
+
const id = (item.resourceVersionId || '').replace(/^wrv_/, '');
|
|
38
|
+
return id ? `version ${id.slice(0, 12)}` : 'version unpinned';
|
|
39
|
+
}
|
|
26
40
|
class TasksDeliverableList extends base_command_1.BaseCommand {
|
|
27
41
|
static description = 'List Deliverables with exact version, location, and evidence state';
|
|
28
42
|
static args = {
|
|
@@ -51,7 +65,7 @@ class TasksDeliverableList extends base_command_1.BaseCommand {
|
|
|
51
65
|
this.log(`${item.linkId} · ${item.kind}${item.format ? `/${item.format}` : ''} · ` +
|
|
52
66
|
`${item.title || item.identity || '(untitled)'}\n` +
|
|
53
67
|
` ${item.location || 'no locator'} · ${fidelityLabel(item.versionFidelity)} · ` +
|
|
54
|
-
`${item.status} · ${item.evidenceLevel}`);
|
|
68
|
+
`${versionLabel(item)} · ${item.status} · ${item.evidenceLevel}`);
|
|
55
69
|
}
|
|
56
70
|
}
|
|
57
71
|
}
|
|
@@ -4,6 +4,7 @@ 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
6
|
const task_lifecycle_output_1 = require("../../../lib/task-lifecycle-output");
|
|
7
|
+
const prompt_1 = require("../../../lib/prompt");
|
|
7
8
|
class TasksLifecycleTransition extends base_command_1.BaseCommand {
|
|
8
9
|
static description = 'Apply a declared lifecycle transition — records effects and advances the stage';
|
|
9
10
|
static args = {
|
|
@@ -33,10 +34,12 @@ class TasksLifecycleTransition extends base_command_1.BaseCommand {
|
|
|
33
34
|
let payload;
|
|
34
35
|
if (flags.payload) {
|
|
35
36
|
try {
|
|
36
|
-
payload =
|
|
37
|
+
payload = (0, prompt_1.parseJsonFlag)(flags.payload, '--payload');
|
|
37
38
|
}
|
|
38
|
-
catch {
|
|
39
|
-
this.error('--payload must be valid JSON.', {
|
|
39
|
+
catch (err) {
|
|
40
|
+
this.error(err instanceof Error ? err.message : '--payload must be valid JSON.', {
|
|
41
|
+
exit: 2,
|
|
42
|
+
});
|
|
40
43
|
}
|
|
41
44
|
if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
|
|
42
45
|
this.error('--payload must be a JSON object.', { exit: 2 });
|
|
@@ -60,7 +60,7 @@ class TasksPlanRunUpdate extends base_command_1.BaseCommand {
|
|
|
60
60
|
let body;
|
|
61
61
|
try {
|
|
62
62
|
if (flags.patch !== undefined) {
|
|
63
|
-
const parsed =
|
|
63
|
+
const parsed = (0, prompt_1.parseJsonFlag)(flags.patch, '--patch');
|
|
64
64
|
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
|
|
65
65
|
throw new Error('--patch must be a JSON object');
|
|
66
66
|
}
|
|
@@ -210,7 +210,7 @@ class TasksResultSubmit extends base_command_1.BaseCommand {
|
|
|
210
210
|
// which the call did not carry. Submitting a Result is not closing a Task;
|
|
211
211
|
// the response now reports where it stands and this prints exactly that.
|
|
212
212
|
this.log(`Submitted Result v${result.result.version} for ${task.id}.`);
|
|
213
|
-
for (const line of (0, task_closure_1.closureReport)(result.closure))
|
|
213
|
+
for (const line of (0, task_closure_1.closureReport)(result.closure, { closing: false }))
|
|
214
214
|
this.log(line);
|
|
215
215
|
if (url)
|
|
216
216
|
this.log(`Task: ${url}`);
|
|
@@ -7,6 +7,7 @@ const outbox_1 = require("../../../lib/outbox");
|
|
|
7
7
|
const task_resolver_1 = require("../../../lib/task-resolver");
|
|
8
8
|
const api_fetch_1 = require("../../../lib/api-fetch");
|
|
9
9
|
const session_task_endpoints_1 = require("../../../lib/session-task-endpoints");
|
|
10
|
+
const prompt_1 = require("../../../lib/prompt");
|
|
10
11
|
class TasksResumeSave extends base_command_1.BaseCommand {
|
|
11
12
|
static description = 'Save recovery state without publishing a visible Task Update';
|
|
12
13
|
static args = {
|
|
@@ -36,10 +37,12 @@ class TasksResumeSave extends base_command_1.BaseCommand {
|
|
|
36
37
|
const task = (0, task_resolver_1.resolveTaskIdentity)({ positionalId: args.task, flagTask: flags.task });
|
|
37
38
|
let resume;
|
|
38
39
|
try {
|
|
39
|
-
resume =
|
|
40
|
+
resume = (0, prompt_1.parseJsonFlag)(flags.snapshot, '--snapshot');
|
|
40
41
|
}
|
|
41
|
-
catch {
|
|
42
|
-
this.error('--snapshot must be a JSON object', {
|
|
42
|
+
catch (err) {
|
|
43
|
+
this.error(err instanceof Error ? err.message : '--snapshot must be a JSON object', {
|
|
44
|
+
exit: 1,
|
|
45
|
+
});
|
|
43
46
|
}
|
|
44
47
|
let result;
|
|
45
48
|
try {
|
|
@@ -43,7 +43,17 @@ const session_task_endpoints_1 = require("../../../lib/session-task-endpoints");
|
|
|
43
43
|
function parseJsonObject(value, label) {
|
|
44
44
|
if (!value)
|
|
45
45
|
return undefined;
|
|
46
|
-
|
|
46
|
+
let parsed;
|
|
47
|
+
try {
|
|
48
|
+
parsed = JSON.parse(value);
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
// A bare SyntaxError ("Unexpected token …") never says WHICH flag was
|
|
52
|
+
// malformed — name it, the same way readJsonValue names its file
|
|
53
|
+
// (OSK-12753).
|
|
54
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
55
|
+
throw new Error(`Invalid JSON in ${label}: ${msg}`);
|
|
56
|
+
}
|
|
47
57
|
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
48
58
|
throw new Error(`${label} must be a JSON object`);
|
|
49
59
|
}
|
package/dist/lib/file-mime.js
CHANGED
package/dist/lib/prompt.d.ts
CHANGED
|
@@ -46,6 +46,13 @@ export declare function confirmDestructive(question: string, yesFlag: boolean, f
|
|
|
46
46
|
* commands can surface the error via `this.handleApiError()` or similar.
|
|
47
47
|
*/
|
|
48
48
|
export declare function readJsonValue(source: string | undefined): Promise<unknown>;
|
|
49
|
+
/**
|
|
50
|
+
* Parse a flag-supplied JSON value. A bare `JSON.parse` throws a SyntaxError
|
|
51
|
+
* that never names which flag was malformed — `--data '{bad'` reads
|
|
52
|
+
* "Unexpected token" with no owner. `readJsonValue` already names its file;
|
|
53
|
+
* this is the same contract for inline flag values (OSK-12753).
|
|
54
|
+
*/
|
|
55
|
+
export declare function parseJsonFlag(value: string, flagName: string): unknown;
|
|
49
56
|
export declare function readJsonBody(source: string | undefined): Promise<Record<string, unknown>>;
|
|
50
57
|
export declare function readStdin(): Promise<string>;
|
|
51
58
|
/**
|
package/dist/lib/prompt.js
CHANGED
|
@@ -37,6 +37,7 @@ exports.prompt = prompt;
|
|
|
37
37
|
exports.confirm = confirm;
|
|
38
38
|
exports.confirmDestructive = confirmDestructive;
|
|
39
39
|
exports.readJsonValue = readJsonValue;
|
|
40
|
+
exports.parseJsonFlag = parseJsonFlag;
|
|
40
41
|
exports.readJsonBody = readJsonBody;
|
|
41
42
|
exports.readStdin = readStdin;
|
|
42
43
|
exports.mergeDefined = mergeDefined;
|
|
@@ -152,6 +153,21 @@ async function readJsonValue(source) {
|
|
|
152
153
|
}
|
|
153
154
|
return parsed;
|
|
154
155
|
}
|
|
156
|
+
/**
|
|
157
|
+
* Parse a flag-supplied JSON value. A bare `JSON.parse` throws a SyntaxError
|
|
158
|
+
* that never names which flag was malformed — `--data '{bad'` reads
|
|
159
|
+
* "Unexpected token" with no owner. `readJsonValue` already names its file;
|
|
160
|
+
* this is the same contract for inline flag values (OSK-12753).
|
|
161
|
+
*/
|
|
162
|
+
function parseJsonFlag(value, flagName) {
|
|
163
|
+
try {
|
|
164
|
+
return JSON.parse(value);
|
|
165
|
+
}
|
|
166
|
+
catch (err) {
|
|
167
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
168
|
+
throw new Error(`Invalid JSON in ${flagName}: ${msg}`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
155
171
|
async function readJsonBody(source) {
|
|
156
172
|
const parsed = await readJsonValue(source);
|
|
157
173
|
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { MemoryMount as SharedMemoryMount, MemoryStore as SharedMemoryStore } from '@skrr-ai/data-schemas';
|
|
2
2
|
import { BaseCommand } from '../base-command';
|
|
3
3
|
import { ApiFetchError, type ApiFetchOptions } from './api-fetch';
|
|
4
4
|
export type MemoryMount = SharedMemoryMount;
|
|
5
5
|
export type MemoryStore = SharedMemoryStore & {
|
|
6
|
-
mount
|
|
6
|
+
mount: SharedMemoryMount;
|
|
7
7
|
};
|
|
8
|
+
export declare function parseMemoryMount(value: unknown): MemoryMount;
|
|
9
|
+
export declare function parseMountedMemoryStore(value: unknown): MemoryStore;
|
|
8
10
|
export declare const scopedMemoryFlags: {
|
|
9
11
|
agent: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
10
12
|
space: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
@@ -1,12 +1,36 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ScopedMemoryCommand = exports.versionedMutationFlags = exports.mutationFlags = exports.scopedMemoryFlags = void 0;
|
|
4
|
+
exports.parseMemoryMount = parseMemoryMount;
|
|
5
|
+
exports.parseMountedMemoryStore = parseMountedMemoryStore;
|
|
4
6
|
exports.parseMemoryApiError = parseMemoryApiError;
|
|
5
7
|
const core_1 = require("@oclif/core");
|
|
6
|
-
const data_schemas_1 = require("@skrr-ai/data-schemas");
|
|
7
8
|
const node_crypto_1 = require("node:crypto");
|
|
8
9
|
const base_command_1 = require("../base-command");
|
|
9
10
|
const api_fetch_1 = require("./api-fetch");
|
|
11
|
+
// The public CLI must not load the private data-schemas package at runtime.
|
|
12
|
+
// The API validates the full wire contract; check the fields used by CLI commands
|
|
13
|
+
// before treating a response as a mounted Store or mount.
|
|
14
|
+
function parseMemoryMount(value) {
|
|
15
|
+
const mount = value;
|
|
16
|
+
if (!mount || typeof mount !== 'object' || typeof mount.storeId !== 'string' ||
|
|
17
|
+
typeof mount.uri !== 'string' || typeof mount.authorizationGeneration !== 'number' ||
|
|
18
|
+
!['read_only', 'read_write'].includes(String(mount.access)) ||
|
|
19
|
+
!['agent', 'current_space', 'ancestor_space'].includes(String(mount.source))) {
|
|
20
|
+
throw new Error('Invalid Memory mount response from server');
|
|
21
|
+
}
|
|
22
|
+
return mount;
|
|
23
|
+
}
|
|
24
|
+
function parseMountedMemoryStore(value) {
|
|
25
|
+
const store = value;
|
|
26
|
+
if (!store || typeof store !== 'object' || typeof store.id !== 'string' ||
|
|
27
|
+
typeof store.revision !== 'number' || typeof store.authorizationGeneration !== 'number' ||
|
|
28
|
+
!store.owner || !['agent', 'space'].includes(String(store.owner.kind)) ||
|
|
29
|
+
typeof store.owner.id !== 'string') {
|
|
30
|
+
throw new Error('Invalid Memory Store response from server');
|
|
31
|
+
}
|
|
32
|
+
return { ...store, mount: parseMemoryMount(store.mount) };
|
|
33
|
+
}
|
|
10
34
|
exports.scopedMemoryFlags = {
|
|
11
35
|
agent: core_1.Flags.string({ description: 'Act through this Agent', required: true }),
|
|
12
36
|
space: core_1.Flags.string({ description: 'Current Space context (required for Space scopes)' }),
|
|
@@ -126,7 +150,7 @@ class ScopedMemoryCommand extends base_command_1.BaseCommand {
|
|
|
126
150
|
async resolveStore(flags, { write = false } = {}) {
|
|
127
151
|
if (flags.store) {
|
|
128
152
|
const rawStore = await this.memoryApi(flags.agent, `/stores/${encodeURIComponent(flags.store)}${this.query(flags)}`);
|
|
129
|
-
const store =
|
|
153
|
+
const store = parseMountedMemoryStore(rawStore);
|
|
130
154
|
if (write && store.mount?.access !== 'read_write') {
|
|
131
155
|
this.error('MEMORY_STORE_READ_ONLY: selected Store is read-only', { exit: 5 });
|
|
132
156
|
}
|
|
@@ -143,7 +167,7 @@ class ScopedMemoryCommand extends base_command_1.BaseCommand {
|
|
|
143
167
|
this.error(`MEMORY_SPACE_CONTEXT_REQUIRED: --space ${id} is required when selecting ${flags.scope}.`, { exit: 2, code: 'MEMORY_SPACE_CONTEXT_REQUIRED' });
|
|
144
168
|
}
|
|
145
169
|
const response = await this.memoryApi(flags.agent, `/stores${this.query(flags)}`);
|
|
146
|
-
const stores = response.stores.map(
|
|
170
|
+
const stores = response.stores.map(parseMountedMemoryStore);
|
|
147
171
|
const store = stores.find((candidate) => candidate.owner.kind === kind && candidate.owner.id === id);
|
|
148
172
|
if (!store)
|
|
149
173
|
this.error(`MEMORY_NOT_MOUNTED: ${flags.scope}`, { exit: 5 });
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { WorkResourceKind } from '@skrr-ai/data-provider';
|
|
1
2
|
export type TaskAssetRole = 'input' | 'evidence' | 'deliverable';
|
|
2
3
|
/**
|
|
3
4
|
* What the bytes ARE in the work ledger, for an upload that is the archived
|
|
@@ -15,6 +16,10 @@ export type TaskAssetRole = 'input' | 'evidence' | 'deliverable';
|
|
|
15
16
|
*/
|
|
16
17
|
export interface TaskAssetLedgerResource {
|
|
17
18
|
identity: string;
|
|
19
|
+
/** The cited artifact's coordinate kind — the Resource identity depends on
|
|
20
|
+
* it (`url:` bytes must land on the `url` Resource, not a parallel `file`
|
|
21
|
+
* one). Omitted by callers that mean the literal file (OSK-12740). */
|
|
22
|
+
kind?: WorkResourceKind;
|
|
18
23
|
title?: string;
|
|
19
24
|
expectationIds?: string[];
|
|
20
25
|
}
|
|
@@ -212,6 +212,8 @@ function fileFormData(filePath, filename, mimeType, role, ledger) {
|
|
|
212
212
|
fd.append('role', role);
|
|
213
213
|
if (ledger?.identity) {
|
|
214
214
|
fd.append('identity', ledger.identity);
|
|
215
|
+
if (ledger.kind)
|
|
216
|
+
fd.append('kind', ledger.kind);
|
|
215
217
|
if (ledger.title)
|
|
216
218
|
fd.append('title', ledger.title);
|
|
217
219
|
if (ledger.expectationIds?.length) {
|
|
@@ -243,6 +245,7 @@ async function genericDirectUpload(p) {
|
|
|
243
245
|
...(p.ledger?.identity
|
|
244
246
|
? {
|
|
245
247
|
identity: p.ledger.identity,
|
|
248
|
+
kind: p.ledger.kind,
|
|
246
249
|
title: p.ledger.title,
|
|
247
250
|
expectationIds: p.ledger.expectationIds,
|
|
248
251
|
}
|
|
@@ -275,6 +278,7 @@ async function sessionDirectUpload(p) {
|
|
|
275
278
|
...(p.ledger?.identity
|
|
276
279
|
? {
|
|
277
280
|
identity: p.ledger.identity,
|
|
281
|
+
kind: p.ledger.kind,
|
|
278
282
|
title: p.ledger.title,
|
|
279
283
|
expectationIds: p.ledger.expectationIds,
|
|
280
284
|
}
|
|
@@ -42,7 +42,9 @@ export type ClosureLike = TaskClosureEvaluation | {
|
|
|
42
42
|
* gate's own details carried for a while, and they are unusable on their own —
|
|
43
43
|
* the whole point is to be able to act without a second lookup.
|
|
44
44
|
*/
|
|
45
|
-
export declare function closureReport(closure: ClosureLike
|
|
45
|
+
export declare function closureReport(closure: ClosureLike, { closing }?: {
|
|
46
|
+
closing?: boolean;
|
|
47
|
+
}): string[];
|
|
46
48
|
/**
|
|
47
49
|
* The ways forward when a closed Task refuses a Result (`TASK_REOPEN_REQUIRED`).
|
|
48
50
|
*
|
package/dist/lib/task-closure.js
CHANGED
|
@@ -38,7 +38,7 @@ const SHORT_BLOCKER = data_provider_1.CLOSURE_BLOCKER_PHRASE;
|
|
|
38
38
|
* gate's own details carried for a while, and they are unusable on their own —
|
|
39
39
|
* the whole point is to be able to act without a second lookup.
|
|
40
40
|
*/
|
|
41
|
-
function closureReport(closure) {
|
|
41
|
+
function closureReport(closure, { closing = true } = {}) {
|
|
42
42
|
if (!closure)
|
|
43
43
|
return ['Closure state: not reported by this call.'];
|
|
44
44
|
if (isUnavailable(closure)) {
|
|
@@ -98,9 +98,19 @@ function closureReport(closure) {
|
|
|
98
98
|
*/
|
|
99
99
|
const reviewRequired = closure.blockers.some((b) => b.code === 'TASK_RESULT_REVIEW_REQUIRED');
|
|
100
100
|
lines.push('');
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
101
|
+
// `result submit` does not close anything — "if closed anyway" there read
|
|
102
|
+
// as though the submit itself had tried to close and been stamped
|
|
103
|
+
// (OSK-12757). Distinguish the non-closing report from the close one.
|
|
104
|
+
if (closing) {
|
|
105
|
+
lines.push(reviewRequired
|
|
106
|
+
? 'Only an accepted independent Review — or the Task owner closing directly — settles this. The rest is recorded on resolution.closure.'
|
|
107
|
+
: 'If this Task is closed anyway, all of the above is recorded on resolution.closure — closing over it settles nothing.');
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
lines.push(reviewRequired
|
|
111
|
+
? 'Only an accepted independent Review — or the Task owner closing directly — settles this. The rest is recorded on resolution.closure at close.'
|
|
112
|
+
: 'These stay outstanding — closing the Task later records them on resolution.closure.');
|
|
113
|
+
}
|
|
104
114
|
return lines;
|
|
105
115
|
}
|
|
106
116
|
/**
|
|
@@ -42759,6 +42759,10 @@ var gR = Object.freeze({ __proto__: null, acceptAgentIntuition: function(e2, t2,
|
|
|
42759
42759
|
return oR.post((function(e3) {
|
|
42760
42760
|
return "".concat(Rc(e3), "/approve-pr");
|
|
42761
42761
|
})(e2), {});
|
|
42762
|
+
}, approveStoreArtifactAdmission: function(e2, t2) {
|
|
42763
|
+
return oR.post((function(e3) {
|
|
42764
|
+
return "".concat(er(), "/admissions/artifacts/").concat(encodeURIComponent(e3), "/approve");
|
|
42765
|
+
})(e2), t2 ? { note: t2 } : {});
|
|
42762
42766
|
}, approveStoreListingAdmission: dR, approveStoreReleaseAdmission: lR, approveWorkflowMerge: function(e2) {
|
|
42763
42767
|
return oR.post((function(e3) {
|
|
42764
42768
|
return "".concat(jr(), "/").concat(encodeURIComponent(e3), "/workflow/approve-merge");
|
|
@@ -43194,10 +43198,10 @@ var gR = Object.freeze({ __proto__: null, acceptAgentIntuition: function(e2, t2,
|
|
|
43194
43198
|
var t2 = e2.taskId, n2 = e2.data;
|
|
43195
43199
|
return oR.post(ka(t2), n2);
|
|
43196
43200
|
}, createTaskAttachmentUploadIntent: function(e2) {
|
|
43197
|
-
var t2 = e2.taskId, n2 = e2.filename, o2 = e2.mimeType, r2 = e2.sizeBytes, a2 = e2.sha256, i2 = e2.role, s2 = e2.commentId, c2 = e2.identity, l2 = e2.
|
|
43201
|
+
var t2 = e2.taskId, n2 = e2.filename, o2 = e2.mimeType, r2 = e2.sizeBytes, a2 = e2.sha256, i2 = e2.role, s2 = e2.commentId, c2 = e2.identity, l2 = e2.kind, u2 = e2.title, d2 = e2.expectationIds, p2 = e2.transport;
|
|
43198
43202
|
return oR.post((function(e3) {
|
|
43199
43203
|
return "".concat(jr(), "/").concat(encodeURIComponent(e3), "/attachments/upload-intent");
|
|
43200
|
-
})(t2), S(S(S(S(S(S({ filename: n2, mimeType: o2, sizeBytes: r2, sha256: a2 }, i2 ? { role: i2 } : {}), s2 ? { commentId: s2 } : {}), c2 ? { identity: c2 } : {}), c2 && l2 ? {
|
|
43204
|
+
})(t2), S(S(S(S(S(S(S({ filename: n2, mimeType: o2, sizeBytes: r2, sha256: a2 }, i2 ? { role: i2 } : {}), s2 ? { commentId: s2 } : {}), c2 ? { identity: c2 } : {}), c2 && l2 ? { kind: l2 } : {}), c2 && u2 ? { title: u2 } : {}), c2 && (null == d2 ? void 0 : d2.length) ? { expectationIds: d2 } : {}), p2 ? { transport: p2 } : {}));
|
|
43201
43205
|
}, createTaskFollowUp: function(e2) {
|
|
43202
43206
|
var t2 = e2.taskId, n2 = e2.data;
|
|
43203
43207
|
return oR.post((function(e3) {
|
|
@@ -46040,6 +46044,10 @@ var gR = Object.freeze({ __proto__: null, acceptAgentIntuition: function(e2, t2,
|
|
|
46040
46044
|
return oR.post((function(e3) {
|
|
46041
46045
|
return "".concat(jr(), "/").concat(encodeURIComponent(e3), "/workflow-findings");
|
|
46042
46046
|
})(e2), t2);
|
|
46047
|
+
}, refuseStoreArtifactAdmission: function(e2, t2) {
|
|
46048
|
+
return oR.post((function(e3) {
|
|
46049
|
+
return "".concat(er(), "/admissions/artifacts/").concat(encodeURIComponent(e3), "/refuse");
|
|
46050
|
+
})(e2), { note: t2 });
|
|
46043
46051
|
}, refuseStoreListingAdmission: pR, refuseStoreReleaseAdmission: uR, regenerateBackupCodes: function() {
|
|
46044
46052
|
return oR.post("".concat(en, "/api/auth/2fa/backup/regenerate"));
|
|
46045
46053
|
}, register: function(e2) {
|
|
@@ -46534,10 +46542,10 @@ var gR = Object.freeze({ __proto__: null, acceptAgentIntuition: function(e2, t2,
|
|
|
46534
46542
|
}, setAgentUsageCap: function(e2, t2) {
|
|
46535
46543
|
return oR.put(Nn(e2), t2);
|
|
46536
46544
|
}, setAgentVisibility: function(e2) {
|
|
46537
|
-
var t2 = e2.agentId, n2 = e2.isPublic, o2 = e2.price, r2 = e2.shareMode, a2 = e2.changelog, i2 = e2.versionMajor, s2 = e2.versionMinor, c2 = e2.capabilityRationales, l2 = e2.supportedLanguages, u2 = e2.
|
|
46538
|
-
return void 0 !== o2 && (
|
|
46545
|
+
var t2 = e2.agentId, n2 = e2.isPublic, o2 = e2.price, r2 = e2.shareMode, a2 = e2.changelog, i2 = e2.versionMajor, s2 = e2.versionMinor, c2 = e2.capabilityRationales, l2 = e2.supportedLanguages, u2 = e2.dependencies, d2 = e2.license, p2 = e2.sourceVisibility, m2 = { isPublic: n2 };
|
|
46546
|
+
return void 0 !== o2 && (m2.price = o2), void 0 !== r2 && (m2.shareMode = r2), void 0 !== a2 && (m2.changelog = a2), void 0 !== i2 && (m2.versionMajor = i2), void 0 !== s2 && (m2.versionMinor = s2), void 0 !== c2 && (m2.capabilityRationales = c2), void 0 !== l2 && (m2.supportedLanguages = l2), void 0 !== u2 && (m2.dependencies = u2), void 0 !== d2 && (m2.license = d2), void 0 !== p2 && (m2.sourceVisibility = p2), oR.post((function(e3) {
|
|
46539
46547
|
return "".concat(en, "/api/agents/").concat(e3, "/visibility");
|
|
46540
|
-
})(t2),
|
|
46548
|
+
})(t2), m2);
|
|
46541
46549
|
}, setAlwaysOnDesired: function(e2, t2) {
|
|
46542
46550
|
return oR.put((n2 = e2, "".concat(en, "/api/agents/").concat(encodeURIComponent(n2), "/always-on")), t2);
|
|
46543
46551
|
var n2;
|