@skrr-ai/cli 0.1.132 → 0.1.133
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/agenda/plan.d.ts +4 -4
- package/dist/commands/agenda/plan.js +121 -9
- package/dist/commands/agent/message/send.js +4 -0
- package/dist/commands/agents/intuitions/generate.js +25 -6
- package/dist/commands/agents/intuitions/list.js +7 -2
- package/dist/commands/agents/spawn.js +6 -0
- package/dist/commands/agents/todos/edit.d.ts +14 -0
- package/dist/commands/agents/todos/edit.js +43 -0
- package/dist/commands/agents/triggers/fire.d.ts +2 -2
- package/dist/commands/agents/triggers/fire.js +20 -3
- package/dist/commands/agents/triggers/policy.d.ts +6 -0
- package/dist/commands/agents/triggers/policy.js +22 -0
- package/dist/commands/goals/briefing/enable.js +1 -2
- package/dist/commands/goals/briefing/status.d.ts +8 -0
- package/dist/commands/goals/briefing/status.js +35 -0
- package/dist/commands/memory/list.js +9 -3
- package/dist/lib/schedule.d.ts +6 -0
- package/dist/lib/schedule.js +1 -0
- package/dist/lib/scoped-memory-command.d.ts +10 -0
- package/dist/lib/scoped-memory-command.js +21 -2
- package/dist/node_modules/@skrr-ai/data-provider/index.js +774 -774
- package/oclif.manifest.json +179 -2
- package/package.json +1 -1
|
@@ -7,10 +7,8 @@ import { BaseCommand } from '../../base-command';
|
|
|
7
7
|
* server, and enqueues the agent turn through the canonical agentic
|
|
8
8
|
* pipeline (preflight → BullMQ → AgentWorker → AgenticClient → SDK).
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* not subscribed here. Pair with `skrr convos show <conversationId>` to
|
|
13
|
-
* inspect the resulting agenda once it persists.
|
|
10
|
+
* Interactive terminals follow the accepted session, including permission
|
|
11
|
+
* requests. JSON and non-interactive invocations remain detached by default.
|
|
14
12
|
*/
|
|
15
13
|
export default class AgendaPlan extends BaseCommand {
|
|
16
14
|
static description: string;
|
|
@@ -22,6 +20,8 @@ export default class AgendaPlan extends BaseCommand {
|
|
|
22
20
|
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
23
21
|
'space-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
24
22
|
timezone: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
23
|
+
follow: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
24
|
+
'approve-tools': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
25
25
|
};
|
|
26
26
|
run(): Promise<void>;
|
|
27
27
|
}
|
|
@@ -3,6 +3,22 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const core_1 = require("@oclif/core");
|
|
4
4
|
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
5
5
|
const base_command_1 = require("../../base-command");
|
|
6
|
+
const api_fetch_1 = require("../../lib/api-fetch");
|
|
7
|
+
const agentic_stream_1 = require("../../lib/agentic-stream");
|
|
8
|
+
const chat_1 = require("../agents/chat");
|
|
9
|
+
function describeRuntime(runtime) {
|
|
10
|
+
if (typeof runtime === 'string')
|
|
11
|
+
return runtime;
|
|
12
|
+
if (!runtime || typeof runtime !== 'object')
|
|
13
|
+
return null;
|
|
14
|
+
const record = runtime;
|
|
15
|
+
const plan = record.executionPlan && typeof record.executionPlan === 'object'
|
|
16
|
+
? record.executionPlan : null;
|
|
17
|
+
const selected = typeof plan?.selectedKind === 'string' ? plan.selectedKind : null;
|
|
18
|
+
if (selected)
|
|
19
|
+
return `selected ${selected}${selected === 'agent-worker' && record.daemonId ? '; local daemon available as tool bridge' : ''}`;
|
|
20
|
+
return typeof record.mode === 'string' ? record.mode : null;
|
|
21
|
+
}
|
|
6
22
|
/**
|
|
7
23
|
* `skrr agenda plan <agent-id>` — kick off a one-shot Agenda Planning turn
|
|
8
24
|
* for an agent. The server-side controller resolves the agent's persistent
|
|
@@ -11,10 +27,8 @@ const base_command_1 = require("../../base-command");
|
|
|
11
27
|
* server, and enqueues the agent turn through the canonical agentic
|
|
12
28
|
* pipeline (preflight → BullMQ → AgentWorker → AgenticClient → SDK).
|
|
13
29
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* not subscribed here. Pair with `skrr convos show <conversationId>` to
|
|
17
|
-
* inspect the resulting agenda once it persists.
|
|
30
|
+
* Interactive terminals follow the accepted session, including permission
|
|
31
|
+
* requests. JSON and non-interactive invocations remain detached by default.
|
|
18
32
|
*/
|
|
19
33
|
class AgendaPlan extends base_command_1.BaseCommand {
|
|
20
34
|
static description = 'Trigger an Agenda Planning turn for an agent. Returns the conversation id where the streaming response will land.';
|
|
@@ -34,10 +48,17 @@ class AgendaPlan extends base_command_1.BaseCommand {
|
|
|
34
48
|
timezone: core_1.Flags.string({
|
|
35
49
|
description: 'IANA timezone hint for the agenda turn (defaults to UTC server-side)',
|
|
36
50
|
}),
|
|
51
|
+
follow: core_1.Flags.boolean({ allowNo: true, description: 'Follow the session (default on an interactive terminal)' }),
|
|
52
|
+
'approve-tools': core_1.Flags.boolean({
|
|
53
|
+
description: 'Allow tool prompts; on a non-interactive follow this grants requested tools for the turn',
|
|
54
|
+
}),
|
|
37
55
|
};
|
|
38
56
|
async run() {
|
|
39
57
|
this.requireAuth();
|
|
40
58
|
const { args, flags } = await this.parse(AgendaPlan);
|
|
59
|
+
if (flags.json && flags.follow)
|
|
60
|
+
this.error('--json is detached; use --follow without --json to stream.', { exit: 1 });
|
|
61
|
+
const follow = flags.follow ?? (Boolean(process.stdin.isTTY) && !flags.json);
|
|
41
62
|
let response;
|
|
42
63
|
try {
|
|
43
64
|
response = await data_provider_1.dataService.planAgenda({
|
|
@@ -57,12 +78,103 @@ class AgendaPlan extends base_command_1.BaseCommand {
|
|
|
57
78
|
this.log(`Conversation ID: ${response.conversationId}`);
|
|
58
79
|
this.log(`Session ID: ${response.sessionId}`);
|
|
59
80
|
this.log(`New conversation: ${response.isNewConversation ? 'yes' : 'no'}`);
|
|
60
|
-
|
|
61
|
-
|
|
81
|
+
const runtimeDescription = describeRuntime(response.runtime);
|
|
82
|
+
if (runtimeDescription)
|
|
83
|
+
this.log(`Runtime: ${runtimeDescription}`);
|
|
62
84
|
this.log('');
|
|
63
|
-
|
|
64
|
-
response.conversationId +
|
|
65
|
-
|
|
85
|
+
if (!follow) {
|
|
86
|
+
this.log('The turn is running detached. It may wait for permission; inspect it in the app or conversation ' + response.conversationId + '.');
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const readMessages = async () => {
|
|
90
|
+
const messages = await data_provider_1.dataService.getMessagesByConvoId(response.conversationId);
|
|
91
|
+
return Array.isArray(messages) ? messages : [];
|
|
92
|
+
};
|
|
93
|
+
let detach;
|
|
94
|
+
const detached = new Promise((resolve) => { detach = () => resolve('detached'); });
|
|
95
|
+
let disconnectTimer;
|
|
96
|
+
const client = new agentic_stream_1.AgenticStreamClient({
|
|
97
|
+
baseURL: this.cliConfig.baseURL,
|
|
98
|
+
token: this.resolvedCredential.token,
|
|
99
|
+
workspaceId: process.env.OVERSKY_WORKSPACE_ID,
|
|
100
|
+
sessionId: response.sessionId,
|
|
101
|
+
conversationId: response.conversationId,
|
|
102
|
+
approveTools: Boolean(process.stdin.isTTY || flags['approve-tools']),
|
|
103
|
+
onEvent: (event) => {
|
|
104
|
+
if (event.type === 'transport.connected' && disconnectTimer) {
|
|
105
|
+
clearTimeout(disconnectTimer);
|
|
106
|
+
disconnectTimer = undefined;
|
|
107
|
+
}
|
|
108
|
+
else if (event.type === 'transport.disconnected' && !disconnectTimer) {
|
|
109
|
+
// An established Socket.IO connection can be disconnected without an
|
|
110
|
+
// automatic retry. Bound the lost view and reconcile its durable row.
|
|
111
|
+
disconnectTimer = setTimeout(detach, 30_000);
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
reconcileTerminal: async () => (0, chat_1.reconcileTerminalFromMessages)(await readMessages(), response.responseMessageId),
|
|
115
|
+
awaitHandover: {
|
|
116
|
+
read: async () => (0, chat_1.handoverStateFromMessages)(await readMessages(), response.responseMessageId),
|
|
117
|
+
responseMessageId: response.responseMessageId,
|
|
118
|
+
conversationId: response.conversationId,
|
|
119
|
+
maxWaitMs: 5 * 60_000,
|
|
120
|
+
},
|
|
121
|
+
replayEnvelopes: (from) => (0, api_fetch_1.apiFetch)(`/api/agentic/sessions/${encodeURIComponent(response.sessionId)}/envelopes?from=${from}&limit=500`, { credential: this.resolvedCredential, signal: AbortSignal.timeout(5000) }),
|
|
122
|
+
});
|
|
123
|
+
let interruptedBy = null;
|
|
124
|
+
let timer;
|
|
125
|
+
const onInterrupt = (signal) => {
|
|
126
|
+
if (interruptedBy) {
|
|
127
|
+
detach();
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
interruptedBy = signal;
|
|
131
|
+
client.cancel();
|
|
132
|
+
if (signal !== 'SIGHUP')
|
|
133
|
+
process.stderr.write(`\nCancellation requested for ${response.sessionId}; waiting up to 10 seconds. The turn may still be running if it does not stop.\n`);
|
|
134
|
+
timer = setTimeout(detach, 10_000);
|
|
135
|
+
};
|
|
136
|
+
const onSigint = () => onInterrupt('SIGINT');
|
|
137
|
+
const onSigterm = () => onInterrupt('SIGTERM');
|
|
138
|
+
const onSighup = () => onInterrupt('SIGHUP');
|
|
139
|
+
process.on('SIGINT', onSigint);
|
|
140
|
+
process.on('SIGTERM', onSigterm);
|
|
141
|
+
process.on('SIGHUP', onSighup);
|
|
142
|
+
try {
|
|
143
|
+
const outcome = await Promise.race([
|
|
144
|
+
client.run().catch((error) => {
|
|
145
|
+
if (error?.code === 'STREAM_ATTACH_TIMEOUT')
|
|
146
|
+
return 'detached';
|
|
147
|
+
throw error;
|
|
148
|
+
}),
|
|
149
|
+
detached,
|
|
150
|
+
]);
|
|
151
|
+
const result = outcome === 'detached' && await client.probeTerminal('detach')
|
|
152
|
+
? client.settledResult() : outcome === 'detached' ? null : outcome;
|
|
153
|
+
if (!result) {
|
|
154
|
+
process.stderr.write(`Detached from ${response.sessionId}; the turn may still be running. Check conversation ${response.conversationId}.\n`);
|
|
155
|
+
process.exitCode = interruptedBy === 'SIGTERM' ? 143 : interruptedBy === 'SIGHUP' ? 129 : interruptedBy ? 130 : 75;
|
|
156
|
+
}
|
|
157
|
+
else if (result.status === 'failed') {
|
|
158
|
+
process.exitCode = 1;
|
|
159
|
+
}
|
|
160
|
+
else if (result.status === 'aborted' && interruptedBy !== 'SIGHUP') {
|
|
161
|
+
this.log(`\nCancellation confirmed for ${response.sessionId}.`);
|
|
162
|
+
}
|
|
163
|
+
if (interruptedBy === 'SIGTERM')
|
|
164
|
+
process.exitCode = 143;
|
|
165
|
+
if (interruptedBy === 'SIGHUP')
|
|
166
|
+
process.exitCode = 129;
|
|
167
|
+
}
|
|
168
|
+
finally {
|
|
169
|
+
if (timer)
|
|
170
|
+
clearTimeout(timer);
|
|
171
|
+
if (disconnectTimer)
|
|
172
|
+
clearTimeout(disconnectTimer);
|
|
173
|
+
process.removeListener('SIGINT', onSigint);
|
|
174
|
+
process.removeListener('SIGTERM', onSigterm);
|
|
175
|
+
process.removeListener('SIGHUP', onSighup);
|
|
176
|
+
client.close();
|
|
177
|
+
}
|
|
66
178
|
}
|
|
67
179
|
}
|
|
68
180
|
exports.default = AgendaPlan;
|
|
@@ -763,6 +763,10 @@ function normalizeIntentPayload({ agentId, jsonBody, merged, }) {
|
|
|
763
763
|
const overlayChannel = optionalString(merged.channelId);
|
|
764
764
|
const overlayThreadTs = optionalString(merged.threadTs);
|
|
765
765
|
const destinationKind = pickDestinationKind({ bodyDestination, overlayKind });
|
|
766
|
+
if (destinationKind !== 'slack_channel' &&
|
|
767
|
+
(merged.channelId !== undefined || bodyDestination?.channelId !== undefined)) {
|
|
768
|
+
throw invalidIntent('--channel / destination.channelId only applies to slack_channel.');
|
|
769
|
+
}
|
|
766
770
|
if (destinationKind !== 'slack_channel' && (overlayThreadTs || bodyDestination?.threadTs)) {
|
|
767
771
|
throw invalidIntent('--thread-ts / destination.threadTs only applies to slack_channel.');
|
|
768
772
|
}
|
|
@@ -13,12 +13,31 @@ class AgentsIntuitionsGenerate extends base_command_1.BaseCommand {
|
|
|
13
13
|
async run() {
|
|
14
14
|
this.requireAuth();
|
|
15
15
|
const { args, flags } = await this.parse(AgentsIntuitionsGenerate);
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
this.
|
|
16
|
+
let result;
|
|
17
|
+
try {
|
|
18
|
+
result = await data_provider_1.dataService.generateAgentIntuitions(args.agentId, flags.force);
|
|
19
|
+
}
|
|
20
|
+
catch (err) {
|
|
21
|
+
this.handleApiError(err);
|
|
22
|
+
}
|
|
23
|
+
if (flags.json) {
|
|
24
|
+
this.log(this.agentJson(args.agentId, result));
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const response = result;
|
|
28
|
+
if (response.outcome === 'insufficient_context') {
|
|
29
|
+
this.log('No intuitions yet: add relevant agent memories or activity, then try again.');
|
|
30
|
+
}
|
|
31
|
+
else if (response.outcome === 'no_suggestions') {
|
|
32
|
+
this.log('No intuitions were suggested from the available context. Try again after more activity.');
|
|
33
|
+
}
|
|
34
|
+
else if (response.intuitions?.length === 0) {
|
|
35
|
+
this.log('No intuitions were returned. Add relevant memories or activity, then try again.');
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
this.log(`Generated intuitions for agent ${args.agentId}`);
|
|
39
|
+
}
|
|
40
|
+
this.printAgentUrl(args.agentId);
|
|
22
41
|
}
|
|
23
42
|
}
|
|
24
43
|
exports.default = AgentsIntuitionsGenerate;
|
|
@@ -16,8 +16,13 @@ class AgentsIntuitionsList extends base_command_1.BaseCommand {
|
|
|
16
16
|
this.printJsonResult((0, list_output_1.listResult)(this.withAgentContext(args.agentId, result), 'intuitions'));
|
|
17
17
|
return;
|
|
18
18
|
}
|
|
19
|
-
const
|
|
20
|
-
|
|
19
|
+
const intuitions = result.intuitions ?? result;
|
|
20
|
+
if (Array.isArray(intuitions) && intuitions.length === 0) {
|
|
21
|
+
this.log(`No active intuitions. Run skrr agents intuitions generate ${args.agentId} to look for suggestions.`);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
this.log(JSON.stringify(intuitions, null, 2));
|
|
25
|
+
}
|
|
21
26
|
this.printAgentUrl(args.agentId);
|
|
22
27
|
}
|
|
23
28
|
}
|
|
@@ -17,6 +17,12 @@ function proactiveInstallReadiness(result, bin) {
|
|
|
17
17
|
if (result.warnings.length === 0) {
|
|
18
18
|
return { status: 'ready', message: 'All requested setup steps completed.' };
|
|
19
19
|
}
|
|
20
|
+
if (result.warnings.some((warning) => warning.code === 'always_on_off')) {
|
|
21
|
+
return {
|
|
22
|
+
status: 'degraded',
|
|
23
|
+
message: 'The Agent is off. Review the setup warnings and enable Always-On explicitly if you want it to run.',
|
|
24
|
+
};
|
|
25
|
+
}
|
|
20
26
|
// A full trigger budget must not make a new persona-only Agent look broken
|
|
21
27
|
// when its core system commitments, local execution policy, and Always-On
|
|
22
28
|
// state installed successfully. The optional backlog watcher is deferred;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { BaseCommand } from '../../../base-command';
|
|
2
|
+
export default class AgentsTodosEdit extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static args: {
|
|
6
|
+
id: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
7
|
+
};
|
|
8
|
+
static flags: {
|
|
9
|
+
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
10
|
+
name: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
at: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
};
|
|
13
|
+
run(): Promise<void>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const base_command_1 = require("../../../base-command");
|
|
5
|
+
const schedule_1 = require("../../../lib/schedule");
|
|
6
|
+
class AgentsTodosEdit extends base_command_1.BaseCommand {
|
|
7
|
+
static description = 'Change the name or time of a pending to-do';
|
|
8
|
+
static examples = [
|
|
9
|
+
'<%= config.bin %> agents todos edit <todo-id> --name "Review launch"',
|
|
10
|
+
'<%= config.bin %> agents todos edit <todo-id> --at 2026-11-05T18:00:00Z',
|
|
11
|
+
];
|
|
12
|
+
static args = { id: core_1.Args.string({ description: 'To-Do ID', required: true, ignoreStdin: true }) };
|
|
13
|
+
static flags = {
|
|
14
|
+
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
15
|
+
name: core_1.Flags.string({ description: 'New name' }),
|
|
16
|
+
at: core_1.Flags.string({ description: 'New ISO-8601 run time' }),
|
|
17
|
+
};
|
|
18
|
+
async run() {
|
|
19
|
+
this.requireAuth();
|
|
20
|
+
const { args, flags } = await this.parse(AgentsTodosEdit);
|
|
21
|
+
if (flags.name === undefined && flags.at === undefined)
|
|
22
|
+
this.error('Supply --name or --at.', { exit: 1 });
|
|
23
|
+
let todo;
|
|
24
|
+
try {
|
|
25
|
+
const current = await schedule_1.scheduleApi.getTodo(args.id);
|
|
26
|
+
if (!current.updatedAt)
|
|
27
|
+
this.error('The to-do has no version; refresh before editing.', { exit: 1 });
|
|
28
|
+
todo = await schedule_1.scheduleApi.updateTodo(args.id, {
|
|
29
|
+
...(flags.name !== undefined ? { name: flags.name } : {}),
|
|
30
|
+
...(flags.at !== undefined ? { runAt: flags.at } : {}),
|
|
31
|
+
expectedUpdatedAt: current.updatedAt,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
this.handleApiError(err);
|
|
36
|
+
}
|
|
37
|
+
if (flags.json)
|
|
38
|
+
this.log(JSON.stringify(todo, null, 2));
|
|
39
|
+
else
|
|
40
|
+
this.log(`Updated to-do ${todo.id} — "${todo.name}" at ${todo.runAt}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
exports.default = AgentsTodosEdit;
|
|
@@ -2,8 +2,7 @@ import { BaseCommand } from '../../../base-command';
|
|
|
2
2
|
/**
|
|
3
3
|
* `skrr agents triggers fire <agent-id> <trigger-id>` — fire a trigger now.
|
|
4
4
|
* Mirrors the Schedule Board's "Run" button (`POST /api/triggers/:id/fire-now`).
|
|
5
|
-
* The
|
|
6
|
-
* concurrency) — the response `outcome` says whether it actually ran.
|
|
5
|
+
* The response distinguishes the manual fire from a scheduled-policy preview.
|
|
7
6
|
*/
|
|
8
7
|
export default class AgentsTriggersFire extends BaseCommand {
|
|
9
8
|
static description: string;
|
|
@@ -15,6 +14,7 @@ export default class AgentsTriggersFire extends BaseCommand {
|
|
|
15
14
|
static flags: {
|
|
16
15
|
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
17
16
|
'from-json': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
17
|
+
strict: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
18
18
|
};
|
|
19
19
|
run(): Promise<void>;
|
|
20
20
|
}
|
|
@@ -7,8 +7,7 @@ const triggers_1 = require("../../../lib/triggers");
|
|
|
7
7
|
/**
|
|
8
8
|
* `skrr agents triggers fire <agent-id> <trigger-id>` — fire a trigger now.
|
|
9
9
|
* Mirrors the Schedule Board's "Run" button (`POST /api/triggers/:id/fire-now`).
|
|
10
|
-
* The
|
|
11
|
-
* concurrency) — the response `outcome` says whether it actually ran.
|
|
10
|
+
* The response distinguishes the manual fire from a scheduled-policy preview.
|
|
12
11
|
*/
|
|
13
12
|
class AgentsTriggersFire extends base_command_1.BaseCommand {
|
|
14
13
|
static description = "Fire one of an agent's triggers immediately";
|
|
@@ -25,6 +24,11 @@ class AgentsTriggersFire extends base_command_1.BaseCommand {
|
|
|
25
24
|
'from-json': core_1.Flags.string({
|
|
26
25
|
description: 'Path to a JSON file (or "-" for stdin) to use as fire options',
|
|
27
26
|
}),
|
|
27
|
+
strict: core_1.Flags.boolean({
|
|
28
|
+
allowNo: true,
|
|
29
|
+
default: true,
|
|
30
|
+
description: 'Exit nonzero if the fire was not accepted; use --no-strict for transport-only success',
|
|
31
|
+
}),
|
|
28
32
|
};
|
|
29
33
|
async run() {
|
|
30
34
|
this.requireAuth();
|
|
@@ -46,13 +50,26 @@ class AgentsTriggersFire extends base_command_1.BaseCommand {
|
|
|
46
50
|
this.error(err.message, { exit: 4 });
|
|
47
51
|
this.handleApiError(err);
|
|
48
52
|
}
|
|
53
|
+
const refused = flags.strict && !(0, triggers_1.fireWasAccepted)(result);
|
|
54
|
+
const refusal = refused ? (0, triggers_1.describeStrictFireRefusal)(result) : null;
|
|
49
55
|
if (flags.json) {
|
|
50
|
-
this.log(JSON.stringify(result, null, 2));
|
|
56
|
+
this.log(JSON.stringify(refused ? { ...result, ok: false, strictRefusal: refusal } : result, null, 2));
|
|
57
|
+
if (refusal) {
|
|
58
|
+
process.stderr.write(`${refusal}\n`);
|
|
59
|
+
this.exit(1);
|
|
60
|
+
}
|
|
51
61
|
return;
|
|
52
62
|
}
|
|
53
63
|
this.log(`Fire requested: outcome=${String(result.outcome ?? '-')} reason=${String(result.reason ?? '-')}`);
|
|
54
64
|
for (const line of (0, triggers_1.describeFireDetail)(result))
|
|
55
65
|
this.log(line);
|
|
66
|
+
const note = (0, triggers_1.describeScheduledFire)(result);
|
|
67
|
+
if (note)
|
|
68
|
+
this.log(note);
|
|
69
|
+
if (refusal) {
|
|
70
|
+
process.stderr.write(`${refusal}\n`);
|
|
71
|
+
this.exit(1);
|
|
72
|
+
}
|
|
56
73
|
}
|
|
57
74
|
}
|
|
58
75
|
exports.default = AgentsTriggersFire;
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import { BaseCommand } from '../../../base-command';
|
|
2
|
+
/**
|
|
3
|
+
* `3` → 3, `0` → 0 (new lookback plans blocked), `default` → null (clears it). The server validates
|
|
4
|
+
* the range again; refusing a bad value here names the flag instead of a schema issue list.
|
|
5
|
+
*/
|
|
6
|
+
export declare function parseLookbackPlansPerDay(raw: string | undefined): number | null | undefined;
|
|
2
7
|
export default class AgentsTriggersPolicy extends BaseCommand {
|
|
3
8
|
static description: string;
|
|
4
9
|
static examples: string[];
|
|
@@ -16,6 +21,7 @@ export default class AgentsTriggersPolicy extends BaseCommand {
|
|
|
16
21
|
'working-hours': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
17
22
|
'quiet-hours': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
18
23
|
'followup-budget': import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
24
|
+
'lookback-plans-per-day': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
19
25
|
};
|
|
20
26
|
run(): Promise<void>;
|
|
21
27
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseLookbackPlansPerDay = parseLookbackPlansPerDay;
|
|
3
4
|
const core_1 = require("@oclif/core");
|
|
4
5
|
const base_command_1 = require("../../../base-command");
|
|
5
6
|
const prompt_1 = require("../../../lib/prompt");
|
|
@@ -30,6 +31,21 @@ function parseFollowUpBudget(values) {
|
|
|
30
31
|
}
|
|
31
32
|
return budget;
|
|
32
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* `3` → 3, `0` → 0 (new lookback plans blocked), `default` → null (clears it). The server validates
|
|
36
|
+
* the range again; refusing a bad value here names the flag instead of a schema issue list.
|
|
37
|
+
*/
|
|
38
|
+
function parseLookbackPlansPerDay(raw) {
|
|
39
|
+
if (raw === undefined)
|
|
40
|
+
return undefined;
|
|
41
|
+
if (raw === 'default')
|
|
42
|
+
return null;
|
|
43
|
+
const count = Number(raw);
|
|
44
|
+
if (raw.trim() === '' || !Number.isInteger(count) || count < 0 || count > 1000) {
|
|
45
|
+
throw new Error('--lookback-plans-per-day must be an integer from 0 to 1000, or "default"');
|
|
46
|
+
}
|
|
47
|
+
return count;
|
|
48
|
+
}
|
|
33
49
|
class AgentsTriggersPolicy extends base_command_1.BaseCommand {
|
|
34
50
|
static description = "Show or update an agent's initiative policy for agent-scoped triggers";
|
|
35
51
|
static examples = [
|
|
@@ -66,6 +82,9 @@ class AgentsTriggersPolicy extends base_command_1.BaseCommand {
|
|
|
66
82
|
description: 'Daily follow-up creation cap for this agent, as pool=count (pools: watch, checkin, act; count "default" clears it). Repeatable',
|
|
67
83
|
multiple: true,
|
|
68
84
|
}),
|
|
85
|
+
'lookback-plans-per-day': core_1.Flags.string({
|
|
86
|
+
description: 'Daily lookback plan allowance for this agent: an integer from 0 to 1000 (0 blocks new plans) or "default" to clear it. `followups plans capacity --agent <id>` reads what applies today',
|
|
87
|
+
}),
|
|
69
88
|
};
|
|
70
89
|
async run() {
|
|
71
90
|
this.requireAuth();
|
|
@@ -81,6 +100,7 @@ class AgentsTriggersPolicy extends base_command_1.BaseCommand {
|
|
|
81
100
|
workingHours: (0, triggers_1.parseJsonObject)(flags['working-hours'], '--working-hours'),
|
|
82
101
|
quietHours: (0, triggers_1.parseJsonObject)(flags['quiet-hours'], '--quiet-hours'),
|
|
83
102
|
followUpBudget: parseFollowUpBudget(flags['followup-budget']),
|
|
103
|
+
lookbackPlansPerDay: parseLookbackPlansPerDay(flags['lookback-plans-per-day']),
|
|
84
104
|
});
|
|
85
105
|
}
|
|
86
106
|
catch (err) {
|
|
@@ -111,6 +131,8 @@ class AgentsTriggersPolicy extends base_command_1.BaseCommand {
|
|
|
111
131
|
this.log(`Follow-up caps: ${budgetEntries.length > 0
|
|
112
132
|
? budgetEntries.map(([pool, cap]) => `${pool} ${String(cap)}/day`).join(', ')
|
|
113
133
|
: 'defaults'}`);
|
|
134
|
+
const lookbackPlans = policy.lookbackPlansPerDay;
|
|
135
|
+
this.log(`Lookback plans: ${typeof lookbackPlans === 'number' ? `${lookbackPlans}/day` : 'default'}`);
|
|
114
136
|
if (Object.keys(counts).length > 0) {
|
|
115
137
|
this.log(`Triggers: ${String(counts.total ?? 0)} total, ${String(counts.enabled ?? 0)} enabled`);
|
|
116
138
|
}
|
|
@@ -28,8 +28,7 @@ class GoalsBriefingEnable extends base_command_1.BaseCommand {
|
|
|
28
28
|
this.log(JSON.stringify(result, null, 2));
|
|
29
29
|
return;
|
|
30
30
|
}
|
|
31
|
-
|
|
32
|
-
this.log(`Morning briefing enabled (cron: ${cron})`);
|
|
31
|
+
this.log(`Morning briefing enabled (cron: ${result.cron})`);
|
|
33
32
|
}
|
|
34
33
|
}
|
|
35
34
|
exports.default = GoalsBriefingEnable;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
5
|
+
const base_command_1 = require("../../../base-command");
|
|
6
|
+
class GoalsBriefingStatus extends base_command_1.BaseCommand {
|
|
7
|
+
static description = 'Show the morning briefing schedule and delivery preference';
|
|
8
|
+
static flags = { json: core_1.Flags.boolean({ description: 'Output as JSON' }) };
|
|
9
|
+
async run() {
|
|
10
|
+
this.requireAuth();
|
|
11
|
+
const { flags } = await this.parse(GoalsBriefingStatus);
|
|
12
|
+
let status;
|
|
13
|
+
try {
|
|
14
|
+
status = await data_provider_1.dataService.getGoalBriefingStatus();
|
|
15
|
+
}
|
|
16
|
+
catch (err) {
|
|
17
|
+
this.handleApiError(err);
|
|
18
|
+
}
|
|
19
|
+
if (flags.json) {
|
|
20
|
+
this.log(JSON.stringify(status, null, 2));
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
this.log(`Morning briefing: ${status.enabled ? 'enabled' : 'disabled'}`);
|
|
24
|
+
if (status.cron)
|
|
25
|
+
this.log(`Schedule: ${status.cron} (${status.timezone || 'timezone unknown'})`);
|
|
26
|
+
if (status.nextRunAt)
|
|
27
|
+
this.log(`Next run: ${status.nextRunAt}`);
|
|
28
|
+
this.log(`Delivery preference: ${status.delivery.categoryLevel}`);
|
|
29
|
+
if (status.delivery.preferenceEligibleChannels.length) {
|
|
30
|
+
this.log(`Preference-eligible channels: ${status.delivery.preferenceEligibleChannels.join(', ')}`);
|
|
31
|
+
this.log('Actual delivery also depends on connected destinations and other notification settings.');
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
exports.default = GoalsBriefingStatus;
|
|
@@ -7,7 +7,7 @@ const base_command_1 = require("../../base-command");
|
|
|
7
7
|
const format_1 = require("../../lib/format");
|
|
8
8
|
const memory_scope_1 = require("../../lib/memory-scope");
|
|
9
9
|
class MemoryList extends base_command_1.BaseCommand {
|
|
10
|
-
static description = 'List memories
|
|
10
|
+
static description = 'List compatibility-pool memories (canonical topics are listed separately)';
|
|
11
11
|
static examples = [
|
|
12
12
|
'<%= config.bin %> memory list',
|
|
13
13
|
'<%= config.bin %> memory list --json',
|
|
@@ -30,15 +30,21 @@ class MemoryList extends base_command_1.BaseCommand {
|
|
|
30
30
|
catch (err) {
|
|
31
31
|
this.handleApiError(err);
|
|
32
32
|
}
|
|
33
|
+
const canonicalHint = flags.agent
|
|
34
|
+
? 'Canonical Agent Memory topics are separate. Run skrr memory topics list with the same --agent and --scope agent:<agent-id>.'
|
|
35
|
+
: 'This is a compatibility pool. Canonical Memory topics are listed separately with skrr memory topics list.';
|
|
33
36
|
if (flags.json) {
|
|
34
|
-
this.printJsonResult((0, list_output_1.listResult)(response, 'memories'));
|
|
37
|
+
this.printJsonResult((0, list_output_1.listResult)({ ...response, memorySource: 'compatibility_pool', canonicalTopicsHint: canonicalHint }, 'memories'));
|
|
35
38
|
return;
|
|
36
39
|
}
|
|
37
40
|
const memories = response.memories ?? [];
|
|
38
41
|
if (memories.length === 0) {
|
|
39
|
-
this.log('No memories.');
|
|
42
|
+
this.log('No compatibility-pool memories.');
|
|
43
|
+
this.log(canonicalHint);
|
|
40
44
|
return;
|
|
41
45
|
}
|
|
46
|
+
this.log('Compatibility-pool memories:');
|
|
47
|
+
this.log(canonicalHint);
|
|
42
48
|
const rows = memories.map((m) => ({
|
|
43
49
|
key: m.key,
|
|
44
50
|
value: m.value,
|
package/dist/lib/schedule.d.ts
CHANGED
|
@@ -19,6 +19,7 @@ export interface Todo {
|
|
|
19
19
|
rationale?: string;
|
|
20
20
|
confidence?: TodoConfidence;
|
|
21
21
|
triggerId?: string;
|
|
22
|
+
updatedAt?: string;
|
|
22
23
|
firedAt?: string;
|
|
23
24
|
result?: {
|
|
24
25
|
conversationId?: string;
|
|
@@ -179,6 +180,11 @@ export declare const scheduleApi: {
|
|
|
179
180
|
listTodos: (agentId: string, date?: string, timezone?: string) => Promise<ListTodosResponse>;
|
|
180
181
|
getTodo: (todoId: string) => Promise<Todo>;
|
|
181
182
|
createTodo: (input: CreateTodoInput) => Promise<Todo>;
|
|
183
|
+
updateTodo: (todoId: string, patch: {
|
|
184
|
+
name?: string;
|
|
185
|
+
runAt?: string;
|
|
186
|
+
expectedUpdatedAt?: string;
|
|
187
|
+
}) => Promise<Todo>;
|
|
182
188
|
/** Cancel a To-Do (DELETE soft-cancels pending; see todos.js). */
|
|
183
189
|
cancelTodo: (todoId: string) => Promise<Todo>;
|
|
184
190
|
proposeSmartSchedule: (input: {
|
package/dist/lib/schedule.js
CHANGED
|
@@ -61,6 +61,7 @@ exports.scheduleApi = {
|
|
|
61
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
|
+
updateTodo: (todoId, patch) => data_provider_1.request.patch(`/api/todos/${encodeURIComponent(todoId)}`, patch),
|
|
64
65
|
/** Cancel a To-Do (DELETE soft-cancels pending; see todos.js). */
|
|
65
66
|
cancelTodo: (todoId) => data_provider_1.request.delete(`/api/todos/${encodeURIComponent(todoId)}`),
|
|
66
67
|
proposeSmartSchedule: (input) => data_provider_1.request.post('/api/todos/smart-schedule/propose', input),
|
|
@@ -82,6 +82,16 @@ export declare function parseMemoryApiError(error: ApiFetchError): {
|
|
|
82
82
|
retryable: boolean;
|
|
83
83
|
details?: Record<string, unknown>;
|
|
84
84
|
};
|
|
85
|
+
/** A gateway timeout can arrive after the canonical mutation committed. */
|
|
86
|
+
export declare function uncertainMemoryMutationRecovery(path: string, options: ApiFetchOptions, status: number): {
|
|
87
|
+
message: string;
|
|
88
|
+
details: {
|
|
89
|
+
spaceId?: string | undefined;
|
|
90
|
+
outcome: string;
|
|
91
|
+
targetStoreId: string;
|
|
92
|
+
idempotencyKey: string;
|
|
93
|
+
};
|
|
94
|
+
} | null;
|
|
85
95
|
export declare abstract class ScopedMemoryCommand extends BaseCommand {
|
|
86
96
|
protected endpoint(agentId: string, suffix?: string): string;
|
|
87
97
|
protected memoryApi<T>(agentId: string, suffix: string, options?: ApiFetchOptions): Promise<T>;
|