@skrr-ai/cli 0.1.130 → 0.1.131
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/agent/message/send.js +3 -0
- package/dist/commands/agents/schedule-trace.js +14 -5
- package/dist/commands/harnesses/prune.d.ts +1 -0
- package/dist/commands/harnesses/prune.js +24 -4
- package/dist/lib/exec-runtime-binary.js +3 -2
- package/dist/lib/harnesses.d.ts +4 -1
- package/dist/lib/harnesses.js +3 -0
- package/dist/lib/schedule.d.ts +2 -0
- package/dist/lib/schedule.js +12 -0
- package/dist/node_modules/@skrr-ai/data-provider/index.js +823 -813
- package/oclif.manifest.json +25 -17
- package/package.json +1 -1
|
@@ -747,6 +747,9 @@ function normalizeIntentPayload({ agentId, jsonBody, merged, }) {
|
|
|
747
747
|
const overlayChannel = optionalString(merged.channelId);
|
|
748
748
|
const overlayThreadTs = optionalString(merged.threadTs);
|
|
749
749
|
const destinationKind = pickDestinationKind({ bodyDestination, overlayKind });
|
|
750
|
+
if (destinationKind !== 'slack_channel' && (overlayThreadTs || bodyDestination?.threadTs)) {
|
|
751
|
+
throw invalidIntent('--thread-ts / destination.threadTs only applies to slack_channel.');
|
|
752
|
+
}
|
|
750
753
|
const destination = buildDestination({
|
|
751
754
|
kind: destinationKind,
|
|
752
755
|
bodyDestination,
|
|
@@ -25,7 +25,7 @@ class AgentsScheduleTrace extends base_command_1.BaseCommand {
|
|
|
25
25
|
};
|
|
26
26
|
static flags = {
|
|
27
27
|
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
28
|
-
date: core_1.Flags.string({ description: 'Plan date (YYYY-MM-DD). Defaults to today.' }),
|
|
28
|
+
date: core_1.Flags.string({ description: 'Plan date (YYYY-MM-DD). Defaults to today in the plan timezone.' }),
|
|
29
29
|
todo: core_1.Flags.string({ description: 'Scope the trace to one to-do' }),
|
|
30
30
|
timezone: core_1.Flags.string({ description: 'IANA timezone for the plan day' }),
|
|
31
31
|
limit: core_1.Flags.integer({ description: 'Events to return (1-200)' }),
|
|
@@ -34,16 +34,25 @@ class AgentsScheduleTrace extends base_command_1.BaseCommand {
|
|
|
34
34
|
async run() {
|
|
35
35
|
this.requireAuth();
|
|
36
36
|
const { args, flags } = await this.parse(AgentsScheduleTrace);
|
|
37
|
-
//
|
|
38
|
-
//
|
|
39
|
-
const
|
|
37
|
+
// Use the same zone for choosing the day and querying its events. UTC can
|
|
38
|
+
// already be tomorrow while it is still evening for the reader.
|
|
39
|
+
const timezone = flags.timezone ?? (flags.date ? undefined : Intl.DateTimeFormat().resolvedOptions().timeZone);
|
|
40
|
+
let date = flags.date;
|
|
41
|
+
if (!date) {
|
|
42
|
+
try {
|
|
43
|
+
date = (0, schedule_1.scheduleTraceToday)(new Date(), timezone);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
this.error(`Invalid IANA timezone: ${timezone}`, { exit: 1 });
|
|
47
|
+
}
|
|
48
|
+
}
|
|
40
49
|
let trace;
|
|
41
50
|
try {
|
|
42
51
|
trace = await schedule_1.scheduleApi.scheduleTrace({
|
|
43
52
|
agentId: args.agent,
|
|
44
53
|
date,
|
|
45
54
|
todoId: flags.todo,
|
|
46
|
-
timezone
|
|
55
|
+
timezone,
|
|
47
56
|
limit: flags.limit,
|
|
48
57
|
cursor: flags.cursor,
|
|
49
58
|
});
|
|
@@ -18,6 +18,7 @@ export default class HarnessesPrune extends BaseCommand {
|
|
|
18
18
|
yes: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
19
19
|
limit: import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
20
20
|
'older-than': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
21
|
+
'include-gone-leases': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
21
22
|
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
22
23
|
};
|
|
23
24
|
run(): Promise<void>;
|
|
@@ -30,12 +30,20 @@ class HarnessesPrune extends base_command_1.BaseCommand {
|
|
|
30
30
|
'pinned row is KEPT, with the agents named. Move the pin (`agents attach-harness`) and run this again.\n\n' +
|
|
31
31
|
'At most --limit rows are removed per run, oldest first; the rest are counted and the next run takes ' +
|
|
32
32
|
'them. Running it again when nothing qualifies removes nothing. A daemon that is still running ' +
|
|
33
|
-
're-registers on its next connection, so removing a row never stops a machine
|
|
33
|
+
're-registers on its next connection, so removing a row never stops a machine.\n\n' +
|
|
34
|
+
'A hosted, dedicated or cloud machine belongs to its lease, so by default it is never touched. ' +
|
|
35
|
+
'--include-gone-leases also considers the rows of such a machine whose lease is GONE (archived, ' +
|
|
36
|
+
'terminating, terminated, failed or lost): no compute runs on it again, so the row can never come ' +
|
|
37
|
+
'back online. A row with no lease, a lease that can come back (stopped, ready, active) and a row ' +
|
|
38
|
+
'with usage recorded against it are kept, and so is everything the rules above keep. Use --older-than ' +
|
|
39
|
+
'to leave recent ones, for example 30d.';
|
|
34
40
|
static examples = [
|
|
35
41
|
'<%= config.bin %> harnesses prune',
|
|
36
42
|
'<%= config.bin %> harnesses prune --yes',
|
|
37
43
|
'<%= config.bin %> harnesses prune --yes --limit 20',
|
|
38
44
|
'<%= config.bin %> harnesses prune --older-than 7d --json',
|
|
45
|
+
'<%= config.bin %> harnesses prune --include-gone-leases --older-than 30d',
|
|
46
|
+
'<%= config.bin %> harnesses prune --include-gone-leases --older-than 30d --yes --limit 200',
|
|
39
47
|
];
|
|
40
48
|
static flags = {
|
|
41
49
|
yes: core_1.Flags.boolean({
|
|
@@ -50,6 +58,10 @@ class HarnessesPrune extends base_command_1.BaseCommand {
|
|
|
50
58
|
'older-than': core_1.Flags.string({
|
|
51
59
|
description: 'Only rows unseen for at least this long: 90m, 36h or 7d (default 24h). The server never goes below its offline window.',
|
|
52
60
|
}),
|
|
61
|
+
'include-gone-leases': core_1.Flags.boolean({
|
|
62
|
+
description: 'Also consider the rows of hosted, dedicated or cloud machines whose lease is gone. Off by default.',
|
|
63
|
+
default: false,
|
|
64
|
+
}),
|
|
53
65
|
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
54
66
|
};
|
|
55
67
|
async run() {
|
|
@@ -71,6 +83,7 @@ class HarnessesPrune extends base_command_1.BaseCommand {
|
|
|
71
83
|
dryRun: !flags.yes,
|
|
72
84
|
...(flags.limit !== undefined ? { limit: flags.limit } : {}),
|
|
73
85
|
...(minUnseenMs !== undefined ? { minUnseenMs } : {}),
|
|
86
|
+
...(flags['include-gone-leases'] ? { includeGoneLeases: true } : {}),
|
|
74
87
|
});
|
|
75
88
|
}
|
|
76
89
|
catch (err) {
|
|
@@ -86,7 +99,9 @@ class HarnessesPrune extends base_command_1.BaseCommand {
|
|
|
86
99
|
render(result) {
|
|
87
100
|
const { dryRun } = result;
|
|
88
101
|
const removing = dryRun ? result.remove.length : result.removedCount;
|
|
89
|
-
|
|
102
|
+
// "superseded" is only true of the personal-machine rows; a gone-lease row was not replaced by anything.
|
|
103
|
+
const kind = result.remove.some((row) => row.goneLease) ? '' : 'superseded ';
|
|
104
|
+
const noun = (n) => `${n} ${kind}harness row${n === 1 ? '' : 's'}`;
|
|
90
105
|
if (dryRun) {
|
|
91
106
|
this.log('Dry run - nothing was removed.');
|
|
92
107
|
}
|
|
@@ -141,6 +156,9 @@ class HarnessesPrune extends base_command_1.BaseCommand {
|
|
|
141
156
|
if (count('not_personal_machine') > 0) {
|
|
142
157
|
passedOver.push(`${count('not_personal_machine')} hosted, dedicated, cloud or of unknown origin`);
|
|
143
158
|
}
|
|
159
|
+
if (count('lease_not_gone') > 0) {
|
|
160
|
+
passedOver.push(`${count('lease_not_gone')} of a machine whose lease is not gone`);
|
|
161
|
+
}
|
|
144
162
|
if (count('no_machine_identity') > 0) {
|
|
145
163
|
passedOver.push(`${count('no_machine_identity')} that name no machine`);
|
|
146
164
|
}
|
|
@@ -159,13 +177,15 @@ class HarnessesPrune extends base_command_1.BaseCommand {
|
|
|
159
177
|
provider: (0, format_1.formatCell)(row.provider),
|
|
160
178
|
daemon: (0, format_1.formatCell)(row.daemonId),
|
|
161
179
|
seen: (0, format_1.localStamp)(row.lastSeenAt),
|
|
162
|
-
replacedBy:
|
|
180
|
+
replacedBy: row.goneLease
|
|
181
|
+
? `lease gone (${row.goneLease})`
|
|
182
|
+
: (0, format_1.formatCell)(row.supersededBy?.daemonId),
|
|
163
183
|
})), [
|
|
164
184
|
{ key: 'id', header: 'HARNESS ID' },
|
|
165
185
|
{ key: 'provider', header: 'PROVIDER' },
|
|
166
186
|
{ key: 'daemon', header: 'DAEMON ID', verbatim: true },
|
|
167
187
|
{ key: 'seen', header: `LAST SEEN (${(0, format_1.localZone)()})` },
|
|
168
|
-
{ key: 'replacedBy', header: 'REPLACED BY (ONLINE)', verbatim: true },
|
|
188
|
+
{ key: 'replacedBy', header: 'REPLACED BY (ONLINE) / LEASE', verbatim: true },
|
|
169
189
|
], (line) => this.log(line));
|
|
170
190
|
}
|
|
171
191
|
}
|
|
@@ -75,9 +75,10 @@ function forwardedFlagsNote(verb, opts = {}) {
|
|
|
75
75
|
// daemon cannot silently end up on a different deployment than the CLI that
|
|
76
76
|
// installed it (OSK-279). Saying so is the difference between a flag you may
|
|
77
77
|
// pass and a flag that is already being passed for you.
|
|
78
|
+
const help = `${base} If \`skrrd\` is not on your PATH, use its installed path instead (typically \`~/.skrr/bin/skrrd\` on macOS and Linux).`;
|
|
78
79
|
return opts.binds
|
|
79
|
-
? `${
|
|
80
|
-
:
|
|
80
|
+
? `${help} \`--server\` and \`--profile\` are filled in from your CLI session unless you pass them.`
|
|
81
|
+
: help;
|
|
81
82
|
}
|
|
82
83
|
/** Extra well-known install locations for one runtime name, checked after PATH. */
|
|
83
84
|
function fallbackPathsForRuntime(name) {
|
package/dist/lib/harnesses.d.ts
CHANGED
|
@@ -243,7 +243,7 @@ export declare function forgetHarness(id: string): Promise<unknown>;
|
|
|
243
243
|
* server (`pruneSupersededHarnesses.js`, `REASONS`) and worded once, in
|
|
244
244
|
* `harnessPruneReasonSentence`, so the table and `--json` never disagree.
|
|
245
245
|
*/
|
|
246
|
-
export type HarnessPruneReason = 'recent' | 'latest_registration' | 'no_live_sibling' | 'pinned' | 'granted' | 'default' | 'aliased' | 'changed_since_plan';
|
|
246
|
+
export type HarnessPruneReason = 'recent' | 'latest_registration' | 'no_live_sibling' | 'has_usage' | 'pinned' | 'granted' | 'default' | 'aliased' | 'changed_since_plan';
|
|
247
247
|
export interface HarnessPruneRow {
|
|
248
248
|
id: string;
|
|
249
249
|
daemonId: string | null;
|
|
@@ -257,6 +257,8 @@ export interface HarnessPruneRow {
|
|
|
257
257
|
daemonId: string | null;
|
|
258
258
|
lastSeenAt: string | null;
|
|
259
259
|
};
|
|
260
|
+
/** The gone lease a row this call removes (or would) belonged to (`--include-gone-leases`). */
|
|
261
|
+
goneLease?: string;
|
|
260
262
|
/** Set on kept rows. */
|
|
261
263
|
reason?: HarnessPruneReason;
|
|
262
264
|
/** For `pinned`: who holds the pin. Other people's agents are a count, never named. */
|
|
@@ -300,6 +302,7 @@ export declare function pruneHarnesses(options?: {
|
|
|
300
302
|
dryRun: boolean;
|
|
301
303
|
limit?: number;
|
|
302
304
|
minUnseenMs?: number;
|
|
305
|
+
includeGoneLeases?: boolean;
|
|
303
306
|
}): Promise<HarnessPruneResult>;
|
|
304
307
|
/**
|
|
305
308
|
* `--older-than` takes a whole number with a unit: `90m`, `36h`, `7d`. A bare
|
package/dist/lib/harnesses.js
CHANGED
|
@@ -192,6 +192,7 @@ async function pruneHarnesses(options = { dryRun: true }) {
|
|
|
192
192
|
dryRun: options.dryRun,
|
|
193
193
|
...(options.limit !== undefined ? { limit: options.limit } : {}),
|
|
194
194
|
...(options.minUnseenMs !== undefined ? { minUnseenMs: options.minUnseenMs } : {}),
|
|
195
|
+
...(options.includeGoneLeases ? { includeGoneLeases: true } : {}),
|
|
195
196
|
},
|
|
196
197
|
});
|
|
197
198
|
}
|
|
@@ -219,6 +220,8 @@ function harnessPruneReasonSentence(row) {
|
|
|
219
220
|
return 'the newest registration of its provider on that machine';
|
|
220
221
|
case 'no_live_sibling':
|
|
221
222
|
return 'nothing has replaced it - no daemon on that machine is online for this provider';
|
|
223
|
+
case 'has_usage':
|
|
224
|
+
return 'usage is recorded against it, so the row keeps the name that usage is attributed to';
|
|
222
225
|
case 'pinned': {
|
|
223
226
|
const names = (row.detail?.agents ?? []).map((a) => a.name ?? a.id);
|
|
224
227
|
const more = row.detail?.moreAgents ?? 0;
|
package/dist/lib/schedule.d.ts
CHANGED
|
@@ -145,6 +145,8 @@ export interface ScheduleTrace {
|
|
|
145
145
|
has_more?: boolean;
|
|
146
146
|
next_cursor?: string | null;
|
|
147
147
|
}
|
|
148
|
+
/** Calendar day at an instant in the zone used for the schedule query. */
|
|
149
|
+
export declare function scheduleTraceToday(now: Date, timezone: string): string;
|
|
148
150
|
export declare function scheduleTracePath(params: {
|
|
149
151
|
agentId: string;
|
|
150
152
|
date: string;
|
package/dist/lib/schedule.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.scheduleApi = void 0;
|
|
4
|
+
exports.scheduleTraceToday = scheduleTraceToday;
|
|
4
5
|
exports.scheduleTracePath = scheduleTracePath;
|
|
5
6
|
exports.isSmartScheduleProposal = isSmartScheduleProposal;
|
|
6
7
|
exports.describeNonProposal = describeNonProposal;
|
|
@@ -29,6 +30,17 @@ exports.proposalToApproveTodos = proposalToApproveTodos;
|
|
|
29
30
|
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
30
31
|
const format_1 = require("./format");
|
|
31
32
|
const triggers_1 = require("./triggers");
|
|
33
|
+
/** Calendar day at an instant in the zone used for the schedule query. */
|
|
34
|
+
function scheduleTraceToday(now, timezone) {
|
|
35
|
+
const parts = new Intl.DateTimeFormat('en-CA', {
|
|
36
|
+
timeZone: timezone,
|
|
37
|
+
year: 'numeric',
|
|
38
|
+
month: '2-digit',
|
|
39
|
+
day: '2-digit',
|
|
40
|
+
}).formatToParts(now);
|
|
41
|
+
const part = (type) => parts.find((item) => item.type === type)?.value;
|
|
42
|
+
return `${part('year')}-${part('month')}-${part('day')}`;
|
|
43
|
+
}
|
|
32
44
|
function scheduleTracePath(params) {
|
|
33
45
|
return (0, triggers_1.withQuery)('/api/todos/smart-schedule/trace', {
|
|
34
46
|
agentId: params.agentId,
|