@skrr-ai/cli 0.1.40 → 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/dist/base-command.d.ts +9 -0
- package/dist/base-command.js +18 -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.js +6 -1
- 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/update.js +6 -1
- 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/resolve.js +1 -1
- package/dist/commands/followups/show.js +16 -0
- 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/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/exec-runtime-binary.js +2 -2
- package/dist/lib/followups.d.ts +10 -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/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/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/node_modules/@skrr-ai/data-provider/index.js +5029 -5007
- package/oclif.manifest.json +2689 -2584
- package/package.json +6 -3
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
46
46
|
exports.localMachine = localMachine;
|
|
47
47
|
exports.resolveDaemonTarget = resolveDaemonTarget;
|
|
48
|
+
exports.listConnectedDaemons = listConnectedDaemons;
|
|
48
49
|
exports.listActiveDaemons = listActiveDaemons;
|
|
49
50
|
const api_fetch_1 = require("./api-fetch");
|
|
50
51
|
const daemonBroker_1 = require("./daemonBroker");
|
|
@@ -103,6 +104,37 @@ async function resolveDaemonTarget(input) {
|
|
|
103
104
|
return { kind: 'none' };
|
|
104
105
|
return { kind: 'ambiguous', daemons };
|
|
105
106
|
}
|
|
107
|
+
/**
|
|
108
|
+
* Daemons that are CONNECTED right now, under the id the daemon-control API
|
|
109
|
+
* takes (`daemon_…`, `dedicated-runtime-…`).
|
|
110
|
+
*
|
|
111
|
+
* `listActiveDaemons` returns Daemon RESOURCE rows: "active" means not revoked,
|
|
112
|
+
* and `id` is the resource's own id. The installer routes relay an RPC to a
|
|
113
|
+
* connected daemon by its connection id, so that list could not be used to pick
|
|
114
|
+
* one: its refusal counted 50 "active daemons" — most of them sandboxes gone for
|
|
115
|
+
* weeks — and suggested values like `d_69eb2d1e...` that `--daemon` then failed
|
|
116
|
+
* to find, and a single "active" daemon would have been auto-picked by an id no
|
|
117
|
+
* route accepts (OSK-9993). Online harness rows carry exactly the ids and the
|
|
118
|
+
* liveness needed, one row per (daemon, provider).
|
|
119
|
+
*/
|
|
120
|
+
async function listConnectedDaemons(credential) {
|
|
121
|
+
const res = await (0, api_fetch_1.apiFetch)('/api/harnesses?status=online', { credential });
|
|
122
|
+
const byDaemon = new Map();
|
|
123
|
+
for (const row of res.harnesses ?? []) {
|
|
124
|
+
if (row.status !== 'online' || !row.daemonId || byDaemon.has(row.daemonId))
|
|
125
|
+
continue;
|
|
126
|
+
// A harness is named "<provider> — <machine>"; the machine half names the daemon.
|
|
127
|
+
const separator = typeof row.name === 'string' ? row.name.indexOf(' — ') : -1;
|
|
128
|
+
byDaemon.set(row.daemonId, {
|
|
129
|
+
id: row.daemonId,
|
|
130
|
+
name: separator === -1 ? undefined : row.name.slice(separator + 3),
|
|
131
|
+
isActive: true,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
// Stable order: the server returns rows most-recently-seen first, so two
|
|
135
|
+
// commands refusing one ambiguity listed the same daemons in different orders.
|
|
136
|
+
return [...byDaemon.values()].sort((a, b) => a.id.localeCompare(b.id));
|
|
137
|
+
}
|
|
106
138
|
/** The same list `skrr list-daemons` prints, so a refusal can name values that work. */
|
|
107
139
|
async function listActiveDaemons(credential) {
|
|
108
140
|
const res = await (0, api_fetch_1.apiFetch)('/api/daemon-resources?status=active&limit=50', { credential });
|
package/dist/lib/daemonBroker.js
CHANGED
|
@@ -311,7 +311,7 @@ async function attemptDaemonBrokerLogin(opts) {
|
|
|
311
311
|
return {
|
|
312
312
|
ok: false,
|
|
313
313
|
reason: 'base_url_mismatch',
|
|
314
|
-
detail: `
|
|
314
|
+
detail: `The skrr background service on this computer is not logged in to ${opts.baseURL}; it is logged in to ${mismatchedBootstrap.serverUrl}.`,
|
|
315
315
|
daemonServerUrl: mismatchedBootstrap.serverUrl,
|
|
316
316
|
};
|
|
317
317
|
}
|
|
@@ -208,7 +208,7 @@ async function handOffToLocalDaemon(env = process.env, opts = {}) {
|
|
|
208
208
|
return {
|
|
209
209
|
status: 'skipped',
|
|
210
210
|
reason: 'legacy-binary',
|
|
211
|
-
detail: 'a legacy oversky
|
|
211
|
+
detail: 'a legacy oversky background service is installed; bootstrap a current skrr one',
|
|
212
212
|
};
|
|
213
213
|
}
|
|
214
214
|
// An older daemon has no `accept-handoff`, and spawning it would fail with
|
|
@@ -64,7 +64,7 @@ exports.RUNTIME_BINARY_NAMES = ['skrrd', 'oversky'];
|
|
|
64
64
|
*/
|
|
65
65
|
function forwardedFlagsNote(verb, opts = {}) {
|
|
66
66
|
const base = opts.bootstrapsRuntime
|
|
67
|
-
? `If
|
|
67
|
+
? `If the background service is not on this computer yet, this command first fetches the signed release. After it is ` +
|
|
68
68
|
`installed, flags are forwarded to \`skrrd ${verb}\` unchanged; run \`skrrd ${verb} --help\` ` +
|
|
69
69
|
`for this verb's own flags, or \`skrrd --help\` for global ones such as \`--profile\`.`
|
|
70
70
|
: `Flags are forwarded to \`skrrd ${verb}\` unchanged, so they are not listed here —` +
|
|
@@ -196,7 +196,7 @@ function isExecutable(p) {
|
|
|
196
196
|
*/
|
|
197
197
|
function notInstalledMessage() {
|
|
198
198
|
return [
|
|
199
|
-
'The skrr
|
|
199
|
+
'The skrr background service is not installed on this computer.',
|
|
200
200
|
'',
|
|
201
201
|
'Install:',
|
|
202
202
|
' macOS: brew install dush1023/oversky/oversky',
|
package/dist/lib/followups.d.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { withQuery } from './triggers';
|
|
2
2
|
type Query = Parameters<typeof withQuery>[1];
|
|
3
3
|
type Json = Record<string, unknown>;
|
|
4
|
+
/**
|
|
5
|
+
* The line a settle verb prints. A follow-up that had already ended is said to
|
|
6
|
+
* have ended, with the terminal it actually has, rather than reported as the
|
|
7
|
+
* thing this command would have done (OSK-10038).
|
|
8
|
+
*/
|
|
9
|
+
export declare function settledLine(id: string, result: Record<string, unknown>, done: string): string;
|
|
4
10
|
/**
|
|
5
11
|
* The `id` argument every follow-up command that addresses one takes.
|
|
6
12
|
*
|
|
@@ -37,6 +43,10 @@ export interface FollowUpRow {
|
|
|
37
43
|
/** Who settled it: `trigger_fire` for the runtime, otherwise the actor. */
|
|
38
44
|
terminalBy?: string | null;
|
|
39
45
|
escalatedInitiativeId?: string | null;
|
|
46
|
+
/** The gate the fire passes: exempt_silent, exempt_user_directed, exempt_system, user_directed_guarded, autonomy_ladder, approval_ladder. */
|
|
47
|
+
gate?: string | null;
|
|
48
|
+
/** Set while its fire waits on an offline machine; it escalates after 60 minutes. */
|
|
49
|
+
parkedAt?: string | null;
|
|
40
50
|
capsule?: unknown;
|
|
41
51
|
nextRunAt?: string | null;
|
|
42
52
|
deadlineAt?: string | null;
|
package/dist/lib/followups.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.followupsApi = exports.WATCH_WAIT_KINDS = exports.FOLLOWUP_RESOLVE_OUTCOMES = exports.FOLLOWUP_STATES = exports.FOLLOWUP_KINDS = exports.followUpIdArg = void 0;
|
|
4
|
+
exports.settledLine = settledLine;
|
|
4
5
|
exports.resolveFollowUpAgent = resolveFollowUpAgent;
|
|
5
6
|
exports.parseSubjectRef = parseSubjectRef;
|
|
6
7
|
exports.followupSummaryLine = followupSummaryLine;
|
|
@@ -26,6 +27,18 @@ const triggers_1 = require("./triggers");
|
|
|
26
27
|
const agent_resolver_1 = require("./agent-resolver");
|
|
27
28
|
const MOUNT = '/api/followups';
|
|
28
29
|
const base = (id) => `${MOUNT}/${encodeURIComponent(id)}`;
|
|
30
|
+
/**
|
|
31
|
+
* The line a settle verb prints. A follow-up that had already ended is said to
|
|
32
|
+
* have ended, with the terminal it actually has, rather than reported as the
|
|
33
|
+
* thing this command would have done (OSK-10038).
|
|
34
|
+
*/
|
|
35
|
+
function settledLine(id, result, done) {
|
|
36
|
+
const followup = result.followup;
|
|
37
|
+
if (result.alreadySettled === true) {
|
|
38
|
+
return `Follow-up ${id} was already settled${followup?.terminal ? ` (${followup.terminal})` : ''}; nothing changed.`;
|
|
39
|
+
}
|
|
40
|
+
return `Follow-up ${id} ${done}.`;
|
|
41
|
+
}
|
|
29
42
|
/**
|
|
30
43
|
* The `id` argument every follow-up command that addresses one takes.
|
|
31
44
|
*
|
|
@@ -79,7 +92,7 @@ function resolveFollowUpAgent(explicitAgentId, env = process.env) {
|
|
|
79
92
|
if (explicitAgentId && explicitAgentId !== sessionAgent.id) {
|
|
80
93
|
throw new agent_resolver_1.AgentResolutionError({
|
|
81
94
|
code: 'AGENT_CONTEXT_CONFLICT',
|
|
82
|
-
message: 'This
|
|
95
|
+
message: 'This session is bound to its session agent. Do not override it with another agent ID.',
|
|
83
96
|
suggestion: 'Use the bound session agent, or start a new daemon session for a different agent.',
|
|
84
97
|
details: { explicitAgentId, sessionAgentId: sessionAgent.id, source: sessionAgent.source },
|
|
85
98
|
});
|
package/dist/lib/format.d.ts
CHANGED
|
@@ -78,6 +78,17 @@ export declare function renderTable<T extends Record<string, string>>(rows: T[],
|
|
|
78
78
|
* should print it in the reader's zone and name that zone once.
|
|
79
79
|
*/
|
|
80
80
|
export declare function localStamp(value: unknown): string;
|
|
81
|
+
/**
|
|
82
|
+
* One timestamp that carries its own zone: `2026-08-21 17:54:03 PDT`.
|
|
83
|
+
*
|
|
84
|
+
* For key/value output and any row that cannot share a header naming the zone.
|
|
85
|
+
* About 25 commands formatted with `toISOString().slice(0, 19)` — UTC with no
|
|
86
|
+
* marker, which reads as local time — while `harnesses list` and `machines`
|
|
87
|
+
* printed local time with the zone named, so one CLI kept two clocks
|
|
88
|
+
* (OSK-10041). Seconds, because the commands that print these (task runs,
|
|
89
|
+
* activity, monitor) order events seconds apart. Never throws.
|
|
90
|
+
*/
|
|
91
|
+
export declare function localTime(value: unknown): string;
|
|
81
92
|
/**
|
|
82
93
|
* `PDT` — the zone `localStamp` renders in, to be named once per command
|
|
83
94
|
* rather than repeated on every row.
|
package/dist/lib/format.js
CHANGED
|
@@ -7,6 +7,7 @@ exports.formatCell = formatCell;
|
|
|
7
7
|
exports.collapseWhitespace = collapseWhitespace;
|
|
8
8
|
exports.renderTable = renderTable;
|
|
9
9
|
exports.localStamp = localStamp;
|
|
10
|
+
exports.localTime = localTime;
|
|
10
11
|
exports.localZone = localZone;
|
|
11
12
|
/**
|
|
12
13
|
* Code points that occupy TWO terminal columns (Unicode East Asian Wide and
|
|
@@ -212,6 +213,26 @@ function localStamp(value) {
|
|
|
212
213
|
return (`${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ` +
|
|
213
214
|
`${pad(date.getHours())}:${pad(date.getMinutes())}`);
|
|
214
215
|
}
|
|
216
|
+
/**
|
|
217
|
+
* One timestamp that carries its own zone: `2026-08-21 17:54:03 PDT`.
|
|
218
|
+
*
|
|
219
|
+
* For key/value output and any row that cannot share a header naming the zone.
|
|
220
|
+
* About 25 commands formatted with `toISOString().slice(0, 19)` — UTC with no
|
|
221
|
+
* marker, which reads as local time — while `harnesses list` and `machines`
|
|
222
|
+
* printed local time with the zone named, so one CLI kept two clocks
|
|
223
|
+
* (OSK-10041). Seconds, because the commands that print these (task runs,
|
|
224
|
+
* activity, monitor) order events seconds apart. Never throws.
|
|
225
|
+
*/
|
|
226
|
+
function localTime(value) {
|
|
227
|
+
if (value === null || value === undefined || value === '')
|
|
228
|
+
return '-';
|
|
229
|
+
const date = value instanceof Date ? value : new Date(typeof value === 'number' ? value : String(value));
|
|
230
|
+
if (Number.isNaN(date.getTime()))
|
|
231
|
+
return String(value);
|
|
232
|
+
const zone = localZone(date);
|
|
233
|
+
const seconds = `${date.getSeconds()}`.padStart(2, '0');
|
|
234
|
+
return `${localStamp(date)}:${seconds}${zone ? ` ${zone}` : ''}`;
|
|
235
|
+
}
|
|
215
236
|
/**
|
|
216
237
|
* `PDT` — the zone `localStamp` renders in, to be named once per command
|
|
217
238
|
* rather than repeated on every row.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How a harness row's provider and status read in human output — ONE rule for
|
|
3
|
+
* `harnesses list` and `harnesses show`.
|
|
4
|
+
*
|
|
5
|
+
* Both findings this closes were the same defect on two columns: the rule lived
|
|
6
|
+
* in one command and not the other.
|
|
7
|
+
*
|
|
8
|
+
* - Status (OSK-9610): `list` printed `superseded` for a row a later
|
|
9
|
+
* registration replaced; `show` printed `offline` for the same id. The server
|
|
10
|
+
* sends `superseded` on both routes — `show` never read it.
|
|
11
|
+
* - Provider (OSK-9649 / OSK-9290): the web renders the placeholder row of a
|
|
12
|
+
* machine with no coding engine as "No coding agent installed" and folds the
|
|
13
|
+
* first-party harness's older spelling into its current one. The CLI printed
|
|
14
|
+
* the stored value — `oversky` on 111 rows, and the first-party harness's
|
|
15
|
+
* older spelling beside its current one — so one product had three names here.
|
|
16
|
+
*
|
|
17
|
+
* `--json` keeps the stored values: it is the API contract, not a rendering.
|
|
18
|
+
*/
|
|
19
|
+
/** What the PROVIDER column says for a machine that has no coding engine. */
|
|
20
|
+
export declare const NO_CODING_AGENT_PROVIDER_LABEL = "none";
|
|
21
|
+
export declare function harnessStatusLabel(row: {
|
|
22
|
+
status?: string | null;
|
|
23
|
+
superseded?: boolean | null;
|
|
24
|
+
}): string;
|
|
25
|
+
export declare function isNoCodingAgentProvider(provider: string | null | undefined): boolean;
|
|
26
|
+
export declare function harnessProviderLabel(provider: string | null | undefined): string;
|
|
27
|
+
/**
|
|
28
|
+
* YOUR alias is what `name` shows and it differs from the name everyone else
|
|
29
|
+
* sees. The server sends both (`aliased`, `sharedName`); every human surface
|
|
30
|
+
* asks this one question of them, so `list`, `show` and `update --name` cannot
|
|
31
|
+
* disagree about whether a row is aliased (OSK-10004).
|
|
32
|
+
*/
|
|
33
|
+
export declare function isAliasCoveringSharedName(row: {
|
|
34
|
+
name?: string | null;
|
|
35
|
+
sharedName?: string | null;
|
|
36
|
+
aliased?: boolean | null;
|
|
37
|
+
}): boolean;
|
|
38
|
+
/** The longer phrase, for a single-row view with room for it. */
|
|
39
|
+
export declare function harnessProviderDescription(provider: string | null | undefined): string;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* How a harness row's provider and status read in human output — ONE rule for
|
|
4
|
+
* `harnesses list` and `harnesses show`.
|
|
5
|
+
*
|
|
6
|
+
* Both findings this closes were the same defect on two columns: the rule lived
|
|
7
|
+
* in one command and not the other.
|
|
8
|
+
*
|
|
9
|
+
* - Status (OSK-9610): `list` printed `superseded` for a row a later
|
|
10
|
+
* registration replaced; `show` printed `offline` for the same id. The server
|
|
11
|
+
* sends `superseded` on both routes — `show` never read it.
|
|
12
|
+
* - Provider (OSK-9649 / OSK-9290): the web renders the placeholder row of a
|
|
13
|
+
* machine with no coding engine as "No coding agent installed" and folds the
|
|
14
|
+
* first-party harness's older spelling into its current one. The CLI printed
|
|
15
|
+
* the stored value — `oversky` on 111 rows, and the first-party harness's
|
|
16
|
+
* older spelling beside its current one — so one product had three names here.
|
|
17
|
+
*
|
|
18
|
+
* `--json` keeps the stored values: it is the API contract, not a rendering.
|
|
19
|
+
*/
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
exports.NO_CODING_AGENT_PROVIDER_LABEL = void 0;
|
|
22
|
+
exports.harnessStatusLabel = harnessStatusLabel;
|
|
23
|
+
exports.isNoCodingAgentProvider = isNoCodingAgentProvider;
|
|
24
|
+
exports.harnessProviderLabel = harnessProviderLabel;
|
|
25
|
+
exports.isAliasCoveringSharedName = isAliasCoveringSharedName;
|
|
26
|
+
exports.harnessProviderDescription = harnessProviderDescription;
|
|
27
|
+
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
28
|
+
/** What the PROVIDER column says for a machine that has no coding engine. */
|
|
29
|
+
exports.NO_CODING_AGENT_PROVIDER_LABEL = 'none';
|
|
30
|
+
function harnessStatusLabel(row) {
|
|
31
|
+
if (row.superseded)
|
|
32
|
+
return 'superseded';
|
|
33
|
+
return typeof row.status === 'string' && row.status.length > 0 ? row.status : 'unknown';
|
|
34
|
+
}
|
|
35
|
+
function isNoCodingAgentProvider(provider) {
|
|
36
|
+
return typeof provider === 'string' && (0, data_provider_1.isManagedProductFallbackProvider)(provider);
|
|
37
|
+
}
|
|
38
|
+
function harnessProviderLabel(provider) {
|
|
39
|
+
if (typeof provider !== 'string' || provider.length === 0)
|
|
40
|
+
return 'unknown';
|
|
41
|
+
if (isNoCodingAgentProvider(provider))
|
|
42
|
+
return exports.NO_CODING_AGENT_PROVIDER_LABEL;
|
|
43
|
+
return String((0, data_provider_1.canonicalHarnessProvider)(provider) ?? provider);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* YOUR alias is what `name` shows and it differs from the name everyone else
|
|
47
|
+
* sees. The server sends both (`aliased`, `sharedName`); every human surface
|
|
48
|
+
* asks this one question of them, so `list`, `show` and `update --name` cannot
|
|
49
|
+
* disagree about whether a row is aliased (OSK-10004).
|
|
50
|
+
*/
|
|
51
|
+
function isAliasCoveringSharedName(row) {
|
|
52
|
+
return Boolean(row.aliased && row.sharedName && row.sharedName !== row.name);
|
|
53
|
+
}
|
|
54
|
+
/** The longer phrase, for a single-row view with room for it. */
|
|
55
|
+
function harnessProviderDescription(provider) {
|
|
56
|
+
if (isNoCodingAgentProvider(provider)) {
|
|
57
|
+
return `${exports.NO_CODING_AGENT_PROVIDER_LABEL} — ${(0, data_provider_1.managedProductFallbackLabel)().toLowerCase()} on this machine`;
|
|
58
|
+
}
|
|
59
|
+
return harnessProviderLabel(provider);
|
|
60
|
+
}
|
package/dist/lib/harnesses.d.ts
CHANGED
|
@@ -51,6 +51,12 @@ export interface Harness {
|
|
|
51
51
|
sharedName?: string;
|
|
52
52
|
aliased?: boolean;
|
|
53
53
|
status?: string;
|
|
54
|
+
/**
|
|
55
|
+
* A later registration on the same machine replaced this row. Sent by both
|
|
56
|
+
* the list and the single-row routes; human output shows it instead of the
|
|
57
|
+
* stored status (`harnessStatusLabel`, OSK-9610).
|
|
58
|
+
*/
|
|
59
|
+
superseded?: boolean;
|
|
54
60
|
harnessLocation?: 'local' | 'cloud';
|
|
55
61
|
daemonId?: string;
|
|
56
62
|
machineUuid?: string;
|
|
@@ -76,3 +76,16 @@ export declare function describeTargetSync(target: {
|
|
|
76
76
|
updatedAt?: string;
|
|
77
77
|
driftCount?: number;
|
|
78
78
|
}, now?: number, liveDaemonIds?: string[]): string;
|
|
79
|
+
/**
|
|
80
|
+
* The command that re-binds a stalled target to the daemon now running on its
|
|
81
|
+
* machine, or null when no such daemon is live.
|
|
82
|
+
*
|
|
83
|
+
* A daemon started a different way on the same machine (launchd → cli) gets a
|
|
84
|
+
* new id, and a target stays bound to the old one. Placement is the machine, not
|
|
85
|
+
* the daemon, so the recovery is `update-target --daemon`, never a re-install,
|
|
86
|
+
* which the placement index refuses (OSK-9961).
|
|
87
|
+
*/
|
|
88
|
+
export declare function rebindCommandFor(target: {
|
|
89
|
+
id: string;
|
|
90
|
+
daemonId?: string | null;
|
|
91
|
+
}, liveDaemonIds: readonly string[]): string | null;
|
|
@@ -7,6 +7,7 @@ exports.resolveBundleLabel = resolveBundleLabel;
|
|
|
7
7
|
exports.parseDaemonId = parseDaemonId;
|
|
8
8
|
exports.sameMachineDaemon = sameMachineDaemon;
|
|
9
9
|
exports.describeTargetSync = describeTargetSync;
|
|
10
|
+
exports.rebindCommandFor = rebindCommandFor;
|
|
10
11
|
const promises_1 = require("node:fs/promises");
|
|
11
12
|
async function readStdin() {
|
|
12
13
|
const chunks = [];
|
|
@@ -180,7 +181,25 @@ function describeTargetSync(target, now = Date.now(), liveDaemonIds = []) {
|
|
|
180
181
|
const live = parseDaemonId(elsewhere);
|
|
181
182
|
const pinned = parseDaemonId(target.daemonId || '');
|
|
182
183
|
// Kept under the STATUS column's `maxWidth: 78`, same constraint as below.
|
|
183
|
-
|
|
184
|
+
// Re-bind, not re-install: install refuses a second target on the same
|
|
185
|
+
// placement, so "re-install" was a remedy that could not succeed (OSK-9961).
|
|
186
|
+
// The full command does not fit the column; status prints it below.
|
|
187
|
+
return `${base} — stalled ${days}d; daemon here now runs as ${live?.source}, not ${pinned?.source}: re-bind below`;
|
|
184
188
|
}
|
|
185
189
|
return `${base} — stalled ${days}d; daemon may be gone: remove, then purge-target --force`;
|
|
186
190
|
}
|
|
191
|
+
/**
|
|
192
|
+
* The command that re-binds a stalled target to the daemon now running on its
|
|
193
|
+
* machine, or null when no such daemon is live.
|
|
194
|
+
*
|
|
195
|
+
* A daemon started a different way on the same machine (launchd → cli) gets a
|
|
196
|
+
* new id, and a target stays bound to the old one. Placement is the machine, not
|
|
197
|
+
* the daemon, so the recovery is `update-target --daemon`, never a re-install,
|
|
198
|
+
* which the placement index refuses (OSK-9961).
|
|
199
|
+
*/
|
|
200
|
+
function rebindCommandFor(target, liveDaemonIds) {
|
|
201
|
+
if (!target.daemonId || liveDaemonIds.includes(target.daemonId))
|
|
202
|
+
return null;
|
|
203
|
+
const live = sameMachineDaemon(target.daemonId, [...liveDaemonIds]);
|
|
204
|
+
return live ? `skrr instructions update-target ${target.id} --daemon ${live}` : null;
|
|
205
|
+
}
|
|
@@ -38,7 +38,23 @@ export declare function isUserInvocable(skill: Pick<DaemonLocalSkill, 'triggers'
|
|
|
38
38
|
* dropped, because the server's own rule is that a skill the user picked and
|
|
39
39
|
* the turn did not load must fail the turn rather than run without it.
|
|
40
40
|
*/
|
|
41
|
-
|
|
41
|
+
/**
|
|
42
|
+
* The restart that refreshes THIS daemon's inventory. A daemon id is
|
|
43
|
+
* `daemon_<machine>_<source>_<profile>`; a bare `skrr daemon restart` restarts
|
|
44
|
+
* the default profile, so for any other profile the hint named a different
|
|
45
|
+
* daemon than the one whose list was stale (OSK-10080 verifier).
|
|
46
|
+
*/
|
|
47
|
+
export declare function daemonRestartCommand(daemonId: string | undefined): string;
|
|
48
|
+
export declare function resolveLocalSkillRefs(inventory: ReadonlyArray<DaemonLocalSkill>, requested: ReadonlyArray<string>, options?: {
|
|
49
|
+
/**
|
|
50
|
+
* The inventory is what the daemon reported when it last registered, not a
|
|
51
|
+
* live read. A skill added since is missing from it — for up to an hour, until
|
|
52
|
+
* the daemon reconnects — so "not on this machine" would be false (OSK-10080).
|
|
53
|
+
*/
|
|
54
|
+
snapshot?: boolean;
|
|
55
|
+
/** Whose snapshot, so the refresh hint restarts the right daemon. */
|
|
56
|
+
daemonId?: string;
|
|
57
|
+
}): {
|
|
42
58
|
refs: Array<{
|
|
43
59
|
name: string;
|
|
44
60
|
pathHash: string;
|
package/dist/lib/local-skills.js
CHANGED
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.SKILL_CONVENTION_DISCOVERY_SINCE = void 0;
|
|
4
4
|
exports.chooseDaemon = chooseDaemon;
|
|
5
5
|
exports.isUserInvocable = isUserInvocable;
|
|
6
|
+
exports.daemonRestartCommand = daemonRestartCommand;
|
|
6
7
|
exports.resolveLocalSkillRefs = resolveLocalSkillRefs;
|
|
7
8
|
exports.withSkillInvocations = withSkillInvocations;
|
|
8
9
|
exports.looksLikeSkillPath = looksLikeSkillPath;
|
|
@@ -10,6 +11,7 @@ exports.findLocalSkillsNamed = findLocalSkillsNamed;
|
|
|
10
11
|
exports.describeStoreSkillMiss = describeStoreSkillMiss;
|
|
11
12
|
exports.daemonPredates = daemonPredates;
|
|
12
13
|
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
14
|
+
const instruction_input_1 = require("./instruction-input");
|
|
13
15
|
/**
|
|
14
16
|
* Which machine to ask, or why there is no single answer.
|
|
15
17
|
*
|
|
@@ -44,7 +46,19 @@ function isUserInvocable(skill) {
|
|
|
44
46
|
* dropped, because the server's own rule is that a skill the user picked and
|
|
45
47
|
* the turn did not load must fail the turn rather than run without it.
|
|
46
48
|
*/
|
|
47
|
-
|
|
49
|
+
/**
|
|
50
|
+
* The restart that refreshes THIS daemon's inventory. A daemon id is
|
|
51
|
+
* `daemon_<machine>_<source>_<profile>`; a bare `skrr daemon restart` restarts
|
|
52
|
+
* the default profile, so for any other profile the hint named a different
|
|
53
|
+
* daemon than the one whose list was stale (OSK-10080 verifier).
|
|
54
|
+
*/
|
|
55
|
+
function daemonRestartCommand(daemonId) {
|
|
56
|
+
const profile = daemonId ? (0, instruction_input_1.parseDaemonId)(daemonId)?.profile : undefined;
|
|
57
|
+
return profile && profile !== 'default'
|
|
58
|
+
? `skrr daemon restart --profile ${profile}`
|
|
59
|
+
: 'skrr daemon restart';
|
|
60
|
+
}
|
|
61
|
+
function resolveLocalSkillRefs(inventory, requested, options = {}) {
|
|
48
62
|
const refs = [];
|
|
49
63
|
const problems = [];
|
|
50
64
|
const seen = new Set();
|
|
@@ -58,7 +72,11 @@ function resolveLocalSkillRefs(inventory, requested) {
|
|
|
58
72
|
if (matches.length === 0) {
|
|
59
73
|
problems.push(named.length > 0
|
|
60
74
|
? `No skill "${name}" under ${root}. It is under: ${named.map((s) => s.source ?? '?').join(', ')}.`
|
|
61
|
-
:
|
|
75
|
+
: options.snapshot
|
|
76
|
+
? `No skill named "${name}" in the list this machine's daemon reported when it last connected. ` +
|
|
77
|
+
`A skill added since then appears after the daemon reconnects — run \`${daemonRestartCommand(options.daemonId)}\` on that machine. ` +
|
|
78
|
+
'See `skrr skills local`.'
|
|
79
|
+
: `No skill named "${name}" on this machine. See \`skrr skills local\`.`);
|
|
62
80
|
continue;
|
|
63
81
|
}
|
|
64
82
|
if (matches.length > 1) {
|
package/dist/lib/login.js
CHANGED
|
@@ -84,7 +84,7 @@ async function cliLogin(opts = {}) {
|
|
|
84
84
|
});
|
|
85
85
|
if (brokerResult.ok) {
|
|
86
86
|
console.log('');
|
|
87
|
-
console.log(' Authorized via the
|
|
87
|
+
console.log(' Authorized via the skrr background service on this computer (no browser needed).');
|
|
88
88
|
return {
|
|
89
89
|
token: brokerResult.accessToken,
|
|
90
90
|
refreshToken: brokerResult.refreshToken,
|
|
@@ -107,7 +107,7 @@ async function cliLogin(opts = {}) {
|
|
|
107
107
|
// broker failures — missing bootstrap, network blip, server 5xx —
|
|
108
108
|
// silently fall through to PKCE / device-code below.
|
|
109
109
|
if (brokerResult.reason === 'ci_token_refused') {
|
|
110
|
-
throw new Error('The
|
|
110
|
+
throw new Error('The skrr background service on this computer is bootstrapped from a CI token, which cannot broker an interactive CLI login. ' +
|
|
111
111
|
'Use `skrr create-token --name <name>` to mint a long-lived CI credential directly, ' +
|
|
112
112
|
'or run `skrr login` on a machine where the daemon was authenticated interactively.');
|
|
113
113
|
}
|
|
@@ -126,19 +126,19 @@ async function cliLogin(opts = {}) {
|
|
|
126
126
|
brokerRateLimited = true;
|
|
127
127
|
if (!(0, ssh_detect_1.isNonInteractive)()) {
|
|
128
128
|
console.log('');
|
|
129
|
-
console.log(' The
|
|
129
|
+
console.log(' The skrr background service on this computer has brokered several logins recently and the server is ' +
|
|
130
130
|
'rate-limiting them. Falling back to the browser flow.');
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
133
|
if (brokerResult.reason === 'base_url_mismatch' && brokerResult.daemonServerUrl) {
|
|
134
134
|
console.log('');
|
|
135
|
-
console.log(` The
|
|
135
|
+
console.log(` The skrr background service on this computer is logged in to ${brokerResult.daemonServerUrl}, but skrr is configured for ${serverUrl}.`);
|
|
136
136
|
console.log(` Skipping the daemon-broker handoff. Run \`skrr login --base-url ${brokerResult.daemonServerUrl}\` to use the daemon instead.`);
|
|
137
137
|
}
|
|
138
138
|
}
|
|
139
139
|
if ((0, ssh_detect_1.isNonInteractive)()) {
|
|
140
140
|
throw new Error(brokerRateLimited
|
|
141
|
-
? 'The
|
|
141
|
+
? 'The skrr background service on this computer is being rate-limited while brokering logins, and this ' +
|
|
142
142
|
'shell cannot run the browser flow instead. The limit is per 15-minute window — ' +
|
|
143
143
|
'retry shortly. For CI, use `skrr create-token` and set OVERSKY_TOKEN=osk_ci_...'
|
|
144
144
|
: 'skrr login requires an interactive terminal or an SSH session. ' +
|
package/dist/lib/machines.d.ts
CHANGED
|
@@ -112,6 +112,12 @@ export interface Machine {
|
|
|
112
112
|
* could come back says so, and a destroyed one cannot.
|
|
113
113
|
*/
|
|
114
114
|
export declare function machineStateLabel(machine: Machine): string;
|
|
115
|
+
/**
|
|
116
|
+
* What a list says it left out, by the label each hidden machine would have
|
|
117
|
+
* printed: `250 terminated, 5 offline, 1 paused`. "offline or terminated"
|
|
118
|
+
* called a paused machine offline after the table stopped doing so (OSK-9996).
|
|
119
|
+
*/
|
|
120
|
+
export declare function hiddenMachinesSummary(hidden: readonly Machine[]): string;
|
|
115
121
|
/** Is this a machine a user could still use, or bring back? */
|
|
116
122
|
export declare function isReachableMachine(machine: Machine): boolean;
|
|
117
123
|
/** The user-editable slice. Identities, capabilities and lifecycle are not. */
|
package/dist/lib/machines.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.machineStateLabel = machineStateLabel;
|
|
4
|
+
exports.hiddenMachinesSummary = hiddenMachinesSummary;
|
|
4
5
|
exports.isReachableMachine = isReachableMachine;
|
|
5
6
|
exports.liveHarnessCount = liveHarnessCount;
|
|
6
7
|
exports.listMachines = listMachines;
|
|
@@ -30,8 +31,36 @@ function machineStateLabel(machine) {
|
|
|
30
31
|
if (controls && controls.canResume === false && controls.canTerminate === false) {
|
|
31
32
|
return 'terminated';
|
|
32
33
|
}
|
|
34
|
+
// A leased machine at rest says WHICH rest. `machines hosted list` printed
|
|
35
|
+
// `paused` and this list printed `offline` for the same machine, with the
|
|
36
|
+
// reason only in `machines show` (OSK-9996). `offline` stays for a machine
|
|
37
|
+
// that simply is not connected.
|
|
38
|
+
const leaseState = machine.lease?.state;
|
|
39
|
+
if (leaseState === 'paused' || leaseState === 'stopped')
|
|
40
|
+
return leaseState;
|
|
41
|
+
// A lease the provider has ended cannot come back either; it read `offline`
|
|
42
|
+
// while an unleased dead sandbox read `terminated`, so the hidden-machine
|
|
43
|
+
// footer counted 95 ended leases as offline (OSK-9996 verifier).
|
|
44
|
+
if (leaseState === 'terminated')
|
|
45
|
+
return 'terminated';
|
|
33
46
|
return 'offline';
|
|
34
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* What a list says it left out, by the label each hidden machine would have
|
|
50
|
+
* printed: `250 terminated, 5 offline, 1 paused`. "offline or terminated"
|
|
51
|
+
* called a paused machine offline after the table stopped doing so (OSK-9996).
|
|
52
|
+
*/
|
|
53
|
+
function hiddenMachinesSummary(hidden) {
|
|
54
|
+
const counts = new Map();
|
|
55
|
+
for (const machine of hidden) {
|
|
56
|
+
const label = machineStateLabel(machine);
|
|
57
|
+
counts.set(label, (counts.get(label) ?? 0) + 1);
|
|
58
|
+
}
|
|
59
|
+
return [...counts.entries()]
|
|
60
|
+
.sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]))
|
|
61
|
+
.map(([label, count]) => `${count} ${label}`)
|
|
62
|
+
.join(', ');
|
|
63
|
+
}
|
|
35
64
|
/** Is this a machine a user could still use, or bring back? */
|
|
36
65
|
function isReachableMachine(machine) {
|
|
37
66
|
return machineStateLabel(machine) !== 'terminated' && machine.status !== 'offline';
|
|
@@ -105,6 +134,22 @@ function hostedSandboxDaemonIds(ref) {
|
|
|
105
134
|
return [];
|
|
106
135
|
return [`hosted-machine-${ref}`, `hosted-job-machine-${ref}`];
|
|
107
136
|
}
|
|
137
|
+
/**
|
|
138
|
+
* An id with its identity-kind prefix removed: `lease:rtl_…` → `rtl_…`,
|
|
139
|
+
* `dedicated-runtime:rtl_…` → `rtl_…`, `machine:0354…` → `0354…`.
|
|
140
|
+
*
|
|
141
|
+
* Other commands print the bare form. `machines dedicated list` and the lease
|
|
142
|
+
* payloads name `rtl_…`, and `harnesses list`'s MACHINE column prints the head
|
|
143
|
+
* of the identifier after the kind — so the id a user has to hand often lacks
|
|
144
|
+
* the prefix this list keys on, and `machines show rtl_…` answered "No machine
|
|
145
|
+
* matches" for a machine it was listing as `lease:rtl_…` (OSK-9269, OSK-9290).
|
|
146
|
+
*/
|
|
147
|
+
function withoutIdentityKind(value) {
|
|
148
|
+
if (!value)
|
|
149
|
+
return undefined;
|
|
150
|
+
const separator = value.indexOf(':');
|
|
151
|
+
return separator === -1 ? undefined : value.slice(separator + 1);
|
|
152
|
+
}
|
|
108
153
|
function resolveMachineRef(machines, ref) {
|
|
109
154
|
const needle = ref.trim();
|
|
110
155
|
const lower = needle.toLowerCase();
|
|
@@ -121,13 +166,26 @@ function resolveMachineRef(machines, ref) {
|
|
|
121
166
|
// two unrelated-looking ids, no way on screen to tell they are one
|
|
122
167
|
// machine. Exact composition, not a substring search, so this cannot
|
|
123
168
|
// match a machine that merely contains the text.
|
|
124
|
-
hostedSandboxDaemonIds(needle).some((candidate) => m.daemonId === candidate)
|
|
169
|
+
hostedSandboxDaemonIds(needle).some((candidate) => m.daemonId === candidate) ||
|
|
170
|
+
withoutIdentityKind(m.id) === needle ||
|
|
171
|
+
withoutIdentityKind(m.machineUuid) === needle ||
|
|
172
|
+
// A harness id names exactly one machine — the one it is registered on.
|
|
173
|
+
// Refusing it with "No machine matches" sent the user to a different
|
|
174
|
+
// command without saying which (OSK-9313).
|
|
175
|
+
(m.harnesses ?? []).some((h) => h.id === needle));
|
|
125
176
|
if (exact.length === 1)
|
|
126
177
|
return exact[0];
|
|
127
178
|
const byName = machines.filter((m) => m.name?.toLowerCase() === lower);
|
|
128
179
|
if (byName.length === 1)
|
|
129
180
|
return byName[0];
|
|
130
|
-
const prefix = machines.filter((m) => [
|
|
181
|
+
const prefix = machines.filter((m) => [
|
|
182
|
+
m.id,
|
|
183
|
+
m.machineUuid,
|
|
184
|
+
m.stableDaemonId,
|
|
185
|
+
m.daemonId,
|
|
186
|
+
withoutIdentityKind(m.id),
|
|
187
|
+
withoutIdentityKind(m.machineUuid),
|
|
188
|
+
].some((candidate) => candidate && candidate.toLowerCase().startsWith(lower)));
|
|
131
189
|
if (prefix.length === 1)
|
|
132
190
|
return prefix[0];
|
|
133
191
|
if (prefix.length > 1) {
|
|
@@ -140,5 +198,13 @@ function resolveMachineRef(machines, ref) {
|
|
|
140
198
|
throw new Error(`"${ref}" matches ${prefix.length} machines: ${shown.join(', ')}` +
|
|
141
199
|
`${rest > 0 ? `, and ${rest} more` : ''}. Use a longer prefix or the full id.`);
|
|
142
200
|
}
|
|
201
|
+
// A harness id prefix or a harness name is the other `show`'s input. Say so
|
|
202
|
+
// rather than only "no machine", which left the reader to guess that a
|
|
203
|
+
// sibling command takes it (OSK-9313).
|
|
204
|
+
const harnessMatch = machines.some((m) => (m.harnesses ?? []).some((h) => (lower.length >= 4 && h.id.toLowerCase().startsWith(lower)) ||
|
|
205
|
+
(typeof h.name === 'string' && h.name.toLowerCase() === lower)));
|
|
206
|
+
if (harnessMatch) {
|
|
207
|
+
throw new Error(`No machine matches "${ref}", but a harness does. \`skrr harnesses show ${ref}\` takes it.`);
|
|
208
|
+
}
|
|
143
209
|
throw new Error(`No machine matches "${ref}". Run \`skrr machines list\` to see them.`);
|
|
144
210
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { TPlugin } from '@skrr-ai/data-provider';
|
|
2
|
+
/**
|
|
3
|
+
* What an agent turn can call, said where tools are configured.
|
|
4
|
+
*
|
|
5
|
+
* Plugin tools (`agents tools`, `--tools`) and OpenAPI actions
|
|
6
|
+
* (`agents api-actions add`) reach an agent turn through the runtime's
|
|
7
|
+
* `agent-tools` server (OSK-9750, OSK-9754). Two limits remain, and the CLI is
|
|
8
|
+
* where the tool is set up, so it says them there:
|
|
9
|
+
* - image and file plugins save their output through a web request an agent
|
|
10
|
+
* turn does not have, so they are stored but not loaded;
|
|
11
|
+
* - an OAuth action runs only after the user authorizes it once, through a
|
|
12
|
+
* link the agent hands over on its first call.
|
|
13
|
+
*/
|
|
14
|
+
/** The catalog's AGENT column. `?` for a server older than the `agentRuntime` field. */
|
|
15
|
+
export declare function agentRuntimeLabel(tool: Pick<TPlugin, 'agentRuntime'>): string;
|
|
16
|
+
export declare const AGENT_COLUMN_FOOTNOTE: string;
|
|
17
|
+
/** Stored plugin keys the catalog says an agent turn does not load. */
|
|
18
|
+
export declare function pluginKeysNotLoaded(keys: string[], catalog: TPlugin[]): string[];
|
|
19
|
+
export declare function pluginsNotLoadedNotice(keys: string[]): string;
|
|
20
|
+
/** Said after adding an OAuth action, since nothing works until both steps happen. */
|
|
21
|
+
export declare function oauthActionNotice(redirectUrl: string): string;
|
|
22
|
+
/** Split an agent's stored `tools` into plugin keys and OpenAPI action tool names. */
|
|
23
|
+
export declare function splitStoredTools(tools: unknown): {
|
|
24
|
+
plugins: string[];
|
|
25
|
+
actions: string[];
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* After `--tools` is saved: warn about the plugin keys an agent turn will not load.
|
|
29
|
+
*
|
|
30
|
+
* Unknown keys are refused by the server (OSK-9545); this covers the known ones
|
|
31
|
+
* that are stored but skipped. Best effort: a catalog that cannot be read says
|
|
32
|
+
* nothing rather than failing a write that already succeeded.
|
|
33
|
+
*/
|
|
34
|
+
export declare function warnPluginsNotLoaded(tools: unknown, warn: (message: string) => void, fetchCatalog?: () => Promise<TPlugin[]>): Promise<void>;
|