@skrr-ai/cli 0.1.102 → 0.1.103
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.js +24 -0
- package/dist/commands/agent/message/send.js +6 -2
- package/dist/commands/agents/triggers/create.js +7 -17
- package/dist/commands/agents/triggers/update.js +41 -28
- package/dist/commands/commitments/preflight.js +18 -1
- package/dist/commands/commitments/roster.d.ts +15 -0
- package/dist/commands/commitments/roster.js +39 -0
- package/dist/commands/commitments/show.js +1 -1
- package/dist/commands/commitments/status.d.ts +17 -0
- package/dist/commands/commitments/status.js +41 -0
- package/dist/commands/commitments/update.js +12 -0
- package/dist/commands/daemon/logs.d.ts +39 -1
- package/dist/commands/daemon/logs.js +140 -13
- package/dist/commands/followups/checkin.js +46 -3
- package/dist/commands/tasks/approvals/resolve.d.ts +12 -0
- package/dist/commands/tasks/approvals/resolve.js +21 -5
- package/dist/commands/triggers/create.js +8 -17
- package/dist/commands/triggers/fire.js +3 -0
- package/dist/commands/triggers/update.js +41 -27
- package/dist/commands/widgets/check.d.ts +39 -0
- package/dist/commands/widgets/check.js +179 -0
- package/dist/lib/agent-mailbox.d.ts +0 -1
- package/dist/lib/agent-mailbox.js +0 -1
- package/dist/lib/commitment-loop-status.d.ts +16 -0
- package/dist/lib/commitment-loop-status.js +164 -0
- package/dist/lib/commitments.d.ts +28 -1
- package/dist/lib/commitments.js +184 -5
- package/dist/lib/delegated-cli.d.ts +23 -1
- package/dist/lib/delegated-cli.js +61 -4
- package/dist/lib/first-party-harness.d.ts +1 -1
- package/dist/lib/first-party-harness.js +1 -1
- package/dist/lib/session-task-write.d.ts +13 -0
- package/dist/lib/session-task-write.js +63 -3
- package/dist/lib/triggers.d.ts +26 -0
- package/dist/lib/triggers.js +134 -1
- package/dist/lib/widgetCheck.d.ts +123 -0
- package/dist/lib/widgetCheck.js +998 -0
- package/dist/lib/widgetStaticScan.d.ts +111 -0
- package/dist/lib/widgetStaticScan.js +833 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/deviceIdentityBridge.d.ts +9 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/deviceIdentityBridge.js +12 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/deviceIdentityBridge.d.ts +9 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/deviceIdentityBridge.js +12 -0
- package/dist/node_modules/@skrr-ai/auth-core/package.json +1 -1
- package/dist/node_modules/@skrr-ai/data-provider/index.js +11902 -8696
- package/oclif.manifest.json +218 -5
- package/package.json +2 -2
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.WIDGETS_CHECK_EXIT = void 0;
|
|
37
|
+
const core_1 = require("@oclif/core");
|
|
38
|
+
const fs = __importStar(require("node:fs"));
|
|
39
|
+
const prompt_1 = require("../../lib/prompt");
|
|
40
|
+
const widgetCheck_1 = require("../../lib/widgetCheck");
|
|
41
|
+
/**
|
|
42
|
+
* `skrr widgets check` — the offline self-check a harness runs in Bash BEFORE it
|
|
43
|
+
* replies, because a rejected widget is only discovered after the message is sent.
|
|
44
|
+
*
|
|
45
|
+
* It extends `Command`, not `BaseCommand`, on purpose: it reads a file or stdin and
|
|
46
|
+
* prints, so it must work with no sign-in, no network and no daemon credential
|
|
47
|
+
* (a sandboxed harness has none, and `BaseCommand.init()` resolves one before any
|
|
48
|
+
* command body runs). The same reason `instructions guide` does it.
|
|
49
|
+
*
|
|
50
|
+
* It reaches NO API. There is no route behind it, so there is nothing for the
|
|
51
|
+
* CLI/API parity spec (`domain-api-parity.spec.ts`) to hold it to: it adds nothing
|
|
52
|
+
* to `api-endpoints.ts` or `dataService`, and it is safe to run anywhere.
|
|
53
|
+
*
|
|
54
|
+
* Exit codes: 0 every widget would be accepted and has no error finding; 1 at
|
|
55
|
+
* least one would be refused or has an error finding (or none was found); 2 the
|
|
56
|
+
* input could not be read.
|
|
57
|
+
*/
|
|
58
|
+
exports.WIDGETS_CHECK_EXIT = { ok: 0, notOk: 1, unreadable: 2 };
|
|
59
|
+
class WidgetsCheck extends core_1.Command {
|
|
60
|
+
static description = 'Check a generative-UI widget offline before sending it: grammar, size limits, JavaScript syntax and likely sandbox failures. Runs entirely offline: it reaches no API, so it needs no sign-in and has no route to keep in parity.';
|
|
61
|
+
static examples = [
|
|
62
|
+
'<%= config.bin %> widgets check reply.md',
|
|
63
|
+
'<%= config.bin %> widgets check - < reply.md',
|
|
64
|
+
'<%= config.bin %> widgets check widget.json --json',
|
|
65
|
+
'<%= config.bin %> widgets check widget.json --render-fence > block.txt',
|
|
66
|
+
];
|
|
67
|
+
static args = {
|
|
68
|
+
file: core_1.Args.string({
|
|
69
|
+
description: 'File to check, or - for stdin. Text containing a widget block, or a JSON widget (a payload, a ui_widget part, or the ui_widget_render arguments, one or an array).',
|
|
70
|
+
required: true,
|
|
71
|
+
ignoreStdin: true,
|
|
72
|
+
}),
|
|
73
|
+
};
|
|
74
|
+
static flags = {
|
|
75
|
+
json: core_1.Flags.boolean({
|
|
76
|
+
description: 'Output the report as JSON: { ok, widgets: [{ id, title, bytes, limits, complete, accepted, ok, issues }], errors, warnings, summary }',
|
|
77
|
+
}),
|
|
78
|
+
format: core_1.Flags.string({
|
|
79
|
+
description: 'How to read the input: auto (JSON if it parses as JSON, otherwise text that contains a widget block), fence, or json',
|
|
80
|
+
options: ['auto', 'fence', 'json'],
|
|
81
|
+
default: 'auto',
|
|
82
|
+
}),
|
|
83
|
+
strict: core_1.Flags.boolean({
|
|
84
|
+
description: 'Also fail (exit 1) on warnings',
|
|
85
|
+
default: false,
|
|
86
|
+
}),
|
|
87
|
+
'render-fence': core_1.Flags.boolean({
|
|
88
|
+
description: 'For a JSON widget: print the correctly delimited block to stdout (the report goes to stderr), verified by parsing it back',
|
|
89
|
+
default: false,
|
|
90
|
+
}),
|
|
91
|
+
};
|
|
92
|
+
async run() {
|
|
93
|
+
const { args, flags } = await this.parse(WidgetsCheck);
|
|
94
|
+
const read = await this.readInput(args.file);
|
|
95
|
+
if (!read.ok) {
|
|
96
|
+
this.emitInputError(flags.json, read.error);
|
|
97
|
+
this.exit(exports.WIDGETS_CHECK_EXIT.unreadable);
|
|
98
|
+
}
|
|
99
|
+
const result = (0, widgetCheck_1.checkWidgetInput)(read.text, {
|
|
100
|
+
format: flags.format,
|
|
101
|
+
strict: flags.strict,
|
|
102
|
+
});
|
|
103
|
+
if (flags['render-fence']) {
|
|
104
|
+
const rendered = (0, widgetCheck_1.renderWidgetFences)(result);
|
|
105
|
+
const report = {
|
|
106
|
+
...result.report,
|
|
107
|
+
errors: [...result.report.errors, ...rendered.errors],
|
|
108
|
+
};
|
|
109
|
+
report.ok = report.ok && rendered.errors.length === 0;
|
|
110
|
+
report.summary = {
|
|
111
|
+
...report.summary,
|
|
112
|
+
errors: report.summary.errors + rendered.errors.length,
|
|
113
|
+
};
|
|
114
|
+
if (flags.json) {
|
|
115
|
+
this.log(JSON.stringify({ ...report, fences: rendered.fences }, null, 2));
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
for (const fence of rendered.fences) {
|
|
119
|
+
this.log(fence);
|
|
120
|
+
}
|
|
121
|
+
process.stderr.write(`${(0, widgetCheck_1.formatWidgetCheckReport)(report).join('\n')}\n`);
|
|
122
|
+
}
|
|
123
|
+
this.exit(report.ok ? exports.WIDGETS_CHECK_EXIT.ok : exports.WIDGETS_CHECK_EXIT.notOk);
|
|
124
|
+
}
|
|
125
|
+
if (flags.json) {
|
|
126
|
+
this.log(JSON.stringify(result.report, null, 2));
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
this.log((0, widgetCheck_1.formatWidgetCheckReport)(result.report).join('\n'));
|
|
130
|
+
}
|
|
131
|
+
this.exit(result.report.ok ? exports.WIDGETS_CHECK_EXIT.ok : exports.WIDGETS_CHECK_EXIT.notOk);
|
|
132
|
+
}
|
|
133
|
+
async readInput(source) {
|
|
134
|
+
try {
|
|
135
|
+
if (source === '-') {
|
|
136
|
+
if (process.stdin.isTTY) {
|
|
137
|
+
return {
|
|
138
|
+
ok: false,
|
|
139
|
+
error: {
|
|
140
|
+
code: 'input/no-stdin',
|
|
141
|
+
message: 'No input on stdin: it is a terminal, so there is nothing to read.',
|
|
142
|
+
fix: `Pipe the widget in (${this.config.bin} widgets check - < reply.md) or pass a file path.`,
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
return { ok: true, text: await (0, prompt_1.readStdin)() };
|
|
147
|
+
}
|
|
148
|
+
const size = fs.statSync(source).size;
|
|
149
|
+
if (size > widgetCheck_1.WIDGET_CHECK_MAX_INPUT_CHARS * 4) {
|
|
150
|
+
return {
|
|
151
|
+
ok: false,
|
|
152
|
+
error: {
|
|
153
|
+
code: 'input/too-large',
|
|
154
|
+
message: `${source} is ${size} bytes, far more than a message can carry.`,
|
|
155
|
+
},
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
return { ok: true, text: fs.readFileSync(source, 'utf8') };
|
|
159
|
+
}
|
|
160
|
+
catch (err) {
|
|
161
|
+
return {
|
|
162
|
+
ok: false,
|
|
163
|
+
error: {
|
|
164
|
+
code: 'input/unreadable',
|
|
165
|
+
message: `Could not read ${source}: ${err?.message ?? String(err)}`,
|
|
166
|
+
fix: 'Pass the path of a readable file, or - to read stdin.',
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
emitInputError(json, error) {
|
|
172
|
+
if (json) {
|
|
173
|
+
this.log(JSON.stringify((0, widgetCheck_1.inputErrorReport)(error), null, 2));
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
process.stderr.write(`error: ${error.message}\n${error.fix ? ` fix: ${error.fix}\n` : ''}`);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
exports.default = WidgetsCheck;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text rendering for `skrr commitments roster` / `skrr commitments status`.
|
|
3
|
+
*
|
|
4
|
+
* The loop state is DERIVED server-side (`CommitmentLoopStatus`); this file
|
|
5
|
+
* only words it. Two rules it must keep:
|
|
6
|
+
* - paused, unarmed and degraded read differently — "you paused it", "nothing
|
|
7
|
+
* will wake it" and "it cannot see" have different fixes;
|
|
8
|
+
* - `unknown` never borrows the healthy wording or an OK mark. "Cannot see"
|
|
9
|
+
* is not "fine".
|
|
10
|
+
*/
|
|
11
|
+
import { type CommitmentLoopStatus, type CommitmentRoster } from '@skrr-ai/data-provider';
|
|
12
|
+
export declare function loopStateLabel(state: unknown): string;
|
|
13
|
+
/** Roster table: one row per Commitment. */
|
|
14
|
+
export declare function formatCommitmentRoster(roster: Partial<CommitmentRoster>): string[];
|
|
15
|
+
/** One Commitment's loop, in full. */
|
|
16
|
+
export declare function formatCommitmentLoopStatus(status: CommitmentLoopStatus): string[];
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.loopStateLabel = loopStateLabel;
|
|
4
|
+
exports.formatCommitmentRoster = formatCommitmentRoster;
|
|
5
|
+
exports.formatCommitmentLoopStatus = formatCommitmentLoopStatus;
|
|
6
|
+
/**
|
|
7
|
+
* Text rendering for `skrr commitments roster` / `skrr commitments status`.
|
|
8
|
+
*
|
|
9
|
+
* The loop state is DERIVED server-side (`CommitmentLoopStatus`); this file
|
|
10
|
+
* only words it. Two rules it must keep:
|
|
11
|
+
* - paused, unarmed and degraded read differently — "you paused it", "nothing
|
|
12
|
+
* will wake it" and "it cannot see" have different fixes;
|
|
13
|
+
* - `unknown` never borrows the healthy wording or an OK mark. "Cannot see"
|
|
14
|
+
* is not "fine".
|
|
15
|
+
*/
|
|
16
|
+
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
17
|
+
const format_1 = require("./format");
|
|
18
|
+
/** One word per state, with a mark only `healthy` may use. */
|
|
19
|
+
const STATE_LABEL = {
|
|
20
|
+
healthy: '✓ healthy',
|
|
21
|
+
blocked: '! blocked',
|
|
22
|
+
paused: '‖ paused',
|
|
23
|
+
unarmed: '! unarmed',
|
|
24
|
+
degraded: '! degraded',
|
|
25
|
+
inactive: '- inactive',
|
|
26
|
+
unknown: '? unknown',
|
|
27
|
+
};
|
|
28
|
+
function loopStateLabel(state) {
|
|
29
|
+
return typeof state === 'string' && state in STATE_LABEL
|
|
30
|
+
? STATE_LABEL[state]
|
|
31
|
+
: STATE_LABEL.unknown;
|
|
32
|
+
}
|
|
33
|
+
function when(value) {
|
|
34
|
+
if (typeof value !== 'string')
|
|
35
|
+
return '-';
|
|
36
|
+
const date = new Date(value);
|
|
37
|
+
if (Number.isNaN(date.getTime()))
|
|
38
|
+
return '-';
|
|
39
|
+
const pad = (n) => String(n).padStart(2, '0');
|
|
40
|
+
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}`;
|
|
41
|
+
}
|
|
42
|
+
function count(value) {
|
|
43
|
+
return typeof value === 'number' && Number.isFinite(value) ? String(value) : '?';
|
|
44
|
+
}
|
|
45
|
+
function runs(status) {
|
|
46
|
+
const used = count(status.cost?.runsToday);
|
|
47
|
+
const max = status.cost?.maxRunsPerDay;
|
|
48
|
+
return typeof max === 'number' ? `${used}/${max}` : used;
|
|
49
|
+
}
|
|
50
|
+
function spend(status) {
|
|
51
|
+
const value = status.cost?.spendTodayUsd;
|
|
52
|
+
if (typeof value !== 'number')
|
|
53
|
+
return 'not metered';
|
|
54
|
+
const amount = `$${value.toFixed(2)}`;
|
|
55
|
+
// A partial ledger is a lower bound; never print it as the whole answer.
|
|
56
|
+
return status.cost?.spendKnown ? amount : `≥ ${amount} (some runs unpriced)`;
|
|
57
|
+
}
|
|
58
|
+
function nextWake(status) {
|
|
59
|
+
const wake = status.nextWakes?.[0];
|
|
60
|
+
return wake ? `${when(wake.at)} ${wake.kind}` : '-';
|
|
61
|
+
}
|
|
62
|
+
function watchSummary(status) {
|
|
63
|
+
const rows = Array.isArray(status.watching) ? status.watching : [];
|
|
64
|
+
if (!rows.length)
|
|
65
|
+
return '-';
|
|
66
|
+
return rows
|
|
67
|
+
.map((row) => {
|
|
68
|
+
const mark = row.access === 'blocked'
|
|
69
|
+
? '✗'
|
|
70
|
+
: row.access === 'unknown'
|
|
71
|
+
? '?'
|
|
72
|
+
: row.completeness === 'partial'
|
|
73
|
+
? '~'
|
|
74
|
+
: '✓';
|
|
75
|
+
return `${row.source}${mark}`;
|
|
76
|
+
})
|
|
77
|
+
.join(' ');
|
|
78
|
+
}
|
|
79
|
+
/** Roster table: one row per Commitment. */
|
|
80
|
+
function formatCommitmentRoster(roster) {
|
|
81
|
+
const lines = [];
|
|
82
|
+
const commitments = Array.isArray(roster.commitments) ? roster.commitments : [];
|
|
83
|
+
lines.push(`Agent ${roster.agentId ?? '-'} — ${commitments.length} commitment${commitments.length === 1 ? '' : 's'}`);
|
|
84
|
+
if (!commitments.length) {
|
|
85
|
+
lines.push('No commitments.');
|
|
86
|
+
return lines;
|
|
87
|
+
}
|
|
88
|
+
(0, format_1.renderTable)(commitments.map((status) => ({
|
|
89
|
+
state: loopStateLabel(status.loopState),
|
|
90
|
+
id: status.commitmentId,
|
|
91
|
+
title: status.systemRole ? `${status.title} [${status.systemRole}]` : status.title,
|
|
92
|
+
next: nextWake(status),
|
|
93
|
+
runs: runs(status),
|
|
94
|
+
watching: watchSummary(status),
|
|
95
|
+
reason: status.loopReason ?? '',
|
|
96
|
+
})), [
|
|
97
|
+
{ key: 'state', header: 'STATE' },
|
|
98
|
+
{ key: 'id', header: 'ID', verbatim: true },
|
|
99
|
+
{ key: 'title', header: 'TITLE', maxWidth: 36 },
|
|
100
|
+
{ key: 'next', header: 'NEXT WAKE' },
|
|
101
|
+
{ key: 'runs', header: 'RUNS TODAY' },
|
|
102
|
+
{ key: 'watching', header: 'WATCHING', maxWidth: 40 },
|
|
103
|
+
{ key: 'reason', header: 'REASON', maxWidth: 40 },
|
|
104
|
+
], (line) => lines.push(line));
|
|
105
|
+
const attention = commitments.filter((status) => !['healthy', 'paused', 'inactive'].includes(String(status.loopState))).length;
|
|
106
|
+
if (attention) {
|
|
107
|
+
lines.push(`${attention} need${attention === 1 ? 's' : ''} attention — run \`skrr commitments status <id>\` for why.`);
|
|
108
|
+
}
|
|
109
|
+
if (roster.truncated) {
|
|
110
|
+
lines.push('More commitments exist than this roster shows.');
|
|
111
|
+
}
|
|
112
|
+
return lines;
|
|
113
|
+
}
|
|
114
|
+
/** One Commitment's loop, in full. */
|
|
115
|
+
function formatCommitmentLoopStatus(status) {
|
|
116
|
+
const lines = [];
|
|
117
|
+
lines.push(`${status.title} (${status.commitmentId})${status.systemRole ? ` [${status.systemRole}]` : ''}`);
|
|
118
|
+
lines.push(` Loop: ${loopStateLabel(status.loopState)}${status.loopReason ? ` (${status.loopReason})` : ''}`);
|
|
119
|
+
lines.push(` ${status.loopDetail || (0, data_provider_1.describeCommitmentLoopState)(status.loopState)}`);
|
|
120
|
+
lines.push(` Lifecycle: ${status.lifecycleStatus}`);
|
|
121
|
+
lines.push(` Last check: ${when(status.lastCheckAt)}`);
|
|
122
|
+
lines.push(` Last seen: ${when(status.lastSuccessfulObservationAt)}`);
|
|
123
|
+
if (status.lastStop) {
|
|
124
|
+
// `fix` is an optional contract field; read it defensively across package builds.
|
|
125
|
+
const stop = status.lastStop;
|
|
126
|
+
lines.push(` Last stop: ${stop.question}${stop.reason ? ` — ${stop.reason}` : ''}`);
|
|
127
|
+
if (stop.detail)
|
|
128
|
+
lines.push(` ${stop.detail}`);
|
|
129
|
+
if (stop.fix)
|
|
130
|
+
lines.push(` Fix: ${stop.fix}`);
|
|
131
|
+
}
|
|
132
|
+
const wakes = Array.isArray(status.nextWakes) ? status.nextWakes : [];
|
|
133
|
+
lines.push(' Next wakes:');
|
|
134
|
+
if (!wakes.length) {
|
|
135
|
+
lines.push(status.loopState === 'unknown'
|
|
136
|
+
? ' (could not be read)'
|
|
137
|
+
: ' none — nothing is scheduled to wake it');
|
|
138
|
+
}
|
|
139
|
+
for (const wake of wakes) {
|
|
140
|
+
lines.push(` ${when(wake.at)} ${wake.kind}${wake.reason ? ` (${wake.reason})` : ''}`);
|
|
141
|
+
}
|
|
142
|
+
const watching = Array.isArray(status.watching) ? status.watching : [];
|
|
143
|
+
lines.push(' Watching:');
|
|
144
|
+
if (!watching.length)
|
|
145
|
+
lines.push(' nothing declared');
|
|
146
|
+
for (const row of watching) {
|
|
147
|
+
const access = row.access === 'readable'
|
|
148
|
+
? row.completeness === 'partial'
|
|
149
|
+
? 'readable, PARTIAL read'
|
|
150
|
+
: 'readable'
|
|
151
|
+
: row.access === 'blocked'
|
|
152
|
+
? 'CANNOT READ'
|
|
153
|
+
: 'not known';
|
|
154
|
+
lines.push(` ${row.source}${row.scope ? ` (${row.scope})` : ''}: ${access}${row.reason ? ` — ${row.reason}` : ''}`);
|
|
155
|
+
// Optional contract field; read defensively across package builds.
|
|
156
|
+
const limitations = row.limitations;
|
|
157
|
+
if (Array.isArray(limitations) && limitations.length) {
|
|
158
|
+
lines.push(` not watched: ${limitations.join(', ')}`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
lines.push(` Open loops: ${count(status.pendingWork?.openLoops)} Pending runs: ${count(status.pendingWork?.pendingRuns)}`);
|
|
162
|
+
lines.push(` Runs today: ${runs(status)} Spend today: ${spend(status)}`);
|
|
163
|
+
return lines;
|
|
164
|
+
}
|
|
@@ -18,7 +18,7 @@ import { type CommitmentObservationsQuery, type CommitmentObservationsResponse }
|
|
|
18
18
|
* "hold this state", derived from a Compass invariant — not authored here).
|
|
19
19
|
*/
|
|
20
20
|
import { COMMITMENT_WATCHED_SOURCES, COMMITMENT_TEMPLATE_IDS, COMMITMENT_CADENCE_MODES, COMMITMENT_CADENCE_TIME_PATTERN, COMMITMENT_CADENCE_MAX_TIMES, COMMITMENT_EXECUTION_ISOLATION_MODES, COMMITMENT_STATUSES, COMMITMENT_KIND_VALUES } from '@skrr-ai/data-provider';
|
|
21
|
-
import type { CommitmentCheck, CommitmentChecksResponse, Commitment, CommitmentActionProposal, CommitmentListResponse, CommitmentPlanResponse, CommitmentStatusResponse, CommitmentWorkLink, CommitmentExecutionReceiptListResponse, CommitmentExecutionReceiptQuarterlyMetricsResponse, CommitmentCapabilitySource, CommitmentDeliveryPatchResponse, CommitmentDeliveryBundleResponse, CommitmentCyclesResponse, CommitmentExplanationResponse, CommitmentRunPermissions } from '@skrr-ai/data-provider';
|
|
21
|
+
import type { CommitmentCheck, CommitmentChecksResponse, Commitment, CommitmentActionProposal, CommitmentListResponse, CommitmentPlanResponse, CommitmentStatusResponse, CommitmentWorkLink, CommitmentExecutionReceiptListResponse, CommitmentExecutionReceiptQuarterlyMetricsResponse, CommitmentCapabilitySource, CommitmentDeliveryPatchResponse, CommitmentDeliveryBundleResponse, CommitmentCyclesResponse, CommitmentExplanationResponse, CommitmentRunPermissions, CommitmentLoopStatus, CommitmentRoster } from '@skrr-ai/data-provider';
|
|
22
22
|
import { withQuery } from './triggers';
|
|
23
23
|
export { COMMITMENT_WATCHED_SOURCES, COMMITMENT_TEMPLATE_IDS, COMMITMENT_CADENCE_MODES, COMMITMENT_CADENCE_TIME_PATTERN, COMMITMENT_CADENCE_MAX_TIMES, COMMITMENT_STATUSES, COMMITMENT_KIND_VALUES, };
|
|
24
24
|
export type { CommitmentCheck, CommitmentChecksResponse, Commitment, CommitmentActionProposal, CommitmentListResponse, CommitmentPlanResponse, CommitmentStatusResponse, CommitmentWorkLink, };
|
|
@@ -223,6 +223,10 @@ export declare const commitmentApi: {
|
|
|
223
223
|
* swept, how stale that is, and the tally it last persisted. Aggregate only.
|
|
224
224
|
*/
|
|
225
225
|
livenessSweep: () => Promise<Record<string, unknown>>;
|
|
226
|
+
/** One agent's Commitments, system roles included, each with its loop status. */
|
|
227
|
+
roster: (agentId: string) => Promise<CommitmentRoster>;
|
|
228
|
+
/** Is this Commitment's loop installed and working. */
|
|
229
|
+
loopStatus: (id: string) => Promise<CommitmentLoopStatus>;
|
|
226
230
|
manifest: (id: string) => Promise<Record<string, unknown>>;
|
|
227
231
|
import: (body: Record<string, unknown>) => Promise<{
|
|
228
232
|
commitment: {
|
|
@@ -737,6 +741,17 @@ export declare function extractStandstillFromCheck(check?: {
|
|
|
737
741
|
* null rather than printing a guess.
|
|
738
742
|
*/
|
|
739
743
|
export declare function describeExecutorBlocked(commitment: CommitmentView): string | null;
|
|
744
|
+
/**
|
|
745
|
+
* The commitment `show` should render: its stored contract, with the
|
|
746
|
+
* assessment replaced by the one the operating state recomputed for this read
|
|
747
|
+
* when the server sent one (OSK-15989). The stored `commitment.assessment` is
|
|
748
|
+
* what the LAST check wrote; while a run is in flight it can still say
|
|
749
|
+
* `blocked`, and printing it above "Agent is working" made the header
|
|
750
|
+
* contradict the rest of the page. `doctor` already reads the live one first.
|
|
751
|
+
*/
|
|
752
|
+
export declare function withLiveAssessment(commitment: CommitmentView, operatingState?: {
|
|
753
|
+
assessment?: unknown;
|
|
754
|
+
} | null): CommitmentView;
|
|
740
755
|
export declare function renderCommitmentSummary(commitment: CommitmentView, log: (line: string) => void,
|
|
741
756
|
/**
|
|
742
757
|
* The most recent check, when the caller has one. Optional because pause /
|
|
@@ -776,6 +791,7 @@ type ReadModelRecord = Record<string, unknown>;
|
|
|
776
791
|
/** Human view for `commitments ledger`; JSON remains the automation surface. */
|
|
777
792
|
export declare function renderCommitmentLedger(ledger: ReadModelRecord, log: (line: string) => void): void;
|
|
778
793
|
export declare function renderCommitmentTrace(trace: ReadModelRecord, log: (line: string) => void): void;
|
|
794
|
+
export declare function renderProactivenessScorecard(scorecard: ReadModelRecord, log: (line: string) => void): void;
|
|
779
795
|
/**
|
|
780
796
|
* One line per Cycle:
|
|
781
797
|
* `09-22 12:04 ● stopped act commitment_execution_budget_exhausted — Raise maxRunsPerDay…`
|
|
@@ -793,6 +809,17 @@ export declare function renderListPageHint(page: {
|
|
|
793
809
|
has_more?: boolean;
|
|
794
810
|
next_cursor?: string | null;
|
|
795
811
|
} | undefined, log: (line: string) => void): void;
|
|
812
|
+
/**
|
|
813
|
+
* Whether a row's retained evidence can still be reopened (OSK-16125).
|
|
814
|
+
*
|
|
815
|
+
* The count alone read as evidence even when every path pointed into a
|
|
816
|
+
* worktree the daemon had already deleted. `retained` artifacts are git
|
|
817
|
+
* locators on the run's delivery commit; `ephemeral` ones cannot be counted
|
|
818
|
+
* on; `unconfirmed` are locators for a path the run did not change. Refs the
|
|
819
|
+
* server classified as none of these (URLs, hashes, legacy rows) count as
|
|
820
|
+
* `other`. `--json` carries each artifact's `ref`, `locator` and `originalRef`.
|
|
821
|
+
*/
|
|
822
|
+
export declare function describeObservationArtifacts(artifacts: unknown): string;
|
|
796
823
|
export declare function renderCommitmentObservations(response: ReadModelRecord, log: (line: string) => void, options?: {
|
|
797
824
|
emptyMessage?: string;
|
|
798
825
|
}): void;
|