@skrr-ai/cli 0.1.131 → 0.1.132
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.d.ts +2 -0
- package/dist/commands/agent/message/send.js +45 -24
- package/dist/commands/agents/plan-day.d.ts +4 -4
- package/dist/commands/agents/plan-day.js +36 -10
- package/dist/commands/agents/schedule-overview.d.ts +14 -0
- package/dist/commands/agents/schedule-overview.js +11 -1
- package/dist/commands/agents/todos/list.d.ts +1 -0
- package/dist/commands/agents/todos/list.js +4 -2
- package/dist/commands/commitments/create.js +13 -0
- package/dist/commands/daemon/install.js +9 -0
- package/dist/generated/agent-guides.json +19 -19
- package/dist/lib/schedule.d.ts +14 -1
- package/dist/lib/schedule.js +6 -3
- package/oclif.manifest.json +18 -2
- package/package.json +1 -1
|
@@ -118,6 +118,8 @@ export default class AgentMessageSend extends BaseCommand {
|
|
|
118
118
|
private submitAsSession;
|
|
119
119
|
private submitAsHuman;
|
|
120
120
|
}
|
|
121
|
+
/** Keep stdout machine-readable while making a slow delivery visible. */
|
|
122
|
+
export declare function withSendWaitNotice<T>(send: () => Promise<T>): Promise<T>;
|
|
121
123
|
export type NormalizedIntentPayload = {
|
|
122
124
|
destination: CanonicalMessageDestination;
|
|
123
125
|
content: {
|
|
@@ -34,6 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.EXIT_DELIVERY_FAILED = exports.EXIT_DELIVERY_RETRYABLE = exports.OWNER_DM_SEGMENTATION_SOFT_LIMIT = void 0;
|
|
37
|
+
exports.withSendWaitNotice = withSendWaitNotice;
|
|
37
38
|
exports.messageSegmentationAdvisory = messageSegmentationAdvisory;
|
|
38
39
|
exports.buildSequencedRequests = buildSequencedRequests;
|
|
39
40
|
exports.deliveryExitCode = deliveryExitCode;
|
|
@@ -308,30 +309,33 @@ class AgentMessageSend extends base_command_1.BaseCommand {
|
|
|
308
309
|
'session claim, not the request. To change it, run the task from a space in ' +
|
|
309
310
|
'the intended workspace.');
|
|
310
311
|
}
|
|
311
|
-
const envelopes =
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
const
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
312
|
+
const { envelopes, halt } = await withSendWaitNotice(async () => {
|
|
313
|
+
const envelopes = [];
|
|
314
|
+
let halt;
|
|
315
|
+
for (const [index, requestPart] of requests.entries()) {
|
|
316
|
+
const envelope = sessionContext
|
|
317
|
+
? await this.submitAsSession({
|
|
318
|
+
sessionContext,
|
|
319
|
+
request: requestPart,
|
|
320
|
+
agentIdentity: agentIdentity,
|
|
321
|
+
principalSource,
|
|
322
|
+
})
|
|
323
|
+
: await this.submitAsHuman({
|
|
324
|
+
request: requestPart,
|
|
325
|
+
agentIdentity: agentIdentity,
|
|
326
|
+
principalSource,
|
|
327
|
+
});
|
|
328
|
+
envelopes.push(envelope);
|
|
329
|
+
// A part that did not reach the user must stop the sequence. Continuing
|
|
330
|
+
// would deliver thought 3 while thought 2 sits held for approval, and the
|
|
331
|
+
// user would read the update out of order — worse than not receiving the
|
|
332
|
+
// tail at all.
|
|
333
|
+
halt = sequenceHalt({ envelope, sentCount: index + 1, totalParts: requests.length });
|
|
334
|
+
if (halt)
|
|
335
|
+
break;
|
|
336
|
+
}
|
|
337
|
+
return { envelopes, halt };
|
|
338
|
+
});
|
|
335
339
|
if (flags.json) {
|
|
336
340
|
// Branch on the REQUESTED part count, not the sent count: a sequence that
|
|
337
341
|
// halted on its first part still has to report the parts it skipped.
|
|
@@ -524,6 +528,18 @@ class AgentMessageSend extends base_command_1.BaseCommand {
|
|
|
524
528
|
}
|
|
525
529
|
}
|
|
526
530
|
exports.default = AgentMessageSend;
|
|
531
|
+
/** Keep stdout machine-readable while making a slow delivery visible. */
|
|
532
|
+
async function withSendWaitNotice(send) {
|
|
533
|
+
const timer = setTimeout(() => {
|
|
534
|
+
process.stderr.write('Waiting for the message outcome; the request is still in progress.\n');
|
|
535
|
+
}, 3000);
|
|
536
|
+
try {
|
|
537
|
+
return await send();
|
|
538
|
+
}
|
|
539
|
+
finally {
|
|
540
|
+
clearTimeout(timer);
|
|
541
|
+
}
|
|
542
|
+
}
|
|
527
543
|
// Re-export the module-scope `request.post` under a local name so the transport
|
|
528
544
|
// helper stays testable without pulling the whole data-provider surface into
|
|
529
545
|
// scope inside every helper file.
|
|
@@ -750,6 +766,11 @@ function normalizeIntentPayload({ agentId, jsonBody, merged, }) {
|
|
|
750
766
|
if (destinationKind !== 'slack_channel' && (overlayThreadTs || bodyDestination?.threadTs)) {
|
|
751
767
|
throw invalidIntent('--thread-ts / destination.threadTs only applies to slack_channel.');
|
|
752
768
|
}
|
|
769
|
+
if (destinationKind !== 'agent_email' &&
|
|
770
|
+
(merged.recipients !== undefined || merged.subject !== undefined ||
|
|
771
|
+
bodyDestination?.recipients !== undefined || bodyDestination?.subject !== undefined)) {
|
|
772
|
+
throw invalidIntent('--to / destination.recipients and --subject / destination.subject only apply to agent_email.');
|
|
773
|
+
}
|
|
753
774
|
const destination = buildDestination({
|
|
754
775
|
kind: destinationKind,
|
|
755
776
|
bodyDestination,
|
|
@@ -28,6 +28,7 @@ export default class AgentsPlanDay extends BaseCommand {
|
|
|
28
28
|
'hours-start': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
29
29
|
'hours-end': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
30
30
|
timezone: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
31
|
+
'approve-next-run': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
31
32
|
'save-hours': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
32
33
|
};
|
|
33
34
|
run(): Promise<void>;
|
|
@@ -44,10 +45,9 @@ export default class AgentsPlanDay extends BaseCommand {
|
|
|
44
45
|
private fetchPending;
|
|
45
46
|
private workingHoursOverride;
|
|
46
47
|
/**
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* polling would just report an absence as if it were a timeout.
|
|
48
|
+
* Gateway failures can interrupt a response after the planner started.
|
|
49
|
+
* Check the durable draft before suggesting another billable request; a
|
|
50
|
+
* 502 can also mean the planner never started, so do not assert that it did.
|
|
51
51
|
*/
|
|
52
52
|
private static readonly TIMEOUT_STATUSES;
|
|
53
53
|
/** Bounded, honest recovery poll. A daemon-run plan lands in ~2-4 minutes. */
|
|
@@ -45,6 +45,10 @@ class AgentsPlanDay extends base_command_1.BaseCommand {
|
|
|
45
45
|
'hours-start': core_1.Flags.string({ description: 'Working-hours start (HH:MM) for the proposal' }),
|
|
46
46
|
'hours-end': core_1.Flags.string({ description: 'Working-hours end (HH:MM) for the proposal' }),
|
|
47
47
|
timezone: core_1.Flags.string({ description: 'IANA timezone for the working-hours window' }),
|
|
48
|
+
'approve-next-run': core_1.Flags.boolean({
|
|
49
|
+
description: 'With --approve, schedule the suggested next planning run',
|
|
50
|
+
dependsOn: ['approve'],
|
|
51
|
+
}),
|
|
48
52
|
'save-hours': core_1.Flags.boolean({
|
|
49
53
|
description: 'On --approve, persist the working-hours window as the agent default',
|
|
50
54
|
}),
|
|
@@ -53,6 +57,14 @@ class AgentsPlanDay extends base_command_1.BaseCommand {
|
|
|
53
57
|
this.requireAuth();
|
|
54
58
|
const { args, flags } = await this.parse(AgentsPlanDay);
|
|
55
59
|
const agentId = args.id;
|
|
60
|
+
if (!flags.dismiss && !flags.approve && flags.timezone) {
|
|
61
|
+
try {
|
|
62
|
+
new Intl.DateTimeFormat('en', { timeZone: flags.timezone });
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
this.error(`Invalid IANA timezone: ${flags.timezone}`, { exit: 1 });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
56
68
|
try {
|
|
57
69
|
if (flags.dismiss) {
|
|
58
70
|
await this.runDismiss(agentId, flags.json);
|
|
@@ -120,12 +132,11 @@ class AgentsPlanDay extends base_command_1.BaseCommand {
|
|
|
120
132
|
};
|
|
121
133
|
}
|
|
122
134
|
/**
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
* polling would just report an absence as if it were a timeout.
|
|
135
|
+
* Gateway failures can interrupt a response after the planner started.
|
|
136
|
+
* Check the durable draft before suggesting another billable request; a
|
|
137
|
+
* 502 can also mean the planner never started, so do not assert that it did.
|
|
127
138
|
*/
|
|
128
|
-
static TIMEOUT_STATUSES = new Set([408, 504, 524]);
|
|
139
|
+
static TIMEOUT_STATUSES = new Set([408, 502, 504, 524]);
|
|
129
140
|
/** Bounded, honest recovery poll. A daemon-run plan lands in ~2-4 minutes. */
|
|
130
141
|
static RECOVERY_ATTEMPTS = 12;
|
|
131
142
|
static RECOVERY_INTERVAL_MS = 15_000;
|
|
@@ -141,9 +152,8 @@ class AgentsPlanDay extends base_command_1.BaseCommand {
|
|
|
141
152
|
return null;
|
|
142
153
|
}
|
|
143
154
|
// stderr, so `--json` stdout stays a single parseable document.
|
|
144
|
-
this.warn(`
|
|
145
|
-
'The run
|
|
146
|
-
'completes — waiting for it rather than starting a second run.');
|
|
155
|
+
this.warn(`The plan request for ${agentId} was interrupted (HTTP ${status}). ` +
|
|
156
|
+
'The run may still be finishing; checking for its saved draft before starting another.');
|
|
147
157
|
for (let attempt = 1; attempt <= AgentsPlanDay.RECOVERY_ATTEMPTS; attempt += 1) {
|
|
148
158
|
await new Promise((resolve) => setTimeout(resolve, AgentsPlanDay.RECOVERY_INTERVAL_MS));
|
|
149
159
|
let pending = null;
|
|
@@ -181,6 +191,7 @@ class AgentsPlanDay extends base_command_1.BaseCommand {
|
|
|
181
191
|
try {
|
|
182
192
|
generated = await schedule_1.scheduleApi.proposeSmartSchedule({
|
|
183
193
|
agentId,
|
|
194
|
+
...(flags.timezone ? { timezone: flags.timezone } : {}),
|
|
184
195
|
...(this.workingHoursOverride(flags)
|
|
185
196
|
? { workingHoursOverride: this.workingHoursOverride(flags) }
|
|
186
197
|
: {}),
|
|
@@ -216,6 +227,9 @@ class AgentsPlanDay extends base_command_1.BaseCommand {
|
|
|
216
227
|
this.log('');
|
|
217
228
|
this.log('This is a draft — nothing is scheduled yet.');
|
|
218
229
|
this.log(` Approve: ${this.config.bin} agents plan-day ${agentId} --approve`);
|
|
230
|
+
if (proposal.nextRunSuggestion) {
|
|
231
|
+
this.log(` Include next run: ${this.config.bin} agents plan-day ${agentId} --approve --approve-next-run`);
|
|
232
|
+
}
|
|
219
233
|
this.log(` Discard: ${this.config.bin} agents plan-day ${agentId} --dismiss`);
|
|
220
234
|
}
|
|
221
235
|
async runApprove(agentId, flags) {
|
|
@@ -224,13 +238,20 @@ class AgentsPlanDay extends base_command_1.BaseCommand {
|
|
|
224
238
|
this.error(`No pending plan for agent ${agentId}. Run \`${this.config.bin} agents plan-day ${agentId}\` first.`, { exit: 4 });
|
|
225
239
|
}
|
|
226
240
|
const todos = (0, schedule_1.proposalToApproveTodos)(proposal);
|
|
227
|
-
if (
|
|
228
|
-
this.error('The pending proposal has no
|
|
241
|
+
if (flags['approve-next-run'] && !proposal.nextRunSuggestion) {
|
|
242
|
+
this.error('The pending proposal has no suggested next run to approve.', { exit: 1 });
|
|
243
|
+
}
|
|
244
|
+
if (todos.length === 0 && !flags['approve-next-run']) {
|
|
245
|
+
const next = proposal.nextRunSuggestion
|
|
246
|
+
? ` Use --approve --approve-next-run to schedule its suggested next run, or --dismiss to discard it.`
|
|
247
|
+
: ' Use --dismiss to discard it.';
|
|
248
|
+
this.error(`The pending proposal has no schedulable to-dos.${next}`, { exit: 1 });
|
|
229
249
|
}
|
|
230
250
|
const result = await schedule_1.scheduleApi.approveSmartSchedule({
|
|
231
251
|
agentId,
|
|
232
252
|
proposalId: proposal.proposalId,
|
|
233
253
|
todos,
|
|
254
|
+
...(flags['approve-next-run'] ? { approveNextRunSuggestion: true } : {}),
|
|
234
255
|
...(flags['save-hours']
|
|
235
256
|
? { saveHoursAsDefault: true, workingHours: proposal.workingHours }
|
|
236
257
|
: {}),
|
|
@@ -254,6 +275,11 @@ class AgentsPlanDay extends base_command_1.BaseCommand {
|
|
|
254
275
|
}
|
|
255
276
|
this.log(`Approved plan ${proposal.proposalId}: created ${result.created.length} to-do(s).`);
|
|
256
277
|
(0, schedule_1.renderCapacityWarning)(result.capacity, (line) => this.log(line));
|
|
278
|
+
if (flags['approve-next-run']) {
|
|
279
|
+
this.log(result.scheduledNextRun?.created
|
|
280
|
+
? `Next planning run scheduled${result.scheduledNextRun.triggerId ? ` (${result.scheduledNextRun.triggerId})` : ''}.`
|
|
281
|
+
: `Next planning run was not created${result.scheduledNextRun?.message || result.scheduledNextRun?.skippedReason ? `: ${result.scheduledNextRun.message || result.scheduledNextRun.skippedReason}` : '.'}`);
|
|
282
|
+
}
|
|
257
283
|
if (result.failed.length > 0) {
|
|
258
284
|
this.log(`${result.failed.length} failed:`);
|
|
259
285
|
for (const f of result.failed) {
|
|
@@ -42,3 +42,17 @@ export declare function reflectionLine(reflection: TriggerDefinition): string;
|
|
|
42
42
|
* else null. "active · next <time>" only says the loop is armed.
|
|
43
43
|
*/
|
|
44
44
|
export declare function reflectionNoteLine(reflection: TriggerDefinition, bin: string): string | null;
|
|
45
|
+
/** A trigger the Always-On control fence withholds, as `/api/upcoming` reports it. */
|
|
46
|
+
export interface WithheldTrigger {
|
|
47
|
+
label?: string;
|
|
48
|
+
reason?: string;
|
|
49
|
+
reasonText?: string;
|
|
50
|
+
indeterminate?: boolean;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* One withheld trigger as the text view prints it. The sentence the server wrote
|
|
54
|
+
* (`reasonText`: "Always-On is off for this agent") is printed rather than the code,
|
|
55
|
+
* because `disabled` alone reads as a property of the trigger when the cause is the
|
|
56
|
+
* agent's Always-On switch. A server that predates `reasonText` still prints the code.
|
|
57
|
+
*/
|
|
58
|
+
export declare function withheldLine(trigger: WithheldTrigger): string;
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.reflectionSummary = reflectionSummary;
|
|
4
4
|
exports.reflectionLine = reflectionLine;
|
|
5
5
|
exports.reflectionNoteLine = reflectionNoteLine;
|
|
6
|
+
exports.withheldLine = withheldLine;
|
|
6
7
|
const core_1 = require("@oclif/core");
|
|
7
8
|
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
8
9
|
const base_command_1 = require("../../base-command");
|
|
@@ -126,7 +127,7 @@ class AgentsScheduleOverview extends base_command_1.BaseCommand {
|
|
|
126
127
|
this.log('');
|
|
127
128
|
this.log(` ${blockedUpcoming.length} trigger(s) withheld — they will not fire as configured:`);
|
|
128
129
|
for (const b of blockedUpcoming.slice(0, 8)) {
|
|
129
|
-
this.log(
|
|
130
|
+
this.log(withheldLine(b));
|
|
130
131
|
}
|
|
131
132
|
if (blockedUpcoming.length > 8) {
|
|
132
133
|
this.log(` … and ${blockedUpcoming.length - 8} more`);
|
|
@@ -214,6 +215,15 @@ function reflectionNoteLine(reflection, bin) {
|
|
|
214
215
|
const note = (0, reflection_1.reflectionAutonomyNote)(reflection, bin);
|
|
215
216
|
return note ? ` Note: ${note}` : null;
|
|
216
217
|
}
|
|
218
|
+
/**
|
|
219
|
+
* One withheld trigger as the text view prints it. The sentence the server wrote
|
|
220
|
+
* (`reasonText`: "Always-On is off for this agent") is printed rather than the code,
|
|
221
|
+
* because `disabled` alone reads as a property of the trigger when the cause is the
|
|
222
|
+
* agent's Always-On switch. A server that predates `reasonText` still prints the code.
|
|
223
|
+
*/
|
|
224
|
+
function withheldLine(trigger) {
|
|
225
|
+
return ` ${trigger.label ?? '(unlabeled)'} — ${trigger.reasonText ?? trigger.reason ?? 'blocked'}`;
|
|
226
|
+
}
|
|
217
227
|
function settledValue(result) {
|
|
218
228
|
return result.status === 'fulfilled' ? result.value : undefined;
|
|
219
229
|
}
|
|
@@ -13,6 +13,7 @@ export default class AgentsTodosList extends BaseCommand {
|
|
|
13
13
|
static flags: {
|
|
14
14
|
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
15
15
|
date: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
16
|
+
timezone: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
16
17
|
};
|
|
17
18
|
run(): Promise<void>;
|
|
18
19
|
}
|
|
@@ -21,14 +21,15 @@ class AgentsTodosList extends base_command_1.BaseCommand {
|
|
|
21
21
|
};
|
|
22
22
|
static flags = {
|
|
23
23
|
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
24
|
-
date: core_1.Flags.string({ description: 'Day to list (YYYY-MM-DD
|
|
24
|
+
date: core_1.Flags.string({ description: 'Day to list (YYYY-MM-DD). Defaults to today in the selected timezone.' }),
|
|
25
|
+
timezone: core_1.Flags.string({ description: 'IANA timezone for the day (defaults to UTC)' }),
|
|
25
26
|
};
|
|
26
27
|
async run() {
|
|
27
28
|
this.requireAuth();
|
|
28
29
|
const { args, flags } = await this.parse(AgentsTodosList);
|
|
29
30
|
let response;
|
|
30
31
|
try {
|
|
31
|
-
response = await schedule_1.scheduleApi.listTodos(args.id, flags.date);
|
|
32
|
+
response = await schedule_1.scheduleApi.listTodos(args.id, flags.date, flags.timezone);
|
|
32
33
|
}
|
|
33
34
|
catch (err) {
|
|
34
35
|
this.handleApiError(err);
|
|
@@ -37,6 +38,7 @@ class AgentsTodosList extends base_command_1.BaseCommand {
|
|
|
37
38
|
this.printJsonResult((0, list_output_1.listResult)(response, 'todos'));
|
|
38
39
|
return;
|
|
39
40
|
}
|
|
41
|
+
this.log(`Day timezone: ${flags.timezone || 'UTC'}`);
|
|
40
42
|
(0, schedule_1.renderTodoList)(response.todos ?? [], (line) => this.log(line));
|
|
41
43
|
}
|
|
42
44
|
}
|
|
@@ -107,6 +107,19 @@ function assertEventDrivenWatchedSource(payload) {
|
|
|
107
107
|
hasEventCapableWatchedSource(payload)) {
|
|
108
108
|
return;
|
|
109
109
|
}
|
|
110
|
+
const sources = Array.isArray(payload.watchedSources) ? payload.watchedSources : [];
|
|
111
|
+
const hasInvalidEvents = sources.some((value) => {
|
|
112
|
+
const source = record(value);
|
|
113
|
+
const config = record(source?.config);
|
|
114
|
+
return source?.enabled !== false && Array.isArray(config?.events) &&
|
|
115
|
+
!hasStructurallyValidExplicitEvent(config);
|
|
116
|
+
});
|
|
117
|
+
if (hasInvalidEvents) {
|
|
118
|
+
throw new Error('Event-driven cadence requires at least one event-capable watched source. ' +
|
|
119
|
+
'An explicit config.events list must contain event objects with non-empty entityType and eventType, ' +
|
|
120
|
+
'for example {"entityType":"github","eventType":"check_run_failed"}. ' +
|
|
121
|
+
'Supply valid bindings, or remove config.events to use the source defaults (which may include more events).');
|
|
122
|
+
}
|
|
110
123
|
throw new Error('Event-driven cadence (--event-driven or --cadence-mode event_plus_interval) requires at least one event-capable watched source. ' +
|
|
111
124
|
'Add --watch github (or another event-capable source), or choose an interval-only cadence.');
|
|
112
125
|
}
|
|
@@ -56,6 +56,15 @@ class DaemonInstall extends core_1.Command {
|
|
|
56
56
|
// own comment records `skrr code run -m <model>` dying the same way. Same
|
|
57
57
|
// mistake, one directory over.
|
|
58
58
|
const argv = this.argv;
|
|
59
|
+
// A forwarded help request is read-only. Do not run installation preflight,
|
|
60
|
+
// bind a profile, or download software just to show the runtime's options.
|
|
61
|
+
if (argv.some((arg) => arg === '--help' || arg === '-h')) {
|
|
62
|
+
if (!(0, exec_runtime_binary_1.isCurrentRuntimeBinary)((0, exec_runtime_binary_1.findRuntimeBinary)())) {
|
|
63
|
+
this.log('The background service is not installed, so its detailed install options are unavailable. Run `skrr daemon install` to install it.');
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
this.exit(await (0, exec_runtime_binary_1.execRuntimeBinary)(['install', '--help']));
|
|
67
|
+
}
|
|
59
68
|
// Before fetching anything: a machine still carrying the previous product
|
|
60
69
|
// identity's state is refused by the runtime's own install, so downloading a
|
|
61
70
|
// release first only delays the same refusal (OSK-6895).
|
|
@@ -454,7 +454,7 @@
|
|
|
454
454
|
"id": "speaking",
|
|
455
455
|
"title": "A Commitment finds; its Agent speaks",
|
|
456
456
|
"readWhen": "a Commitment run found something and you must decide whether the owner hears of it",
|
|
457
|
-
"tokens":
|
|
457
|
+
"tokens": 301,
|
|
458
458
|
"aliases": [],
|
|
459
459
|
"explains": []
|
|
460
460
|
},
|
|
@@ -709,7 +709,7 @@
|
|
|
709
709
|
]
|
|
710
710
|
}
|
|
711
711
|
],
|
|
712
|
-
"hash": "
|
|
712
|
+
"hash": "74f6b87c1bd1f851fbfe0b1ee5da04425d1b6fdafbf55445a39e121af9c4e65b",
|
|
713
713
|
"tokens": 545
|
|
714
714
|
},
|
|
715
715
|
"routedIndex": {
|
|
@@ -1167,7 +1167,7 @@
|
|
|
1167
1167
|
"id": "speaking",
|
|
1168
1168
|
"title": "A Commitment finds; its Agent speaks",
|
|
1169
1169
|
"readWhen": "a Commitment run found something and you must decide whether the owner hears of it",
|
|
1170
|
-
"tokens":
|
|
1170
|
+
"tokens": 301,
|
|
1171
1171
|
"aliases": [],
|
|
1172
1172
|
"explains": []
|
|
1173
1173
|
},
|
|
@@ -1353,7 +1353,7 @@
|
|
|
1353
1353
|
]
|
|
1354
1354
|
}
|
|
1355
1355
|
],
|
|
1356
|
-
"hash": "
|
|
1356
|
+
"hash": "6960740319e60127c5a1007fd32e77afada0b14442b5f6fb810a7fee1407cb63",
|
|
1357
1357
|
"tokens": 494
|
|
1358
1358
|
},
|
|
1359
1359
|
"cards": {
|
|
@@ -1747,7 +1747,7 @@
|
|
|
1747
1747
|
"routed": true,
|
|
1748
1748
|
"aliases": [],
|
|
1749
1749
|
"body": "## Concept model\n\n| Noun | Question it answers |\n| --- | --- |\n| **Compass** | What does good look like for this Agent, and what may it never trade away? |\n| **Northstar** | Which Commitments should exist, at what priority and on what budget? |\n| **Commitment** | Which outcome does this Agent keep true, and how does it keep checking? |\n| **Check** | What did one wake of a Commitment see, decide and do? |\n\nA Commitment is not a unit of work. A **Task** is one unit of work and a **Goal** is a dated\noutcome with key results; a Commitment watches both and may create Tasks, and is neither.\n\n## Decide\n\nFive mechanisms make something happen later, and the noun alone does not pick one:\n\n| Mechanism | What it is for | The signal that picks it |\n| --- | --- | --- |\n| **Follow-up** | Coming back to one thing, once or a bounded few times: a reminder, a watch, a check-in, an agreed action | The ask ends: \"look tomorrow\", \"tell me when CI is green\" |\n| **Trigger** | Running the Agent with a set prompt on a schedule, an event, once, or on demand | The person names when, and every run does the same work |\n| **Heartbeat** | Checking in on a conversation, group chat or Space at a frequency that backs off while unread | The person wants regular contact, not an outcome held |\n| **Commitment** | Keeping an outcome true: watched sources, a cadence and a loop that decides when to act | \"Keep X true\", \"watch this metric\": no end, and stale evidence matters |\n| **Workflow** | Running a durable graph of Tasks in order | Repeatable work whose steps depend on each other |\n\nA one-off \"look at it tomorrow\" is a follow-up, never a Commitment. Standing observation is a\nCommitment with a freshness contract, not a recurring trigger or a task board left running.\n\n## Workflow\n\n### Start a Commitment\n\n1. Read the Agent's Commitments first, and change one rather than add a near-duplicate.\n2. Create it and turn it on in one call: the outcome, what it watches, how often it checks, where\n its work goes. Turning it on runs Preflight; a refusal keeps the draft and reports the code,\n reason and fix.\n3. Leave it a draft only when the person asked to see it first.\n4. Read it back, and tell the person what it watches, how often, and whether it is on.\n\n## Authority\n\n| Actor | May do | Only a person may do |\n| --- | --- | --- |\n| Agent | Read the Commitments of an Agent it can view; create one, change it and turn it on; request a check; pause one; decide whether a finding is worth telling the owner | Lift a stop a person made; set or clear a concurrency limit; choose the Task review policy; approve an action proposal or a cadence change; configure a Northstar's governance or decide its intents |\n| Person | Everything in both columns | — |\n\nA Commitment grants no permission: its runs work under the Agent's own. A Check never writes an\nowner-facing message, and a Compass never creates, rewrites, pauses or archives a Commitment. The\nserver cannot always tell an Agent from the person whose login it holds, so an accepted call is\nnot permission: the right-hand column stays a person's.\n\n## Live state\n\n- `skrr commitments list --agent <agent-id>` — an Agent's Commitments, with status and assessment.\n- `skrr commitments show <commitment-id>` — the contract, its next check and the last one.\n- `skrr commitments roster --agent <agent-id>` — each loop: whether it is armed, its next wake, runs today.\n\n## Related guides\n\n- `tasks` — the Tasks a Commitment creates or watches.\n- `spaces` — Goals, and Workflows: durable graphs of Tasks.\n- `agents` — the Agent a Commitment belongs to, and where its runs execute.\n- `communication` — whether, what and how to tell the owner.",
|
|
1750
|
-
"hash": "
|
|
1750
|
+
"hash": "197d9b84d1a4367ecf4b7a51687604d13814ec9e9265fe662883278a7738d2fa",
|
|
1751
1751
|
"tokens": 1169,
|
|
1752
1752
|
"sections": [
|
|
1753
1753
|
{
|
|
@@ -1824,7 +1824,7 @@
|
|
|
1824
1824
|
"id": "speaking",
|
|
1825
1825
|
"title": "A Commitment finds; its Agent speaks",
|
|
1826
1826
|
"readWhen": "a Commitment run found something and you must decide whether the owner hears of it",
|
|
1827
|
-
"tokens":
|
|
1827
|
+
"tokens": 301,
|
|
1828
1828
|
"aliases": [],
|
|
1829
1829
|
"explains": []
|
|
1830
1830
|
},
|
|
@@ -5850,7 +5850,7 @@
|
|
|
5850
5850
|
"id": "speaking",
|
|
5851
5851
|
"title": "A Commitment finds; its Agent speaks",
|
|
5852
5852
|
"readWhen": "a Commitment run found something and you must decide whether the owner hears of it",
|
|
5853
|
-
"tokens":
|
|
5853
|
+
"tokens": 301,
|
|
5854
5854
|
"aliases": [],
|
|
5855
5855
|
"explains": []
|
|
5856
5856
|
},
|
|
@@ -5966,7 +5966,7 @@
|
|
|
5966
5966
|
"id": "speaking",
|
|
5967
5967
|
"title": "A Commitment finds; its Agent speaks",
|
|
5968
5968
|
"readWhen": "a Commitment run found something and you must decide whether the owner hears of it",
|
|
5969
|
-
"tokens":
|
|
5969
|
+
"tokens": 301,
|
|
5970
5970
|
"aliases": [],
|
|
5971
5971
|
"explains": []
|
|
5972
5972
|
},
|
|
@@ -6084,7 +6084,7 @@
|
|
|
6084
6084
|
"id": "speaking",
|
|
6085
6085
|
"title": "A Commitment finds; its Agent speaks",
|
|
6086
6086
|
"readWhen": "a Commitment run found something and you must decide whether the owner hears of it",
|
|
6087
|
-
"tokens":
|
|
6087
|
+
"tokens": 301,
|
|
6088
6088
|
"aliases": [],
|
|
6089
6089
|
"explains": []
|
|
6090
6090
|
},
|
|
@@ -6206,7 +6206,7 @@
|
|
|
6206
6206
|
"id": "speaking",
|
|
6207
6207
|
"title": "A Commitment finds; its Agent speaks",
|
|
6208
6208
|
"readWhen": "a Commitment run found something and you must decide whether the owner hears of it",
|
|
6209
|
-
"tokens":
|
|
6209
|
+
"tokens": 301,
|
|
6210
6210
|
"aliases": [],
|
|
6211
6211
|
"explains": []
|
|
6212
6212
|
},
|
|
@@ -6322,7 +6322,7 @@
|
|
|
6322
6322
|
"id": "speaking",
|
|
6323
6323
|
"title": "A Commitment finds; its Agent speaks",
|
|
6324
6324
|
"readWhen": "a Commitment run found something and you must decide whether the owner hears of it",
|
|
6325
|
-
"tokens":
|
|
6325
|
+
"tokens": 301,
|
|
6326
6326
|
"aliases": [],
|
|
6327
6327
|
"explains": []
|
|
6328
6328
|
},
|
|
@@ -6438,7 +6438,7 @@
|
|
|
6438
6438
|
"id": "speaking",
|
|
6439
6439
|
"title": "A Commitment finds; its Agent speaks",
|
|
6440
6440
|
"readWhen": "a Commitment run found something and you must decide whether the owner hears of it",
|
|
6441
|
-
"tokens":
|
|
6441
|
+
"tokens": 301,
|
|
6442
6442
|
"aliases": [],
|
|
6443
6443
|
"explains": []
|
|
6444
6444
|
},
|
|
@@ -6560,7 +6560,7 @@
|
|
|
6560
6560
|
"id": "speaking",
|
|
6561
6561
|
"title": "A Commitment finds; its Agent speaks",
|
|
6562
6562
|
"readWhen": "a Commitment run found something and you must decide whether the owner hears of it",
|
|
6563
|
-
"tokens":
|
|
6563
|
+
"tokens": 301,
|
|
6564
6564
|
"aliases": [],
|
|
6565
6565
|
"explains": []
|
|
6566
6566
|
},
|
|
@@ -6598,9 +6598,9 @@
|
|
|
6598
6598
|
"version": 4,
|
|
6599
6599
|
"aliases": [],
|
|
6600
6600
|
"explains": [],
|
|
6601
|
-
"body": "Read this when a Commitment run found something and you must decide whether the owner hears of it.\n\nA Check never writes to the owner. When something it found may matter, the run is handed a brief\nunder \"Owner communication — your call.\": what was found, the evidence, why it may matter and a\nsuggested next step. Those are facts to judge, not a message to forward.\n\n- Decide with everything in view: what you already said, whether the owner replied, what another\n surface already raised. One message, a different message or nothing are all valid outcomes, and\n silence is often the right one.\n- To speak from the run,
|
|
6602
|
-
"hash": "
|
|
6603
|
-
"tokens":
|
|
6601
|
+
"body": "Read this when a Commitment run found something and you must decide whether the owner hears of it.\n\nA Check never writes to the owner. When something it found may matter, the run is handed a brief\nunder \"Owner communication — your call.\": what was found, the evidence, why it may matter and a\nsuggested next step. Those are facts to judge, not a message to forward.\n\n- Decide with everything in view: what you already said, whether the owner replied, what another\n surface already raised. One message, a different message or nothing are all valid outcomes, and\n silence is often the right one.\n- To speak from the run, send it with `skrr agent message send` where the run allows it: it is\n delivered under the owner's limits and counted for this Commitment. Otherwise return a\n `status_update` or `report` action intent with its `text` for the Commitment's report\n destinations. A `message` action intent is recorded but never delivered. Write the words yourself.\n- The owner's limits (mute, quiet hours, a daily nudge cap) decide whether a run is asked to speak\n at all, and whatever you deliver counts against them, whichever way you send it.\n\n`skrr commitments reports <commitment-id>` lists where its reports go and on what condition; the\ndefault sends only on a material change.",
|
|
6602
|
+
"hash": "45fa02a0344903cc355dff0b66eee45b14dab79a8f62fba8620106b29e11e8a9",
|
|
6603
|
+
"tokens": 301,
|
|
6604
6604
|
"sections": [
|
|
6605
6605
|
{
|
|
6606
6606
|
"id": "model",
|
|
@@ -6676,7 +6676,7 @@
|
|
|
6676
6676
|
"id": "speaking",
|
|
6677
6677
|
"title": "A Commitment finds; its Agent speaks",
|
|
6678
6678
|
"readWhen": "a Commitment run found something and you must decide whether the owner hears of it",
|
|
6679
|
-
"tokens":
|
|
6679
|
+
"tokens": 301,
|
|
6680
6680
|
"aliases": [],
|
|
6681
6681
|
"explains": []
|
|
6682
6682
|
},
|
|
@@ -6796,7 +6796,7 @@
|
|
|
6796
6796
|
"id": "speaking",
|
|
6797
6797
|
"title": "A Commitment finds; its Agent speaks",
|
|
6798
6798
|
"readWhen": "a Commitment run found something and you must decide whether the owner hears of it",
|
|
6799
|
-
"tokens":
|
|
6799
|
+
"tokens": 301,
|
|
6800
6800
|
"aliases": [],
|
|
6801
6801
|
"explains": []
|
|
6802
6802
|
},
|
|
@@ -6914,7 +6914,7 @@
|
|
|
6914
6914
|
"id": "speaking",
|
|
6915
6915
|
"title": "A Commitment finds; its Agent speaks",
|
|
6916
6916
|
"readWhen": "a Commitment run found something and you must decide whether the owner hears of it",
|
|
6917
|
-
"tokens":
|
|
6917
|
+
"tokens": 301,
|
|
6918
6918
|
"aliases": [],
|
|
6919
6919
|
"explains": []
|
|
6920
6920
|
},
|
package/dist/lib/schedule.d.ts
CHANGED
|
@@ -68,6 +68,11 @@ export interface SmartScheduleProposal {
|
|
|
68
68
|
truncated: boolean;
|
|
69
69
|
};
|
|
70
70
|
todos: ProposedTodo[];
|
|
71
|
+
nextRunSuggestion?: {
|
|
72
|
+
runAt: string;
|
|
73
|
+
reason?: string;
|
|
74
|
+
confidence?: number;
|
|
75
|
+
};
|
|
71
76
|
/**
|
|
72
77
|
* Agent-scope trigger budget at proposal time. Advisory — approval enforces
|
|
73
78
|
* it for real — but it is the difference between a warning the user can act
|
|
@@ -105,6 +110,12 @@ export interface ApproveSmartScheduleResponse {
|
|
|
105
110
|
}>;
|
|
106
111
|
/** Post-write budget, so a caller approving several plans sees the wall coming. */
|
|
107
112
|
capacity?: TriggerCapacity;
|
|
113
|
+
scheduledNextRun?: {
|
|
114
|
+
created?: boolean;
|
|
115
|
+
triggerId?: string;
|
|
116
|
+
skippedReason?: string;
|
|
117
|
+
message?: string;
|
|
118
|
+
} | null;
|
|
108
119
|
}
|
|
109
120
|
/**
|
|
110
121
|
* The self-schedule TRACE — why the agent's day looks the way it does.
|
|
@@ -165,7 +176,7 @@ export declare const scheduleApi: {
|
|
|
165
176
|
limit?: number;
|
|
166
177
|
cursor?: string;
|
|
167
178
|
}) => Promise<ScheduleTrace>;
|
|
168
|
-
listTodos: (agentId: string, date?: string) => Promise<ListTodosResponse>;
|
|
179
|
+
listTodos: (agentId: string, date?: string, timezone?: string) => Promise<ListTodosResponse>;
|
|
169
180
|
getTodo: (todoId: string) => Promise<Todo>;
|
|
170
181
|
createTodo: (input: CreateTodoInput) => Promise<Todo>;
|
|
171
182
|
/** Cancel a To-Do (DELETE soft-cancels pending; see todos.js). */
|
|
@@ -173,6 +184,7 @@ export declare const scheduleApi: {
|
|
|
173
184
|
proposeSmartSchedule: (input: {
|
|
174
185
|
agentId: string;
|
|
175
186
|
workingHoursOverride?: WorkingHoursWindow;
|
|
187
|
+
timezone?: string;
|
|
176
188
|
regenerateHint?: string;
|
|
177
189
|
}) => Promise<SmartScheduleProposal>;
|
|
178
190
|
pendingProposal: (agentId: string) => Promise<{
|
|
@@ -182,6 +194,7 @@ export declare const scheduleApi: {
|
|
|
182
194
|
agentId: string;
|
|
183
195
|
proposalId: string;
|
|
184
196
|
todos: ApproveTodoInput[];
|
|
197
|
+
approveNextRunSuggestion?: boolean;
|
|
185
198
|
saveHoursAsDefault?: boolean;
|
|
186
199
|
workingHours?: WorkingHoursWindow;
|
|
187
200
|
}) => Promise<ApproveSmartScheduleResponse>;
|
package/dist/lib/schedule.js
CHANGED
|
@@ -52,13 +52,13 @@ function scheduleTracePath(params) {
|
|
|
52
52
|
});
|
|
53
53
|
}
|
|
54
54
|
/** Build the `/api/todos` list query — agentId is required, date optional. */
|
|
55
|
-
function todoListPath(agentId, date) {
|
|
56
|
-
return (0, triggers_1.withQuery)('/api/todos', { agentId, date });
|
|
55
|
+
function todoListPath(agentId, date, timezone) {
|
|
56
|
+
return (0, triggers_1.withQuery)('/api/todos', { agentId, date, timezone });
|
|
57
57
|
}
|
|
58
58
|
exports.scheduleApi = {
|
|
59
59
|
/** The self-schedule trace for one agent-day. See `scheduleTracePath`. */
|
|
60
60
|
scheduleTrace: (params) => data_provider_1.request.get(scheduleTracePath(params)),
|
|
61
|
-
listTodos: (agentId, date) => data_provider_1.request.get(todoListPath(agentId, date)),
|
|
61
|
+
listTodos: (agentId, date, timezone) => data_provider_1.request.get(todoListPath(agentId, date, timezone)),
|
|
62
62
|
getTodo: (todoId) => data_provider_1.request.get(`/api/todos/${encodeURIComponent(todoId)}`),
|
|
63
63
|
createTodo: (input) => data_provider_1.request.post('/api/todos', input),
|
|
64
64
|
/** Cancel a To-Do (DELETE soft-cancels pending; see todos.js). */
|
|
@@ -162,6 +162,9 @@ function renderProposal(proposal, log) {
|
|
|
162
162
|
if (proposal.expiresAt)
|
|
163
163
|
log(`Expires: ${formatStamp(proposal.expiresAt)}`);
|
|
164
164
|
renderCapacityWarning(proposal.capacity, log);
|
|
165
|
+
if (proposal.nextRunSuggestion) {
|
|
166
|
+
log(`Next run: ${formatStamp(proposal.nextRunSuggestion.runAt)}${proposal.nextRunSuggestion.reason ? ` · ${proposal.nextRunSuggestion.reason}` : ''}`);
|
|
167
|
+
}
|
|
165
168
|
log('');
|
|
166
169
|
const live = proposal.todos.filter((t) => !t.dropped);
|
|
167
170
|
if (live.length === 0) {
|
package/oclif.manifest.json
CHANGED
|
@@ -12225,6 +12225,15 @@
|
|
|
12225
12225
|
"multiple": false,
|
|
12226
12226
|
"type": "option"
|
|
12227
12227
|
},
|
|
12228
|
+
"approve-next-run": {
|
|
12229
|
+
"dependsOn": [
|
|
12230
|
+
"approve"
|
|
12231
|
+
],
|
|
12232
|
+
"description": "With --approve, schedule the suggested next planning run",
|
|
12233
|
+
"name": "approve-next-run",
|
|
12234
|
+
"allowNo": false,
|
|
12235
|
+
"type": "boolean"
|
|
12236
|
+
},
|
|
12228
12237
|
"save-hours": {
|
|
12229
12238
|
"description": "On --approve, persist the working-hours window as the agent default",
|
|
12230
12239
|
"name": "save-hours",
|
|
@@ -16065,11 +16074,18 @@
|
|
|
16065
16074
|
"type": "boolean"
|
|
16066
16075
|
},
|
|
16067
16076
|
"date": {
|
|
16068
|
-
"description": "Day to list (YYYY-MM-DD
|
|
16077
|
+
"description": "Day to list (YYYY-MM-DD). Defaults to today in the selected timezone.",
|
|
16069
16078
|
"name": "date",
|
|
16070
16079
|
"hasDynamicHelp": false,
|
|
16071
16080
|
"multiple": false,
|
|
16072
16081
|
"type": "option"
|
|
16082
|
+
},
|
|
16083
|
+
"timezone": {
|
|
16084
|
+
"description": "IANA timezone for the day (defaults to UTC)",
|
|
16085
|
+
"name": "timezone",
|
|
16086
|
+
"hasDynamicHelp": false,
|
|
16087
|
+
"multiple": false,
|
|
16088
|
+
"type": "option"
|
|
16073
16089
|
}
|
|
16074
16090
|
},
|
|
16075
16091
|
"hasDynamicHelp": false,
|
|
@@ -143170,5 +143186,5 @@
|
|
|
143170
143186
|
]
|
|
143171
143187
|
}
|
|
143172
143188
|
},
|
|
143173
|
-
"version": "0.1.
|
|
143189
|
+
"version": "0.1.132"
|
|
143174
143190
|
}
|