@skrr-ai/cli 0.1.39 → 0.1.41
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/README.md +1 -1
- package/dist/base-command.d.ts +9 -0
- package/dist/base-command.js +26 -3
- package/dist/commands/agent-shares/list-for.js +4 -11
- package/dist/commands/agent-shares/received.js +4 -11
- package/dist/commands/agent-shares/sent.js +4 -11
- package/dist/commands/agent-shares/with.js +3 -10
- package/dist/commands/agents/activity.js +1 -1
- package/dist/commands/agents/api-actions/add.js +6 -0
- package/dist/commands/agents/chat.js +6 -1
- package/dist/commands/agents/create.d.ts +7 -0
- package/dist/commands/agents/create.js +19 -2
- package/dist/commands/agents/manager/ensure.d.ts +18 -0
- package/dist/commands/agents/manager/ensure.js +56 -0
- package/dist/commands/agents/show.js +4 -0
- package/dist/commands/agents/tools/auth.d.ts +6 -0
- package/dist/commands/agents/tools/auth.js +27 -1
- package/dist/commands/agents/tools/index.js +11 -1
- package/dist/commands/agents/triggers/policy.d.ts +1 -0
- package/dist/commands/agents/triggers/policy.js +32 -0
- package/dist/commands/agents/update.js +10 -4
- package/dist/commands/code/install.d.ts +4 -2
- package/dist/commands/code/install.js +12 -10
- package/dist/commands/convos/list.js +1 -3
- package/dist/commands/convos/show.js +4 -11
- package/dist/commands/daemon/index.js +3 -3
- package/dist/commands/daemon/install.js +4 -4
- package/dist/commands/daemon/login.js +1 -1
- package/dist/commands/daemon/logs.d.ts +3 -1
- package/dist/commands/daemon/logs.js +16 -1
- package/dist/commands/daemon/start.js +3 -3
- package/dist/commands/daemon/status.d.ts +9 -0
- package/dist/commands/daemon/status.js +22 -0
- package/dist/commands/dm/messages.js +1 -11
- package/dist/commands/followups/cancel.js +1 -1
- package/dist/commands/followups/observability.js +6 -2
- package/dist/commands/followups/remind.js +5 -2
- package/dist/commands/followups/reschedule.js +2 -1
- package/dist/commands/followups/resolve.js +1 -1
- package/dist/commands/followups/show.js +20 -0
- package/dist/commands/followups/watch.d.ts +1 -0
- package/dist/commands/followups/watch.js +9 -3
- package/dist/commands/harnesses/forget.js +20 -3
- package/dist/commands/harnesses/install.js +18 -6
- package/dist/commands/harnesses/installers.d.ts +1 -1
- package/dist/commands/harnesses/installers.js +36 -12
- package/dist/commands/harnesses/list.d.ts +74 -2
- package/dist/commands/harnesses/list.js +231 -15
- package/dist/commands/harnesses/ping.d.ts +2 -0
- package/dist/commands/harnesses/ping.js +21 -0
- package/dist/commands/harnesses/show.d.ts +22 -0
- package/dist/commands/harnesses/show.js +116 -17
- package/dist/commands/harnesses/update.d.ts +8 -0
- package/dist/commands/harnesses/update.js +25 -1
- package/dist/commands/harnesses/usage.d.ts +2 -0
- package/dist/commands/harnesses/usage.js +7 -2
- package/dist/commands/instructions/status.js +13 -0
- package/dist/commands/instructions/update-target.d.ts +1 -0
- package/dist/commands/instructions/update-target.js +11 -3
- package/dist/commands/login.js +5 -5
- package/dist/commands/machines/list.js +8 -9
- package/dist/commands/machines/show.js +46 -17
- package/dist/commands/messages/show.js +3 -10
- package/dist/commands/shares/get.js +2 -9
- package/dist/commands/shares/list.js +1 -9
- package/dist/commands/shortcuts/show.js +4 -11
- package/dist/commands/skills/local.js +6 -0
- package/dist/commands/spaces/actions/run.js +3 -4
- package/dist/commands/spaces/briefs/get.js +2 -9
- package/dist/commands/spaces/briefs/list.js +1 -9
- package/dist/commands/spaces/conversations.js +1 -9
- package/dist/commands/spaces/heartbeats/list.js +1 -9
- package/dist/commands/spaces/heartbeats/status.js +2 -9
- package/dist/commands/tasks/activity.js +1 -10
- package/dist/commands/tasks/approvals/list.js +1 -9
- package/dist/commands/tasks/attachments/list.js +1 -9
- package/dist/commands/tasks/comments/list.js +1 -9
- package/dist/commands/tasks/dri-status.js +2 -9
- package/dist/commands/tasks/events/append.js +9 -7
- package/dist/commands/tasks/execution-timeline.js +1 -9
- package/dist/commands/tasks/lifecycle/detach.js +26 -5
- package/dist/commands/tasks/monitor.js +1 -9
- package/dist/commands/tasks/result/submit.js +9 -0
- package/dist/commands/tasks/runs.js +1 -9
- package/dist/commands/tasks/show.js +5 -12
- package/dist/commands/token/list.d.ts +8 -0
- package/dist/commands/token/list.js +51 -6
- package/dist/help.js +8 -12
- package/dist/lib/agent-home-workspace.d.ts +19 -0
- package/dist/lib/agent-home-workspace.js +39 -0
- package/dist/lib/agent-resolver.js +2 -2
- package/dist/lib/agentic-stream.d.ts +22 -1
- package/dist/lib/agentic-stream.js +48 -7
- package/dist/lib/cli-installers.d.ts +84 -2
- package/dist/lib/cli-installers.js +146 -13
- package/dist/lib/command-miss.d.ts +22 -0
- package/dist/lib/command-miss.js +78 -0
- package/dist/lib/daemon-setup.js +2 -2
- package/dist/lib/daemon-target.d.ts +14 -0
- package/dist/lib/daemon-target.js +32 -0
- package/dist/lib/daemonBroker.js +1 -1
- package/dist/lib/daemonHandoff.js +1 -1
- package/dist/lib/dedicated-lease-command.js +4 -1
- package/dist/lib/dedicated-machines.d.ts +8 -1
- package/dist/lib/dedicated-machines.js +22 -6
- package/dist/lib/dedicated-wait.js +13 -0
- package/dist/lib/exec-runtime-binary.js +2 -2
- package/dist/lib/followups.d.ts +18 -0
- package/dist/lib/followups.js +14 -1
- package/dist/lib/format.d.ts +11 -0
- package/dist/lib/format.js +21 -0
- package/dist/lib/harness-labels.d.ts +39 -0
- package/dist/lib/harness-labels.js +60 -0
- package/dist/lib/harnesses.d.ts +6 -0
- package/dist/lib/instruction-input.d.ts +13 -0
- package/dist/lib/instruction-input.js +20 -1
- package/dist/lib/label-ref.d.ts +8 -1
- package/dist/lib/label-ref.js +12 -2
- package/dist/lib/local-skills.d.ts +17 -1
- package/dist/lib/local-skills.js +20 -2
- package/dist/lib/login.js +5 -5
- package/dist/lib/machines.d.ts +6 -0
- package/dist/lib/machines.js +68 -2
- package/dist/lib/option-hint.d.ts +15 -0
- package/dist/lib/option-hint.js +75 -0
- package/dist/lib/runtime-tool-support.d.ts +34 -0
- package/dist/lib/runtime-tool-support.js +77 -0
- package/dist/lib/share-rows.d.ts +17 -0
- package/dist/lib/share-rows.js +35 -0
- package/dist/lib/workspaces.d.ts +3 -0
- package/dist/lib/workspaces.js +38 -0
- package/dist/node_modules/@skrr-ai/data-provider/index.js +5029 -5007
- package/oclif.manifest.json +34255 -34142
- package/package.json +10 -5
|
@@ -4,6 +4,7 @@ const core_1 = require("@oclif/core");
|
|
|
4
4
|
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
5
5
|
const agent_visual_refs_1 = require("../../lib/agent-visual-refs");
|
|
6
6
|
const create_1 = require("./create");
|
|
7
|
+
const runtime_tool_support_1 = require("../../lib/runtime-tool-support");
|
|
7
8
|
const base_command_1 = require("../../base-command");
|
|
8
9
|
const execution_target_1 = require("../../lib/execution-target");
|
|
9
10
|
const prompt_1 = require("../../lib/prompt");
|
|
@@ -51,7 +52,10 @@ class AgentsUpdate extends base_command_1.BaseCommand {
|
|
|
51
52
|
description: 'Default Claude permission mode for sessions',
|
|
52
53
|
options: ['default', 'acceptEdits', 'bypassPermissions', 'plan'],
|
|
53
54
|
}),
|
|
54
|
-
tools: core_1.Flags.string({
|
|
55
|
+
tools: core_1.Flags.string({
|
|
56
|
+
description: 'Tools JSON array of plugin keys, e.g. \'["calculator"]\'. `skrr agents tools` lists the keys, ' +
|
|
57
|
+
'and which of them an agent turn can call.',
|
|
58
|
+
}),
|
|
55
59
|
'model-parameters': core_1.Flags.string({ description: 'Model parameters JSON object' }),
|
|
56
60
|
'agent-ids': core_1.Flags.string({ description: 'Delegated agent IDs JSON array' }),
|
|
57
61
|
'network-mode': core_1.Flags.string({ description: 'Agent network mode' }),
|
|
@@ -186,14 +190,16 @@ class AgentsUpdate extends base_command_1.BaseCommand {
|
|
|
186
190
|
this.handleApiError(err);
|
|
187
191
|
}
|
|
188
192
|
// The same check `agents create` makes. Without it, a key the server does
|
|
189
|
-
// not model
|
|
190
|
-
// was discarded with the same "Updated agent"
|
|
193
|
+
// not model, a typo of one that it does (`max_turns` for `maxTurns`), or a
|
|
194
|
+
// field only the server sets was discarded with the same "Updated agent"
|
|
195
|
+
// line as a real change.
|
|
191
196
|
// `removeProjectIds` is an instruction, not a stored field, so it never
|
|
192
197
|
// comes back and is not reported.
|
|
193
198
|
const unapplied = (0, create_1.unappliedPayloadKeys)(payload, updated, ['removeProjectIds']);
|
|
194
199
|
if (unapplied.length > 0) {
|
|
195
|
-
this.warn(
|
|
200
|
+
this.warn((0, create_1.unappliedPayloadKeysWarning)(unapplied));
|
|
196
201
|
}
|
|
202
|
+
await (0, runtime_tool_support_1.warnPluginsNotLoaded)(payload.tools, (message) => this.warn(message));
|
|
197
203
|
if (flags.json) {
|
|
198
204
|
this.log(JSON.stringify((0, web_url_1.withAgentUrl)(this.cliConfig.baseURL, updated), null, 2));
|
|
199
205
|
return;
|
|
@@ -38,8 +38,10 @@ export default class CodeInstall extends BaseCommand {
|
|
|
38
38
|
*
|
|
39
39
|
* Refuses rather than guessing when several are active. Picking one would mean
|
|
40
40
|
* installing a hundred megabytes onto a machine the user was not thinking
|
|
41
|
-
* about
|
|
42
|
-
* so the error
|
|
41
|
+
* about. The candidates are CONNECTED daemons by the id the installer routes
|
|
42
|
+
* take (`listConnectedDaemons`), so the error names values that work — the
|
|
43
|
+
* Daemon resource list `skrr list-daemons` prints is a different id space
|
|
44
|
+
* (OSK-9993).
|
|
43
45
|
*
|
|
44
46
|
* A Dedicated Runtime's own machine is refused here, before any request. The
|
|
45
47
|
* daemon and the API refuse it too; saying so locally is what keeps the answer
|
|
@@ -34,7 +34,7 @@ class CodeInstall extends base_command_1.BaseCommand {
|
|
|
34
34
|
static description = `Install the ${auth_core_1.FIRST_PARTY_HARNESS.displayName} engine on this machine, through the daemon`;
|
|
35
35
|
static examples = [
|
|
36
36
|
'<%= config.bin %> code install',
|
|
37
|
-
'<%= config.bin %> code install --daemon
|
|
37
|
+
'<%= config.bin %> code install --daemon <daemon-id>',
|
|
38
38
|
'<%= config.bin %> code install --json',
|
|
39
39
|
];
|
|
40
40
|
static flags = {
|
|
@@ -90,7 +90,7 @@ class CodeInstall extends base_command_1.BaseCommand {
|
|
|
90
90
|
this.failWithCliError({
|
|
91
91
|
message: `The daemon on ${(0, daemon_ref_1.formatDaemonRef)(daemonId)} accepted the request and returned no ` +
|
|
92
92
|
'install job, and does not say why. Nothing has been shown to start. ' +
|
|
93
|
-
`Check what it offers with \`${this.config.bin}
|
|
93
|
+
`Check what it offers with \`${this.config.bin} harnesses installers --daemon ${daemonId}\`, and ` +
|
|
94
94
|
`\`${this.config.bin} code doctor\` here once you expect it to have landed.`,
|
|
95
95
|
code: 'INSTALL_NOT_TRACKED',
|
|
96
96
|
exit: 1,
|
|
@@ -132,7 +132,7 @@ class CodeInstall extends base_command_1.BaseCommand {
|
|
|
132
132
|
return await (0, daemon_target_1.resolveDaemonTarget)({
|
|
133
133
|
explicit,
|
|
134
134
|
local: (0, daemon_target_1.localMachine)({ baseURL: this.cliConfig?.baseURL }),
|
|
135
|
-
listActiveDaemons: () => (0, daemon_target_1.
|
|
135
|
+
listActiveDaemons: () => (0, daemon_target_1.listConnectedDaemons)(this.resolvedCredential),
|
|
136
136
|
});
|
|
137
137
|
}
|
|
138
138
|
catch (err) {
|
|
@@ -144,8 +144,10 @@ class CodeInstall extends base_command_1.BaseCommand {
|
|
|
144
144
|
*
|
|
145
145
|
* Refuses rather than guessing when several are active. Picking one would mean
|
|
146
146
|
* installing a hundred megabytes onto a machine the user was not thinking
|
|
147
|
-
* about
|
|
148
|
-
* so the error
|
|
147
|
+
* about. The candidates are CONNECTED daemons by the id the installer routes
|
|
148
|
+
* take (`listConnectedDaemons`), so the error names values that work — the
|
|
149
|
+
* Daemon resource list `skrr list-daemons` prints is a different id space
|
|
150
|
+
* (OSK-9993).
|
|
149
151
|
*
|
|
150
152
|
* A Dedicated Runtime's own machine is refused here, before any request. The
|
|
151
153
|
* daemon and the API refuse it too; saying so locally is what keeps the answer
|
|
@@ -169,8 +171,8 @@ class CodeInstall extends base_command_1.BaseCommand {
|
|
|
169
171
|
}
|
|
170
172
|
if (target.kind === 'none') {
|
|
171
173
|
this.failWithCliError({
|
|
172
|
-
message: 'No
|
|
173
|
-
`Start the
|
|
174
|
+
message: 'No daemon is connected for this account, so nothing can perform the install. ' +
|
|
175
|
+
`Start the background service on this computer with \`${this.config.bin} daemon start\`, then run this again.`,
|
|
174
176
|
code: 'NO_DAEMON',
|
|
175
177
|
exit: 1,
|
|
176
178
|
retryable: false,
|
|
@@ -179,11 +181,11 @@ class CodeInstall extends base_command_1.BaseCommand {
|
|
|
179
181
|
const { daemons } = target;
|
|
180
182
|
const choices = daemons
|
|
181
183
|
.slice(0, 10)
|
|
182
|
-
.map((d) => ` ${
|
|
184
|
+
.map((d) => ` ${d.id} ${d.name || '—'}`)
|
|
183
185
|
.join('\n');
|
|
184
186
|
this.failWithCliError({
|
|
185
|
-
message: `${daemons.length}
|
|
186
|
-
`Pass one with --daemon, or see
|
|
187
|
+
message: `${daemons.length} connected daemons — say which machine should install the engine:\n${choices}\n` +
|
|
188
|
+
`Pass one with --daemon, or see each daemon id in the DAEMON ID column of \`${this.config.bin} harnesses list\`.`,
|
|
187
189
|
code: 'AMBIGUOUS_DAEMON',
|
|
188
190
|
exit: 1,
|
|
189
191
|
retryable: false,
|
|
@@ -110,9 +110,7 @@ class ConvosList extends base_command_1.BaseCommand {
|
|
|
110
110
|
// The owning agent is the field callers most often had to reach for --json
|
|
111
111
|
// to see (and the one `--agent` filters on), so surface it in the table too.
|
|
112
112
|
agent: String(c.agent_id ?? c.agentId ?? '-'),
|
|
113
|
-
updated: c.updatedAt
|
|
114
|
-
? new Date(String(c.updatedAt)).toISOString().slice(0, 19).replace('T', ' ')
|
|
115
|
-
: '-',
|
|
113
|
+
updated: (0, format_1.localTime)(c.updatedAt),
|
|
116
114
|
}));
|
|
117
115
|
(0, format_1.renderTable)(rows, [
|
|
118
116
|
{ key: 'id', header: 'ID' },
|
|
@@ -5,6 +5,7 @@ const core_1 = require("@oclif/core");
|
|
|
5
5
|
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
6
6
|
const base_command_1 = require("../../base-command");
|
|
7
7
|
const web_url_1 = require("../../lib/web-url");
|
|
8
|
+
const format_1 = require("../../lib/format");
|
|
8
9
|
class ConvosShow extends base_command_1.BaseCommand {
|
|
9
10
|
static description = 'Show details for a single conversation';
|
|
10
11
|
static examples = [
|
|
@@ -38,10 +39,10 @@ class ConvosShow extends base_command_1.BaseCommand {
|
|
|
38
39
|
this.log(`Model: ${c.model ?? '-'}`);
|
|
39
40
|
this.log(`User: ${c.user ?? '-'}`);
|
|
40
41
|
if (c.createdAt) {
|
|
41
|
-
this.log(`Created: ${
|
|
42
|
+
this.log(`Created: ${(0, format_1.localTime)(c.createdAt)}`);
|
|
42
43
|
}
|
|
43
44
|
if (c.updatedAt) {
|
|
44
|
-
this.log(`Updated: ${
|
|
45
|
+
this.log(`Updated: ${(0, format_1.localTime)(c.updatedAt)}`);
|
|
45
46
|
}
|
|
46
47
|
if (c.agent_id || c.agentId) {
|
|
47
48
|
this.log(`Agent: ${typeof c.agentName === 'string' && c.agentName ? `${c.agentName} (${c.agent_id ?? c.agentId})` : (c.agent_id ?? c.agentId)}`);
|
|
@@ -102,17 +103,9 @@ function formatHandoverParty(entry, baseURL) {
|
|
|
102
103
|
if (entry.by)
|
|
103
104
|
lines.push(` By: ${entry.by}`);
|
|
104
105
|
if (entry.at)
|
|
105
|
-
lines.push(` At: ${
|
|
106
|
+
lines.push(` At: ${(0, format_1.localTime)(entry.at)}`);
|
|
106
107
|
// The reason last, because it is the sentence rather than a field.
|
|
107
108
|
if (entry.reason)
|
|
108
109
|
lines.push(` Reason: ${entry.reason}`);
|
|
109
110
|
return lines;
|
|
110
111
|
}
|
|
111
|
-
function formatTime(value) {
|
|
112
|
-
try {
|
|
113
|
-
return new Date(String(value)).toISOString().slice(0, 19).replace('T', ' ');
|
|
114
|
-
}
|
|
115
|
-
catch {
|
|
116
|
-
return String(value);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
@@ -37,10 +37,10 @@ class Daemon extends core_1.Command {
|
|
|
37
37
|
this.log((0, exec_runtime_binary_1.notInstalledMessage)());
|
|
38
38
|
this.exit(127);
|
|
39
39
|
}
|
|
40
|
-
this.log(`
|
|
40
|
+
this.log(`background service binary: ${bin}`);
|
|
41
41
|
this.log('');
|
|
42
|
-
this.log('
|
|
43
|
-
this.log(' skrr daemon install — install
|
|
42
|
+
this.log('Background service on this computer:');
|
|
43
|
+
this.log(' skrr daemon install — install it as a background service');
|
|
44
44
|
this.log(' skrr daemon uninstall — remove that service (local state is left alone)');
|
|
45
45
|
this.log(' skrr daemon start — start the daemon');
|
|
46
46
|
this.log(' skrr daemon stop — stop the daemon');
|
|
@@ -35,7 +35,7 @@ class DaemonInstall extends core_1.Command {
|
|
|
35
35
|
// whole topic, and without a per-command alias only the bare topic
|
|
36
36
|
// resolved: every subcommand under it failed.
|
|
37
37
|
static aliases = ['daemons:install'];
|
|
38
|
-
static summary = 'Install the
|
|
38
|
+
static summary = 'Install the skrr background service on this computer';
|
|
39
39
|
static description = (0, exec_runtime_binary_1.forwardedFlagsNote)('install', {
|
|
40
40
|
binds: true,
|
|
41
41
|
bootstrapsRuntime: true,
|
|
@@ -57,11 +57,11 @@ class DaemonInstall extends core_1.Command {
|
|
|
57
57
|
// is a floor under the missing case, not a second update channel competing
|
|
58
58
|
// with the daemon's own.
|
|
59
59
|
if (!(0, exec_runtime_binary_1.isCurrentRuntimeBinary)((0, exec_runtime_binary_1.findRuntimeBinary)())) {
|
|
60
|
-
this.log('No
|
|
60
|
+
this.log('No skrr background service installed on this computer. Fetching the signed release...');
|
|
61
61
|
const outcome = await (0, daemon_installer_1.installDaemon)();
|
|
62
62
|
if (!outcome.ok) {
|
|
63
63
|
this.log('');
|
|
64
|
-
this.log(` Could not install the
|
|
64
|
+
this.log(` Could not install the background service: ${outcome.error}`);
|
|
65
65
|
this.log('');
|
|
66
66
|
this.log(' You can install it directly instead:');
|
|
67
67
|
this.log(' macOS: brew install dush1023/oversky/oversky');
|
|
@@ -84,7 +84,7 @@ class DaemonInstall extends core_1.Command {
|
|
|
84
84
|
// Reachable only if the runtime vanished between the bootstrap above
|
|
85
85
|
// and this line. Saying so beats repeating install instructions for
|
|
86
86
|
// something that was just installed.
|
|
87
|
-
this.log('The skrr
|
|
87
|
+
this.log('The skrr background service disappeared between installing it and running it.');
|
|
88
88
|
this.exit(127);
|
|
89
89
|
}
|
|
90
90
|
throw err;
|
|
@@ -28,7 +28,7 @@ const exec_runtime_binary_1 = require("../../lib/exec-runtime-binary");
|
|
|
28
28
|
*/
|
|
29
29
|
class DaemonLogin extends core_1.Command {
|
|
30
30
|
static aliases = ['daemons:login'];
|
|
31
|
-
static summary = 'Authenticate the
|
|
31
|
+
static summary = 'Authenticate the skrr background service on this computer (separate from `skrr login`)';
|
|
32
32
|
static description = (0, exec_runtime_binary_1.forwardedFlagsNote)('login', { binds: true });
|
|
33
33
|
static strict = false; // forward all args verbatim — see run()
|
|
34
34
|
async run() {
|
|
@@ -17,6 +17,7 @@ export interface DaemonLogsFlags {
|
|
|
17
17
|
lines?: number;
|
|
18
18
|
stderr?: boolean;
|
|
19
19
|
path?: boolean;
|
|
20
|
+
profile?: string;
|
|
20
21
|
}
|
|
21
22
|
/**
|
|
22
23
|
* Older daemons already kept logs in this profile-scoped location, even
|
|
@@ -50,7 +51,7 @@ export declare function describeLogAge(mtimeMs: number, now?: number): {
|
|
|
50
51
|
line: string;
|
|
51
52
|
stale: boolean;
|
|
52
53
|
};
|
|
53
|
-
export declare function resolveLegacyDaemonLogPath(flags: Pick<DaemonLogsFlags, 'stderr'>, options?: {
|
|
54
|
+
export declare function resolveLegacyDaemonLogPath(flags: Pick<DaemonLogsFlags, 'stderr' | 'profile'>, options?: {
|
|
54
55
|
home?: string;
|
|
55
56
|
env?: NodeJS.ProcessEnv;
|
|
56
57
|
}): string;
|
|
@@ -81,6 +82,7 @@ export default class DaemonLogs extends Command {
|
|
|
81
82
|
lines: import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
82
83
|
stderr: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
83
84
|
path: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
85
|
+
profile: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
84
86
|
};
|
|
85
87
|
static examples: string[];
|
|
86
88
|
run(): Promise<void>;
|
|
@@ -64,8 +64,14 @@ function describeLogAge(mtimeMs, now = Date.now()) {
|
|
|
64
64
|
function resolveLegacyDaemonLogPath(flags, options = {}) {
|
|
65
65
|
const home = options.home ?? (0, node_os_1.homedir)();
|
|
66
66
|
const env = options.env ?? process.env;
|
|
67
|
+
// An explicit --profile outranks the environment, as it does everywhere else.
|
|
68
|
+
const fromFlag = flags.profile?.trim();
|
|
67
69
|
const fromEnv = env.OVERSKY_PROFILE?.trim();
|
|
68
|
-
let profile =
|
|
70
|
+
let profile = fromFlag && PROFILE_NAME.test(fromFlag)
|
|
71
|
+
? fromFlag
|
|
72
|
+
: fromEnv && PROFILE_NAME.test(fromEnv)
|
|
73
|
+
? fromEnv
|
|
74
|
+
: undefined;
|
|
69
75
|
if (!profile) {
|
|
70
76
|
try {
|
|
71
77
|
const pinned = (0, node_fs_1.readFileSync)(node_path_1.default.join(home, '.skrr', 'profile.lock'), 'utf8').trim();
|
|
@@ -110,6 +116,8 @@ function readDaemonLogTail(filePath, maxLines) {
|
|
|
110
116
|
*/
|
|
111
117
|
function buildOverskyLogsArgs(flags) {
|
|
112
118
|
return [
|
|
119
|
+
// The runtime's own global option, placed before the subcommand.
|
|
120
|
+
...(flags.profile ? ['--profile', flags.profile] : []),
|
|
113
121
|
'logs',
|
|
114
122
|
...(flags.follow ? ['--follow'] : []),
|
|
115
123
|
...(flags.lines !== undefined ? ['--lines', String(flags.lines)] : []),
|
|
@@ -149,6 +157,12 @@ class DaemonLogs extends core_1.Command {
|
|
|
149
157
|
path: core_1.Flags.boolean({
|
|
150
158
|
description: 'Print the resolved log file path and exit',
|
|
151
159
|
}),
|
|
160
|
+
// Every other daemon verb reaches a non-default profile with --profile; this
|
|
161
|
+
// one could only be steered by OVERSKY_PROFILE (OSK-10001).
|
|
162
|
+
profile: core_1.Flags.string({
|
|
163
|
+
char: 'p',
|
|
164
|
+
description: 'Read the logs of this daemon profile instead of the active one',
|
|
165
|
+
}),
|
|
152
166
|
};
|
|
153
167
|
static examples = [
|
|
154
168
|
'<%= config.bin %> daemon logs',
|
|
@@ -156,6 +170,7 @@ class DaemonLogs extends core_1.Command {
|
|
|
156
170
|
'<%= config.bin %> daemon logs --lines 500',
|
|
157
171
|
'<%= config.bin %> daemon logs --stderr',
|
|
158
172
|
'<%= config.bin %> daemon logs --path',
|
|
173
|
+
'<%= config.bin %> daemon logs --profile dogfood-laptop --lines 50',
|
|
159
174
|
];
|
|
160
175
|
async run() {
|
|
161
176
|
const { flags } = await this.parse(DaemonLogs);
|
|
@@ -34,19 +34,19 @@ class DaemonStart extends core_1.Command {
|
|
|
34
34
|
const status = await (0, exec_runtime_binary_1.execRuntimeBinaryCapture)((0, runtime_start_verification_1.statusArgsForStart)(argv));
|
|
35
35
|
const verification = (0, runtime_start_verification_1.verifyRuntimeStart)(status.stdout, status.code, argv);
|
|
36
36
|
if (verification.status === 'reauth_required') {
|
|
37
|
-
this.logToStderr(`
|
|
37
|
+
this.logToStderr(`The background service did not start: profile '${verification.profile}' requires ` +
|
|
38
38
|
`re-authentication (reason: ${verification.reason ?? 'UNKNOWN'}). Run ` +
|
|
39
39
|
`\`${verification.recoveryCommand}\`, then retry \`skrr daemon start\`.`);
|
|
40
40
|
this.exit(runtime_start_verification_1.DAEMON_START_REAUTH_EXIT);
|
|
41
41
|
}
|
|
42
42
|
if (verification.status === 'not_running') {
|
|
43
|
-
this.logToStderr(`
|
|
43
|
+
this.logToStderr(`The background service did not keep running after skrrd exited successfully ` +
|
|
44
44
|
`(profile '${verification.profile}', service status: ` +
|
|
45
45
|
`${verification.runtimeStatus ?? 'unknown'}). Run \`skrr daemon logs\` for the reason.`);
|
|
46
46
|
this.exit(runtime_start_verification_1.DAEMON_START_UNVERIFIED_EXIT);
|
|
47
47
|
}
|
|
48
48
|
if (verification.status === 'unreadable_status') {
|
|
49
|
-
this.logToStderr(`skrrd start exited successfully, but skrr could not verify a running
|
|
49
|
+
this.logToStderr(`skrrd start exited successfully, but skrr could not verify a running background service ` +
|
|
50
50
|
`for profile '${verification.profile}'; refusing to report success. ` +
|
|
51
51
|
'Run `skrr daemon status` and `skrr daemon logs` for the reason.');
|
|
52
52
|
this.exit(runtime_start_verification_1.DAEMON_START_UNVERIFIED_EXIT);
|
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
import { Command } from '@oclif/core';
|
|
2
|
+
/**
|
|
3
|
+
* The status report is the runtime's, and it describes the daemon: running,
|
|
4
|
+
* connected, which credential. Whether the coding-agent CLIs on the machine can
|
|
5
|
+
* actually run a turn — installed, signed in — is a different command, and
|
|
6
|
+
* nothing on this surface named it (OSK-10002). One line after a successful
|
|
7
|
+
* human report; never inside `--json`, whose contract is one document, and
|
|
8
|
+
* never after `--help` or a failure, where it would be noise beside the point.
|
|
9
|
+
*/
|
|
10
|
+
export declare function readinessPointer(argv: readonly string[], exitCode: number): string | null;
|
|
2
11
|
export default class DaemonStatus extends Command {
|
|
3
12
|
static aliases: string[];
|
|
4
13
|
static summary: string;
|
|
@@ -1,7 +1,26 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.readinessPointer = readinessPointer;
|
|
3
4
|
const core_1 = require("@oclif/core");
|
|
4
5
|
const exec_runtime_binary_1 = require("../../lib/exec-runtime-binary");
|
|
6
|
+
/**
|
|
7
|
+
* The status report is the runtime's, and it describes the daemon: running,
|
|
8
|
+
* connected, which credential. Whether the coding-agent CLIs on the machine can
|
|
9
|
+
* actually run a turn — installed, signed in — is a different command, and
|
|
10
|
+
* nothing on this surface named it (OSK-10002). One line after a successful
|
|
11
|
+
* human report; never inside `--json`, whose contract is one document, and
|
|
12
|
+
* never after `--help` or a failure, where it would be noise beside the point.
|
|
13
|
+
*/
|
|
14
|
+
function readinessPointer(argv, exitCode) {
|
|
15
|
+
if (exitCode !== 0)
|
|
16
|
+
return null;
|
|
17
|
+
if (argv.some((arg) => arg === '--json' || arg === '--help' || arg === '-h'))
|
|
18
|
+
return null;
|
|
19
|
+
// Runnable as printed: `installers` picks the only connected daemon itself,
|
|
20
|
+
// and lists the ids to choose from when there are several (OSK-10002 verifier).
|
|
21
|
+
return (' Coding agents: which CLIs are installed on this machine, and signed in where the daemon can tell — ' +
|
|
22
|
+
'`skrr harnesses installers` (add `--daemon <Daemon ID above>` if several daemons are connected)');
|
|
23
|
+
}
|
|
5
24
|
class DaemonStatus extends core_1.Command {
|
|
6
25
|
// `skrr daemons <sub>` — the plural is advertised as an alias for the
|
|
7
26
|
// whole topic, and without a per-command alias only the bare topic
|
|
@@ -23,6 +42,9 @@ class DaemonStatus extends core_1.Command {
|
|
|
23
42
|
const argv = this.argv;
|
|
24
43
|
try {
|
|
25
44
|
const code = await (0, exec_runtime_binary_1.execRuntimeBinary)(['status', ...argv]);
|
|
45
|
+
const pointer = readinessPointer(argv, code);
|
|
46
|
+
if (pointer)
|
|
47
|
+
this.log(pointer);
|
|
26
48
|
this.exit(code);
|
|
27
49
|
}
|
|
28
50
|
catch (err) {
|
|
@@ -87,7 +87,7 @@ class DmMessages extends base_command_1.BaseCommand {
|
|
|
87
87
|
return;
|
|
88
88
|
}
|
|
89
89
|
(0, format_1.renderTable)(selected.map((message) => ({
|
|
90
|
-
when:
|
|
90
|
+
when: (0, format_1.localTime)(message.createdAt),
|
|
91
91
|
role: String(message.sender ?? (message.isCreatedByUser ? 'user' : 'assistant')),
|
|
92
92
|
text: textFromMessage(message).replace(/\s+/g, ' ').trim(),
|
|
93
93
|
id: String(message.messageId ?? message._id ?? message.id ?? '-'),
|
|
@@ -100,16 +100,6 @@ class DmMessages extends base_command_1.BaseCommand {
|
|
|
100
100
|
}
|
|
101
101
|
}
|
|
102
102
|
exports.default = DmMessages;
|
|
103
|
-
function formatTime(value) {
|
|
104
|
-
if (!value)
|
|
105
|
-
return '-';
|
|
106
|
-
try {
|
|
107
|
-
return new Date(String(value)).toISOString().slice(0, 19);
|
|
108
|
-
}
|
|
109
|
-
catch {
|
|
110
|
-
return String(value);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
103
|
function textFromMessage(message) {
|
|
114
104
|
if (typeof message.text === 'string')
|
|
115
105
|
return message.text;
|
|
@@ -44,7 +44,7 @@ class FollowupsCancel extends base_command_1.BaseCommand {
|
|
|
44
44
|
this.log(JSON.stringify(result, null, 2));
|
|
45
45
|
return;
|
|
46
46
|
}
|
|
47
|
-
this.log(
|
|
47
|
+
this.log((0, followups_1.settledLine)(args.id, result, 'cancelled'));
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
exports.default = FollowupsCancel;
|
|
@@ -24,7 +24,7 @@ const outcomes = (terminal) => Object.entries(terminal)
|
|
|
24
24
|
* every agent only with `--all-agents`.
|
|
25
25
|
*/
|
|
26
26
|
class FollowupsObservability extends base_command_1.BaseCommand {
|
|
27
|
-
static description = 'Per-agent, per-kind rollup — created, outcomes, escalation, budget, check-in silence';
|
|
27
|
+
static description = 'Per-agent, per-kind rollup — created, outcomes, escalation, spend, budget, check-in silence';
|
|
28
28
|
static examples = [
|
|
29
29
|
'<%= config.bin %> followups observability',
|
|
30
30
|
'<%= config.bin %> followups observability --agent agent_1',
|
|
@@ -93,6 +93,9 @@ class FollowupsObservability extends base_command_1.BaseCommand {
|
|
|
93
93
|
outcomes: outcomes(kind.terminal),
|
|
94
94
|
escalated: rate(kind.escalationRate),
|
|
95
95
|
fires: String(kind.fires),
|
|
96
|
+
spend: kind.spend
|
|
97
|
+
? `$${kind.spend.today.toFixed(2)} / $${kind.spend.total.toFixed(2)}`
|
|
98
|
+
: '—',
|
|
96
99
|
budget: kind.budget ? `${kind.budget.used}/${kind.budget.limit ?? '∞'}` : '—',
|
|
97
100
|
silence: rate(kind.silenceRate),
|
|
98
101
|
})), [
|
|
@@ -104,11 +107,12 @@ class FollowupsObservability extends base_command_1.BaseCommand {
|
|
|
104
107
|
{ key: 'outcomes', header: 'OUTCOMES' },
|
|
105
108
|
{ key: 'escalated', header: 'ESCALATED' },
|
|
106
109
|
{ key: 'fires', header: 'FIRES' },
|
|
110
|
+
{ key: 'spend', header: 'SPENT TODAY/ALL' },
|
|
107
111
|
{ key: 'budget', header: 'TODAY/LIMIT' },
|
|
108
112
|
{ key: 'silence', header: 'SILENT' },
|
|
109
113
|
], (line) => this.log(line));
|
|
110
114
|
});
|
|
111
|
-
this.log(`\nAs of ${report.generatedAt ?? 'now'}. TODAY/LIMIT is the daily budget (reminders are not metered); SILENT is how often a check-in chose to stay quiet.`);
|
|
115
|
+
this.log(`\nAs of ${report.generatedAt ?? 'now'}. SPENT is the agent turns these follow-ups woke (USD, today / all time); TODAY/LIMIT is the daily creation budget (reminders are not metered); SILENT is how often a check-in chose to stay quiet.`);
|
|
112
116
|
}
|
|
113
117
|
}
|
|
114
118
|
exports.default = FollowupsObservability;
|
|
@@ -15,11 +15,14 @@ class FollowupsRemind extends base_command_1.BaseCommand {
|
|
|
15
15
|
static description = 'Remind the owner at a time — the reminder follow-up';
|
|
16
16
|
static examples = [
|
|
17
17
|
'<%= config.bin %> followups remind --subject task:OSK-42 --content "pick the deploy up" --in 2h',
|
|
18
|
-
'<%= config.bin %> followups remind --subject conversation:conv_9 --content "ask how the move went" --at 2026-09-20T09:00:00Z',
|
|
18
|
+
'<%= config.bin %> followups remind --subject conversation:conv_9 --content "ask how the move went" --at 2026-09-20T09:00:00Z --active --agent agent_1',
|
|
19
19
|
'<%= config.bin %> followups remind --subject task:OSK-42 --content "ping me" --at 2026-09-20T09:00:00Z --active --agent agent_1',
|
|
20
20
|
];
|
|
21
21
|
static flags = {
|
|
22
|
-
subject: core_1.Flags.string({
|
|
22
|
+
subject: core_1.Flags.string({
|
|
23
|
+
description: 'Subject ref: type:externalKey. A passive reminder attaches to a task, project, goal or wiki_page; use --active for a conversation',
|
|
24
|
+
required: true,
|
|
25
|
+
}),
|
|
23
26
|
content: core_1.Flags.string({ description: "The reminder's own words", required: true }),
|
|
24
27
|
at: core_1.Flags.string({ description: 'ISO-8601 instant to remind at', exclusive: ['in'] }),
|
|
25
28
|
in: core_1.Flags.string({
|
|
@@ -42,7 +42,8 @@ class FollowupsReschedule extends base_command_1.BaseCommand {
|
|
|
42
42
|
this.log(JSON.stringify(result, null, 2));
|
|
43
43
|
return;
|
|
44
44
|
}
|
|
45
|
-
|
|
45
|
+
const next = result.followup?.nextRunAt;
|
|
46
|
+
this.log(`Follow-up ${args.id} rescheduled to ${typeof next === 'string' ? next : at}.`);
|
|
46
47
|
}
|
|
47
48
|
}
|
|
48
49
|
exports.default = FollowupsReschedule;
|
|
@@ -48,7 +48,7 @@ class FollowupsResolve extends base_command_1.BaseCommand {
|
|
|
48
48
|
this.log(JSON.stringify(result, null, 2));
|
|
49
49
|
return;
|
|
50
50
|
}
|
|
51
|
-
this.log(
|
|
51
|
+
this.log((0, followups_1.settledLine)(args.id, result, `settled: ${flags.outcome}`));
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
exports.default = FollowupsResolve;
|
|
@@ -3,6 +3,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const core_1 = require("@oclif/core");
|
|
4
4
|
const base_command_1 = require("../../base-command");
|
|
5
5
|
const followups_1 = require("../../lib/followups");
|
|
6
|
+
/** What each gate posture means for whoever reads `show`. */
|
|
7
|
+
const GATE_LABEL = {
|
|
8
|
+
exempt_silent: 'fires without approval (silent)',
|
|
9
|
+
exempt_user_directed: 'fires without approval (you asked for it)',
|
|
10
|
+
exempt_system: 'fires without approval (system)',
|
|
11
|
+
user_directed_guarded: 'fires without approval (you asked for it); still held by quiet hours, approval-only action classes and the spend cap',
|
|
12
|
+
autonomy_ladder: "follows the agent's autonomy mode",
|
|
13
|
+
approval_ladder: 'needs approval unless the autonomy mode allows it',
|
|
14
|
+
};
|
|
6
15
|
/** `skrr followups show <id>` — one follow-up, the same shape as the list rows. */
|
|
7
16
|
class FollowupsShow extends base_command_1.BaseCommand {
|
|
8
17
|
static description = 'Show one follow-up';
|
|
@@ -34,8 +43,19 @@ class FollowupsShow extends base_command_1.BaseCommand {
|
|
|
34
43
|
['why', row.why],
|
|
35
44
|
['intent', row.intentKey],
|
|
36
45
|
['producer', row.producer],
|
|
46
|
+
['gate', row.gate ? (GATE_LABEL[row.gate] ?? row.gate) : undefined],
|
|
37
47
|
['terminal', row.terminal ? `${row.terminal} (${row.terminalReason ?? '—'})` : undefined],
|
|
48
|
+
[
|
|
49
|
+
'settled',
|
|
50
|
+
row.terminal ? `${row.terminalAt ?? '—'} by ${row.terminalBy ?? 'unknown'}` : undefined,
|
|
51
|
+
],
|
|
38
52
|
['deadline', row.deadlineAt],
|
|
53
|
+
[
|
|
54
|
+
'waiting',
|
|
55
|
+
row.parkedAt && !row.terminal
|
|
56
|
+
? `on an offline machine since ${row.parkedAt} (escalates after 60 minutes)`
|
|
57
|
+
: undefined,
|
|
58
|
+
],
|
|
39
59
|
['escalated to', row.escalatedInitiativeId],
|
|
40
60
|
]) {
|
|
41
61
|
if (value)
|
|
@@ -21,7 +21,11 @@ const triggers_1 = require("../../lib/triggers");
|
|
|
21
21
|
* cannot stop is a leak.
|
|
22
22
|
*/
|
|
23
23
|
class FollowupsWatch extends base_command_1.BaseCommand {
|
|
24
|
-
static
|
|
24
|
+
static summary = 'Watch an asynchronous tail until it settles — the watch follow-up';
|
|
25
|
+
static description = [
|
|
26
|
+
'Two forms, and they cost different amounts. Prefer the predicate form whenever the state is readable over HTTPS: --url + --until is evaluated by the server, wakes the agent once when the condition settles, and always ends at --deadline.',
|
|
27
|
+
"The recipe form (--check / --success / --abort) wakes the agent for one turn per check, and every turn counts against the agent's watch budget. Use it only for a check a predicate cannot express.",
|
|
28
|
+
].join('\n\n');
|
|
25
29
|
static examples = [
|
|
26
30
|
'<%= config.bin %> followups watch --subject task:OSK-42 --why "deploy still running" --url https://ci.example.com/api/build/9 --until \'{"path":"status","op":"equals","value":"done"}\' --deadline 6h',
|
|
27
31
|
'<%= config.bin %> followups watch --subject task:OSK-42 --why "pr review" --check "gh pr view 42 --json state" --success "state == MERGED" --abort "state == CLOSED" --wait event --wait-entity github --wait-event pull_request_merged --wait-fallback 2h',
|
|
@@ -34,7 +38,7 @@ class FollowupsWatch extends base_command_1.BaseCommand {
|
|
|
34
38
|
// predicate form
|
|
35
39
|
url: core_1.Flags.string({ description: 'HTTPS endpoint to observe (predicate form)' }),
|
|
36
40
|
until: core_1.Flags.string({
|
|
37
|
-
description: 'Predicate tree as JSON (predicate form): a leaf {"path","op","value"} or {"all"|"any": [...]}. op is equals, not_equals, contains, starts_with, in, gt, lt, exists, … — an unknown op is refused with the full list',
|
|
41
|
+
description: 'Predicate tree as JSON (predicate form — the server evaluates it; no agent turn per check): a leaf {"path","op","value"} or {"all"|"any": [...]}. op is equals, not_equals, contains, starts_with, in, gt, lt, exists, … — an unknown op is refused with the full list',
|
|
38
42
|
}),
|
|
39
43
|
grant: core_1.Flags.string({ description: 'Grant id supplying the watch credentials' }),
|
|
40
44
|
deadline: core_1.Flags.string({ description: 'When the watch must stop (predicate form, required)' }),
|
|
@@ -43,7 +47,9 @@ class FollowupsWatch extends base_command_1.BaseCommand {
|
|
|
43
47
|
'root-path': core_1.Flags.string({ description: 'JSON root path inside the response' }),
|
|
44
48
|
'resume-prompt': core_1.Flags.string({ description: 'What to tell the settling turn' }),
|
|
45
49
|
// recipe form
|
|
46
|
-
check: core_1.Flags.string({
|
|
50
|
+
check: core_1.Flags.string({
|
|
51
|
+
description: 'The check the agent runs (recipe form) — every check wakes the agent for one turn, counted against the watch budget',
|
|
52
|
+
}),
|
|
47
53
|
success: core_1.Flags.string({ description: 'What state means the wait resolved (recipe form)' }),
|
|
48
54
|
abort: core_1.Flags.string({ description: 'When to stop and escalate (recipe form)' }),
|
|
49
55
|
wait: core_1.Flags.string({
|
|
@@ -54,12 +54,29 @@ class HarnessesForget extends base_command_1.BaseCommand {
|
|
|
54
54
|
const current = await (0, harnesses_1.getHarness)(args.harness);
|
|
55
55
|
label = current?.harness?.name || args.harness;
|
|
56
56
|
}
|
|
57
|
-
catch {
|
|
58
|
-
|
|
57
|
+
catch (err) {
|
|
58
|
+
// Existence before consent (OSK-9995): asking "Forget harness X?" about
|
|
59
|
+
// a row that does not exist, then reporting NOT_FOUND only after --yes,
|
|
60
|
+
// made the prompt the first thing to fail. Any other read failure still
|
|
61
|
+
// falls back to the id — the confirmation has to happen regardless.
|
|
62
|
+
if (err instanceof api_fetch_1.ApiFetchError && err.status === 404) {
|
|
63
|
+
// NOT_FOUND, the code `harnesses show` gives the same missing id, so a
|
|
64
|
+
// script branching on the code sees one answer (OSK-9995 verifier).
|
|
65
|
+
this.failWithCliError({
|
|
66
|
+
message: `No harness on this account has id ${args.harness}. Run \`skrr harnesses list --all\` to see them.`,
|
|
67
|
+
code: 'NOT_FOUND',
|
|
68
|
+
status: 404,
|
|
69
|
+
exit: 4,
|
|
70
|
+
retryable: false,
|
|
71
|
+
});
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
59
74
|
}
|
|
60
75
|
const ok = await this.confirm(`Forget harness "${label}"? Agents pinned to it lose their pin.`);
|
|
61
76
|
if (!ok) {
|
|
62
|
-
|
|
77
|
+
// Non-zero because nothing was forgotten — the same rule as `tasks
|
|
78
|
+
// update`: a script can only read the exit code, and 0 read as success.
|
|
79
|
+
this.error('Cancelled — nothing was forgotten.', { exit: 1 });
|
|
63
80
|
return;
|
|
64
81
|
}
|
|
65
82
|
}
|