@skrr-ai/cli 0.1.37 → 0.1.39
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/bin/dev-fallback.js +175 -4
- package/dist/base-command.js +46 -2
- package/dist/commands/agents/actions/create.js +18 -7
- package/dist/commands/agents/actions/delete.d.ts +1 -0
- package/dist/commands/agents/actions/delete.js +7 -0
- package/dist/commands/agents/actions/update.js +5 -3
- package/dist/commands/agents/api-actions/add.js +5 -2
- package/dist/commands/agents/api-actions/index.d.ts +11 -0
- package/dist/commands/agents/api-actions/index.js +27 -1
- package/dist/commands/agents/avatar/default/index.d.ts +11 -0
- package/dist/commands/agents/avatar/default/index.js +17 -0
- package/dist/commands/agents/avatar/default/set.d.ts +2 -1
- package/dist/commands/agents/avatar/default/set.js +32 -7
- package/dist/commands/agents/avatar/upload.js +7 -1
- package/dist/commands/agents/categories/delete.js +8 -0
- package/dist/commands/agents/categories/index.d.ts +21 -5
- package/dist/commands/agents/categories/index.js +68 -15
- package/dist/commands/agents/chat.d.ts +21 -0
- package/dist/commands/agents/chat.js +94 -7
- package/dist/commands/agents/create.js +11 -4
- package/dist/commands/agents/list.d.ts +15 -0
- package/dist/commands/agents/list.js +31 -1
- package/dist/commands/agents/scene-background/upload.d.ts +30 -0
- package/dist/commands/agents/scene-background/upload.js +97 -0
- package/dist/commands/agents/show.js +13 -0
- package/dist/commands/agents/tools/calls.d.ts +23 -5
- package/dist/commands/agents/tools/calls.js +81 -18
- package/dist/commands/agents/update.js +15 -5
- package/dist/commands/code/{oversky-agent.d.ts → skrr-agent.d.ts} +3 -3
- package/dist/commands/code/{oversky-agent.js → skrr-agent.js} +11 -8
- package/dist/commands/convos/messages.d.ts +13 -0
- package/dist/commands/convos/messages.js +40 -16
- package/dist/commands/daemon/index.js +8 -1
- package/dist/commands/daemon/logs.d.ts +26 -0
- package/dist/commands/daemon/logs.js +56 -0
- package/dist/commands/daemon/uninstall.js +1 -1
- package/dist/commands/followups/act.js +3 -2
- package/dist/commands/followups/cancel.d.ts +6 -3
- package/dist/commands/followups/cancel.js +16 -6
- package/dist/commands/followups/observability.d.ts +23 -0
- package/dist/commands/followups/observability.js +114 -0
- package/dist/commands/followups/reschedule.js +1 -1
- package/dist/commands/followups/resolve.js +3 -3
- package/dist/commands/followups/show.js +2 -1
- package/dist/commands/followups/watch.js +9 -5
- package/dist/commands/harnesses/forget.js +28 -0
- package/dist/commands/harnesses/install.d.ts +41 -0
- package/dist/commands/harnesses/install.js +165 -0
- package/dist/commands/harnesses/installers.d.ts +45 -0
- package/dist/commands/harnesses/installers.js +155 -0
- package/dist/commands/harnesses/list.d.ts +82 -1
- package/dist/commands/harnesses/list.js +104 -12
- package/dist/commands/harnesses/models.js +10 -1
- package/dist/commands/harnesses/show.d.ts +15 -0
- package/dist/commands/harnesses/show.js +44 -3
- package/dist/commands/harnesses/update.js +1 -1
- package/dist/commands/harnesses/usage.d.ts +25 -0
- package/dist/commands/harnesses/usage.js +24 -2
- package/dist/commands/instructions/status.js +13 -1
- package/dist/commands/machines/dedicated/catalog.js +4 -15
- package/dist/commands/machines/dedicated/create.d.ts +8 -0
- package/dist/commands/machines/dedicated/create.js +63 -2
- package/dist/commands/machines/dedicated/destroy.js +19 -5
- package/dist/commands/machines/dedicated/exec.js +3 -1
- package/dist/commands/machines/dedicated/list.js +9 -6
- package/dist/commands/machines/dedicated/price-book.d.ts +17 -0
- package/dist/commands/machines/dedicated/price-book.js +35 -0
- package/dist/commands/machines/hosted/list.js +12 -0
- package/dist/commands/machines/list.js +11 -0
- package/dist/commands/machines/show.d.ts +1 -0
- package/dist/commands/machines/show.js +40 -11
- package/dist/commands/profiles/list.d.ts +23 -0
- package/dist/commands/profiles/list.js +96 -0
- package/dist/commands/search/skills.d.ts +11 -1
- package/dist/commands/search/skills.js +26 -8
- package/dist/commands/skills/details.d.ts +2 -0
- package/dist/commands/skills/details.js +24 -1
- package/dist/commands/skills/import-as-actions.d.ts +32 -0
- package/dist/commands/skills/import-as-actions.js +175 -0
- package/dist/commands/skills/install.d.ts +2 -0
- package/dist/commands/skills/install.js +24 -1
- package/dist/commands/skills/invocable.js +6 -2
- package/dist/commands/skills/local.d.ts +40 -0
- package/dist/commands/skills/local.js +160 -0
- package/dist/commands/skills/search.d.ts +11 -1
- package/dist/commands/skills/search.js +29 -8
- package/dist/commands/spaces/actions/add.js +23 -5
- package/dist/commands/spaces/actions/available.js +3 -0
- package/dist/commands/spaces/actions/list.d.ts +5 -0
- package/dist/commands/spaces/actions/list.js +49 -3
- package/dist/commands/spaces/actions/run.d.ts +28 -0
- package/dist/commands/spaces/actions/run.js +146 -0
- package/dist/commands/spaces/actions/update.js +27 -5
- package/dist/commands/spaces/label-summaries.d.ts +27 -0
- package/dist/commands/spaces/label-summaries.js +64 -0
- package/dist/commands/spaces/task-rollups.d.ts +5 -0
- package/dist/commands/spaces/task-rollups.js +15 -4
- package/dist/commands/spaces/workflows/lifecycle-diagnostics.js +63 -3
- package/dist/commands/tasks/actions/attach.js +32 -7
- package/dist/commands/tasks/complete.js +13 -0
- package/dist/commands/tasks/create.js +1 -1
- package/dist/commands/tasks/events/append.js +29 -6
- package/dist/commands/tasks/expectations/assess.d.ts +1 -0
- package/dist/commands/tasks/expectations/assess.js +43 -5
- package/dist/commands/tasks/expectations.js +77 -16
- package/dist/commands/tasks/follow-up.js +2 -2
- package/dist/commands/tasks/lifecycle/definitions.js +21 -2
- package/dist/commands/tasks/lifecycle/detach.d.ts +7 -0
- package/dist/commands/tasks/lifecycle/detach.js +43 -3
- package/dist/commands/tasks/lifecycle/migrate.d.ts +2 -0
- package/dist/commands/tasks/lifecycle/migrate.js +42 -3
- package/dist/commands/tasks/lifecycle/reopen.d.ts +2 -0
- package/dist/commands/tasks/lifecycle/reopen.js +40 -3
- package/dist/commands/tasks/lifecycle/transition.js +33 -2
- package/dist/commands/tasks/list.js +16 -9
- package/dist/commands/tasks/move.js +11 -13
- package/dist/commands/tasks/review-queue.d.ts +15 -0
- package/dist/commands/tasks/review-queue.js +180 -31
- package/dist/commands/tasks/show.d.ts +11 -0
- package/dist/commands/tasks/show.js +105 -12
- package/dist/commands/tasks/trust.js +7 -2
- package/dist/commands/tasks/update.js +46 -10
- package/dist/commands/tasks/updates/add.js +1 -1
- package/dist/commands/token/list.d.ts +22 -0
- package/dist/commands/token/list.js +68 -0
- package/dist/commands/token/revoke.d.ts +23 -0
- package/dist/commands/token/revoke.js +53 -0
- package/dist/lib/agent-actions.d.ts +57 -2
- package/dist/lib/agent-actions.js +113 -21
- package/dist/lib/agent-pin-mute.d.ts +10 -5
- package/dist/lib/agent-pin-mute.js +17 -4
- package/dist/lib/agent-visual-refs.d.ts +27 -0
- package/dist/lib/agent-visual-refs.js +127 -2
- package/dist/lib/agentic-stream.d.ts +6 -0
- package/dist/lib/agentic-stream.js +34 -3
- package/dist/lib/assignee-resolver.d.ts +1 -1
- package/dist/lib/assignee-resolver.js +8 -0
- package/dist/lib/bulk-task-targets.d.ts +12 -0
- package/dist/lib/bulk-task-targets.js +34 -1
- package/dist/lib/cli-installers.d.ts +130 -0
- package/dist/lib/cli-installers.js +145 -0
- package/dist/lib/command-miss.js +55 -7
- package/dist/lib/dedicated-lease-command.d.ts +16 -1
- package/dist/lib/dedicated-lease-command.js +26 -3
- package/dist/lib/dedicated-machines.d.ts +135 -1
- package/dist/lib/dedicated-machines.js +307 -3
- package/dist/lib/failed-lookup.d.ts +3 -0
- package/dist/lib/failed-lookup.js +40 -0
- package/dist/lib/first-party-harness-agent.js +9 -2
- package/dist/lib/first-party-harness-doctor.d.ts +15 -0
- package/dist/lib/first-party-harness-doctor.js +126 -27
- package/dist/lib/followups.d.ts +14 -6
- package/dist/lib/followups.js +31 -6
- package/dist/lib/harnesses.d.ts +8 -0
- package/dist/lib/instruction-input.d.ts +19 -1
- package/dist/lib/instruction-input.js +52 -1
- package/dist/lib/label-scope.d.ts +15 -0
- package/dist/lib/label-scope.js +25 -5
- package/dist/lib/local-skills.d.ts +98 -0
- package/dist/lib/local-skills.js +195 -0
- package/dist/lib/machines.d.ts +10 -10
- package/dist/lib/machines.js +23 -1
- package/dist/lib/search-query.d.ts +19 -0
- package/dist/lib/search-query.js +35 -0
- package/dist/lib/space-custom-actions.d.ts +72 -0
- package/dist/lib/space-custom-actions.js +117 -0
- package/dist/lib/space-resolver.d.ts +1 -21
- package/dist/lib/space-resolver.js +19 -10
- package/dist/lib/task-closure.d.ts +3 -2
- package/dist/lib/task-closure.js +18 -20
- package/dist/lib/task-lifecycle-output.js +117 -9
- package/dist/lib/task-ref-resolver.d.ts +1 -17
- package/dist/lib/task-ref-resolver.js +18 -8
- package/dist/lib/tasks.js +9 -3
- package/dist/node_modules/@skrr-ai/data-provider/index.js +5076 -4947
- package/oclif.manifest.json +15505 -14460
- package/package.json +9 -3
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const core_1 = require("@oclif/core");
|
|
4
|
+
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
4
5
|
const base_command_1 = require("../../base-command");
|
|
5
6
|
const followups_1 = require("../../lib/followups");
|
|
6
7
|
const agent_resolver_1 = require("../../lib/agent-resolver");
|
|
@@ -12,13 +13,13 @@ const triggers_1 = require("../../lib/triggers");
|
|
|
12
13
|
class FollowupsAct extends base_command_1.BaseCommand {
|
|
13
14
|
static description = 'Run an agreed action at a time — the act follow-up';
|
|
14
15
|
static examples = [
|
|
15
|
-
'<%= config.bin %> followups act --subject task:OSK-42 --why "user approved the merge" --action \'{"builtinType":"
|
|
16
|
+
'<%= config.bin %> followups act --subject task:OSK-42 --why "user approved the merge" --action \'{"builtinType":"task_mark_done","config":{"taskId":"OSK-42"}}\' --at 2026-09-20T09:00:00Z',
|
|
16
17
|
];
|
|
17
18
|
static flags = {
|
|
18
19
|
subject: core_1.Flags.string({ description: 'Subject ref: type:externalKey', required: true }),
|
|
19
20
|
why: core_1.Flags.string({ description: 'Why this wake exists, in one line', required: true }),
|
|
20
21
|
action: core_1.Flags.string({
|
|
21
|
-
description:
|
|
22
|
+
description: `Action payload JSON: {"builtinType": "...", "config": {...}, "refId?": "..."}. builtinType is one of: ${data_provider_1.BUILTIN_ACTION_TYPES.join(', ')}`,
|
|
22
23
|
required: true,
|
|
23
24
|
}),
|
|
24
25
|
at: core_1.Flags.string({ description: 'ISO-8601 instant to act at', exclusive: ['in'] }),
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { BaseCommand } from '../../base-command';
|
|
2
2
|
/**
|
|
3
|
-
* `skrr followups cancel <id>` —
|
|
4
|
-
*
|
|
5
|
-
* the
|
|
3
|
+
* `skrr followups cancel <id>` — "never mind". It records exactly what
|
|
4
|
+
* `resolve --outcome abandoned` records (terminal `abandoned`, the reason as
|
|
5
|
+
* the note); it exists so calling one off does not require knowing the
|
|
6
|
+
* terminal vocabulary. Neither help text used to say so, and a user had to
|
|
7
|
+
* read the service to choose between them (OSK-9679).
|
|
6
8
|
*/
|
|
7
9
|
export default class FollowupsCancel extends BaseCommand {
|
|
8
10
|
static description: string;
|
|
11
|
+
static examples: string[];
|
|
9
12
|
static args: {
|
|
10
13
|
id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
11
14
|
};
|
|
@@ -4,17 +4,27 @@ const core_1 = require("@oclif/core");
|
|
|
4
4
|
const base_command_1 = require("../../base-command");
|
|
5
5
|
const followups_1 = require("../../lib/followups");
|
|
6
6
|
/**
|
|
7
|
-
* `skrr followups cancel <id>` —
|
|
8
|
-
*
|
|
9
|
-
* the
|
|
7
|
+
* `skrr followups cancel <id>` — "never mind". It records exactly what
|
|
8
|
+
* `resolve --outcome abandoned` records (terminal `abandoned`, the reason as
|
|
9
|
+
* the note); it exists so calling one off does not require knowing the
|
|
10
|
+
* terminal vocabulary. Neither help text used to say so, and a user had to
|
|
11
|
+
* read the service to choose between them (OSK-9679).
|
|
10
12
|
*/
|
|
11
13
|
class FollowupsCancel extends base_command_1.BaseCommand {
|
|
12
|
-
static description = '
|
|
14
|
+
static description = 'Call off a follow-up you no longer want (same record as resolve --outcome abandoned)';
|
|
15
|
+
static examples = [
|
|
16
|
+
'<%= config.bin %> followups cancel fu_abc',
|
|
17
|
+
'<%= config.bin %> followups cancel fu_abc --reason "handled it by hand"',
|
|
18
|
+
'# If what you were waiting for happened, record that instead:',
|
|
19
|
+
'<%= config.bin %> followups resolve fu_abc --outcome resolved',
|
|
20
|
+
];
|
|
13
21
|
static args = {
|
|
14
|
-
id:
|
|
22
|
+
id: followups_1.followUpIdArg,
|
|
15
23
|
};
|
|
16
24
|
static flags = {
|
|
17
|
-
reason: core_1.Flags.string({
|
|
25
|
+
reason: core_1.Flags.string({
|
|
26
|
+
description: 'Why it is being called off — stored as the note (default: "cancelled")',
|
|
27
|
+
}),
|
|
18
28
|
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
19
29
|
};
|
|
20
30
|
async run() {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base-command';
|
|
2
|
+
/**
|
|
3
|
+
* `skrr followups observability` — how follow-ups are doing, per (agent, kind).
|
|
4
|
+
*
|
|
5
|
+
* `list` answers "what is still owed", one row per follow-up. This answers the
|
|
6
|
+
* question a page of rows cannot: how many were created, how they ended, how
|
|
7
|
+
* often they escalated, today's budget, and how often a check-in chose to stay
|
|
8
|
+
* quiet. The API served this rollup from the day the service shipped and no
|
|
9
|
+
* command reached it (OSK-9678).
|
|
10
|
+
*
|
|
11
|
+
* Scope follows `list`: one agent by default (the session's, or `--agent`),
|
|
12
|
+
* every agent only with `--all-agents`.
|
|
13
|
+
*/
|
|
14
|
+
export default class FollowupsObservability extends BaseCommand {
|
|
15
|
+
static description: string;
|
|
16
|
+
static examples: string[];
|
|
17
|
+
static flags: {
|
|
18
|
+
agent: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
19
|
+
'all-agents': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
20
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
21
|
+
};
|
|
22
|
+
run(): Promise<void>;
|
|
23
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
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 format_1 = require("../../lib/format");
|
|
6
|
+
const followups_1 = require("../../lib/followups");
|
|
7
|
+
const agent_resolver_1 = require("../../lib/agent-resolver");
|
|
8
|
+
const rate = (value) => value === null ? '—' : `${Math.round(value * 100)}%`;
|
|
9
|
+
/** `resolved 3 · abandoned 1` — the outcomes that happened, not five zeros. */
|
|
10
|
+
const outcomes = (terminal) => Object.entries(terminal)
|
|
11
|
+
.filter(([, count]) => count > 0)
|
|
12
|
+
.map(([outcome, count]) => `${outcome} ${count}`)
|
|
13
|
+
.join(' · ') || '—';
|
|
14
|
+
/**
|
|
15
|
+
* `skrr followups observability` — how follow-ups are doing, per (agent, kind).
|
|
16
|
+
*
|
|
17
|
+
* `list` answers "what is still owed", one row per follow-up. This answers the
|
|
18
|
+
* question a page of rows cannot: how many were created, how they ended, how
|
|
19
|
+
* often they escalated, today's budget, and how often a check-in chose to stay
|
|
20
|
+
* quiet. The API served this rollup from the day the service shipped and no
|
|
21
|
+
* command reached it (OSK-9678).
|
|
22
|
+
*
|
|
23
|
+
* Scope follows `list`: one agent by default (the session's, or `--agent`),
|
|
24
|
+
* every agent only with `--all-agents`.
|
|
25
|
+
*/
|
|
26
|
+
class FollowupsObservability extends base_command_1.BaseCommand {
|
|
27
|
+
static description = 'Per-agent, per-kind rollup — created, outcomes, escalation, budget, check-in silence';
|
|
28
|
+
static examples = [
|
|
29
|
+
'<%= config.bin %> followups observability',
|
|
30
|
+
'<%= config.bin %> followups observability --agent agent_1',
|
|
31
|
+
'<%= config.bin %> followups observability --all-agents --json',
|
|
32
|
+
];
|
|
33
|
+
static flags = {
|
|
34
|
+
agent: core_1.Flags.string({
|
|
35
|
+
description: 'Agent ID (default: bound session agent)',
|
|
36
|
+
exclusive: ['all-agents'],
|
|
37
|
+
}),
|
|
38
|
+
'all-agents': core_1.Flags.boolean({
|
|
39
|
+
description: 'Roll up every agent — the human view',
|
|
40
|
+
exclusive: ['agent'],
|
|
41
|
+
default: false,
|
|
42
|
+
}),
|
|
43
|
+
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
44
|
+
};
|
|
45
|
+
async run() {
|
|
46
|
+
this.requireAuth();
|
|
47
|
+
const { flags } = await this.parse(FollowupsObservability);
|
|
48
|
+
let agentId;
|
|
49
|
+
if (!flags['all-agents']) {
|
|
50
|
+
try {
|
|
51
|
+
agentId = (0, followups_1.resolveFollowUpAgent)(flags.agent).id;
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
const failure = (0, agent_resolver_1.agentResolutionFailure)(err);
|
|
55
|
+
this.failWithCliError({
|
|
56
|
+
message: failure.message,
|
|
57
|
+
code: failure.code,
|
|
58
|
+
exit: 2,
|
|
59
|
+
retryable: false,
|
|
60
|
+
details: { suggestion: failure.suggestion, context: failure.details },
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
let report;
|
|
65
|
+
try {
|
|
66
|
+
report = await followups_1.followupsApi.observability(agentId ? { agentId } : {});
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
this.handleApiError(err);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
if (flags.json) {
|
|
73
|
+
this.log(JSON.stringify(report, null, 2));
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const agents = (report.agents ?? []).filter((agent) => agent.kinds.length > 0);
|
|
77
|
+
if (agents.length === 0) {
|
|
78
|
+
this.log('No follow-ups.');
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
// One heading per agent rather than an AGENT column: an agent id repeated
|
|
82
|
+
// on every row pushed the table past any normal terminal width.
|
|
83
|
+
agents.forEach((agent, index) => {
|
|
84
|
+
if (index > 0)
|
|
85
|
+
this.log('');
|
|
86
|
+
this.log(agent.agentId === 'user' ? 'user (reminders with no agent)' : agent.agentId);
|
|
87
|
+
(0, format_1.renderTable)(agent.kinds.map((kind) => ({
|
|
88
|
+
kind: kind.kind,
|
|
89
|
+
created: String(kind.created),
|
|
90
|
+
open: String(kind.armed),
|
|
91
|
+
proposed: String(kind.proposed),
|
|
92
|
+
settled: String(kind.settled),
|
|
93
|
+
outcomes: outcomes(kind.terminal),
|
|
94
|
+
escalated: rate(kind.escalationRate),
|
|
95
|
+
fires: String(kind.fires),
|
|
96
|
+
budget: kind.budget ? `${kind.budget.used}/${kind.budget.limit ?? '∞'}` : '—',
|
|
97
|
+
silence: rate(kind.silenceRate),
|
|
98
|
+
})), [
|
|
99
|
+
{ key: 'kind', header: 'KIND' },
|
|
100
|
+
{ key: 'created', header: 'CREATED' },
|
|
101
|
+
{ key: 'open', header: 'OPEN' },
|
|
102
|
+
{ key: 'proposed', header: 'PROPOSED' },
|
|
103
|
+
{ key: 'settled', header: 'SETTLED' },
|
|
104
|
+
{ key: 'outcomes', header: 'OUTCOMES' },
|
|
105
|
+
{ key: 'escalated', header: 'ESCALATED' },
|
|
106
|
+
{ key: 'fires', header: 'FIRES' },
|
|
107
|
+
{ key: 'budget', header: 'TODAY/LIMIT' },
|
|
108
|
+
{ key: 'silence', header: 'SILENT' },
|
|
109
|
+
], (line) => this.log(line));
|
|
110
|
+
});
|
|
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.`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
exports.default = FollowupsObservability;
|
|
@@ -11,7 +11,7 @@ class FollowupsReschedule extends base_command_1.BaseCommand {
|
|
|
11
11
|
'<%= config.bin %> followups reschedule fu_abc --at 2026-09-20T09:00:00Z',
|
|
12
12
|
];
|
|
13
13
|
static args = {
|
|
14
|
-
id:
|
|
14
|
+
id: followups_1.followUpIdArg,
|
|
15
15
|
};
|
|
16
16
|
static flags = {
|
|
17
17
|
at: core_1.Flags.string({ description: 'New instant (ISO-8601)', exclusive: ['in'] }),
|
|
@@ -13,13 +13,13 @@ const followups_1 = require("../../lib/followups");
|
|
|
13
13
|
* are not accepted here.
|
|
14
14
|
*/
|
|
15
15
|
class FollowupsResolve extends base_command_1.BaseCommand {
|
|
16
|
-
static description = 'Settle a follow-up with its honest outcome';
|
|
16
|
+
static description = 'Settle a follow-up with its honest outcome — resolved (it paid off) or abandoned (never mind; `cancel` is the shortcut)';
|
|
17
17
|
static examples = [
|
|
18
18
|
'<%= config.bin %> followups resolve fu_abc --outcome resolved --note "the deploy landed"',
|
|
19
|
-
'<%= config.bin %> followups resolve fu_abc --outcome abandoned',
|
|
19
|
+
'<%= config.bin %> followups resolve fu_abc --outcome abandoned --note "no longer needed"',
|
|
20
20
|
];
|
|
21
21
|
static args = {
|
|
22
|
-
id:
|
|
22
|
+
id: followups_1.followUpIdArg,
|
|
23
23
|
};
|
|
24
24
|
static flags = {
|
|
25
25
|
outcome: core_1.Flags.string({
|
|
@@ -7,7 +7,7 @@ const followups_1 = require("../../lib/followups");
|
|
|
7
7
|
class FollowupsShow extends base_command_1.BaseCommand {
|
|
8
8
|
static description = 'Show one follow-up';
|
|
9
9
|
static args = {
|
|
10
|
-
id:
|
|
10
|
+
id: followups_1.followUpIdArg,
|
|
11
11
|
};
|
|
12
12
|
static flags = {
|
|
13
13
|
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
@@ -30,6 +30,7 @@ class FollowupsShow extends base_command_1.BaseCommand {
|
|
|
30
30
|
const row = response.followup;
|
|
31
31
|
this.log((0, followups_1.followupSummaryLine)(row));
|
|
32
32
|
for (const [label, value] of [
|
|
33
|
+
['says', row.content],
|
|
33
34
|
['why', row.why],
|
|
34
35
|
['intent', row.intentKey],
|
|
35
36
|
['producer', row.producer],
|
|
@@ -23,9 +23,9 @@ const triggers_1 = require("../../lib/triggers");
|
|
|
23
23
|
class FollowupsWatch extends base_command_1.BaseCommand {
|
|
24
24
|
static description = 'Watch an asynchronous tail until it settles — the watch follow-up';
|
|
25
25
|
static examples = [
|
|
26
|
-
'<%= config.bin %> followups watch --subject task:OSK-42 --why "deploy still running" --url https://ci.example.com/api/build/9 --until \'{"
|
|
27
|
-
'<%= 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
|
|
28
|
-
'<%= config.bin %> followups watch --subject
|
|
26
|
+
'<%= 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
|
+
'<%= 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',
|
|
28
|
+
'<%= config.bin %> followups watch --subject conversation:abc --why "vendor reply" --check "check inbox" --success "reply arrived" --abort "3 days" --wait clock --wait-at 2026-09-20T09:00:00Z',
|
|
29
29
|
];
|
|
30
30
|
static flags = {
|
|
31
31
|
subject: core_1.Flags.string({ description: 'Subject ref: type:externalKey', required: true }),
|
|
@@ -33,7 +33,9 @@ class FollowupsWatch extends base_command_1.BaseCommand {
|
|
|
33
33
|
agent: core_1.Flags.string({ description: 'Agent ID (default: bound session agent)' }),
|
|
34
34
|
// predicate form
|
|
35
35
|
url: core_1.Flags.string({ description: 'HTTPS endpoint to observe (predicate form)' }),
|
|
36
|
-
until: core_1.Flags.string({
|
|
36
|
+
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',
|
|
38
|
+
}),
|
|
37
39
|
grant: core_1.Flags.string({ description: 'Grant id supplying the watch credentials' }),
|
|
38
40
|
deadline: core_1.Flags.string({ description: 'When the watch must stop (predicate form, required)' }),
|
|
39
41
|
'check-every': core_1.Flags.string({ description: 'Observation interval (predicate form)' }),
|
|
@@ -59,7 +61,9 @@ class FollowupsWatch extends base_command_1.BaseCommand {
|
|
|
59
61
|
'wait-filter-value': core_1.Flags.string({ description: 'Event filter value' }),
|
|
60
62
|
'wait-interval-seconds': core_1.Flags.integer({ description: 'Poll interval for --wait poll_until' }),
|
|
61
63
|
'wait-max-attempts': core_1.Flags.integer({ description: 'Attempt cap for --wait poll_until' }),
|
|
62
|
-
'wait-fallback': core_1.Flags.string({
|
|
64
|
+
'wait-fallback': core_1.Flags.string({
|
|
65
|
+
description: 'SLA backstop — required for --wait event (an event may never arrive), optional for poll_until',
|
|
66
|
+
}),
|
|
63
67
|
// delivery
|
|
64
68
|
endpoint: core_1.Flags.string({ description: 'Delivery endpoint id (EndpointRegistry)' }),
|
|
65
69
|
'endpoint-target': core_1.Flags.string({ description: 'Channel target for channel endpoints' }),
|
|
@@ -3,6 +3,8 @@ 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 harnesses_1 = require("../../lib/harnesses");
|
|
6
|
+
const api_fetch_1 = require("../../lib/api-fetch");
|
|
7
|
+
const show_1 = require("./show");
|
|
6
8
|
/**
|
|
7
9
|
* Forget an harness — `forget`, not `delete`.
|
|
8
10
|
*
|
|
@@ -26,6 +28,24 @@ class HarnessesForget extends base_command_1.BaseCommand {
|
|
|
26
28
|
async run() {
|
|
27
29
|
this.requireAuth();
|
|
28
30
|
const { args, flags } = await this.parse(HarnessesForget);
|
|
31
|
+
// Refuse a reference that cannot name a harness BEFORE asking anything.
|
|
32
|
+
//
|
|
33
|
+
// The confirmation used to run first, so `harnesses forget notanid` asked
|
|
34
|
+
// whether to delete something that could never exist, and a scripted caller
|
|
35
|
+
// who added `--yes` to get past it then hit a second, different failure:
|
|
36
|
+
// a bare `Invalid harness ID / HTTP_400` from the server. Two round trips
|
|
37
|
+
// for one typo, on the command where a typo matters most.
|
|
38
|
+
//
|
|
39
|
+
// The sibling `harnesses show` already explains this class of mistake
|
|
40
|
+
// (`describeWrongHarnessRef` names which KIND of id you passed and which
|
|
41
|
+
// command takes it). `forget` is the DESTRUCTIVE one and had the worse
|
|
42
|
+
// message; it now shares the explanation.
|
|
43
|
+
if (!/^[0-9a-f]{24}$/i.test(args.harness.trim())) {
|
|
44
|
+
this.error(`Not a harness id: ${args.harness}\n${(0, show_1.describeWrongHarnessRef)(args.harness)}`, {
|
|
45
|
+
exit: 1,
|
|
46
|
+
});
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
29
49
|
// Name it before removing it. An id alone does not tell the operator which
|
|
30
50
|
// of their machines they are about to drop from the fleet.
|
|
31
51
|
if (!flags.yes) {
|
|
@@ -52,6 +72,14 @@ class HarnessesForget extends base_command_1.BaseCommand {
|
|
|
52
72
|
this.log(`Forgot ${args.harness}.`);
|
|
53
73
|
}
|
|
54
74
|
catch (err) {
|
|
75
|
+
// A well-formed id the server still rejects: say so in the same words
|
|
76
|
+
// `show` uses, rather than relaying `Invalid harness ID`.
|
|
77
|
+
if (err instanceof api_fetch_1.ApiFetchError && err.status === 400) {
|
|
78
|
+
this.error(`Not a harness id: ${args.harness}\n${(0, show_1.describeWrongHarnessRef)(args.harness)}`, {
|
|
79
|
+
exit: 1,
|
|
80
|
+
});
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
55
83
|
this.handleApiError(err);
|
|
56
84
|
}
|
|
57
85
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base-command';
|
|
2
|
+
/**
|
|
3
|
+
* Install one managed coding-agent CLI on a machine.
|
|
4
|
+
*
|
|
5
|
+
* ## Why this did not exist
|
|
6
|
+
*
|
|
7
|
+
* The daemon has installed any of seven providers since `d878b79581`, and
|
|
8
|
+
* `POST /api/daemons/:id/cli-installers/:provider/install` is the request the
|
|
9
|
+
* web app's Install button sends. From the CLI only ONE of them was reachable:
|
|
10
|
+
* `skrr code install`, whose provider is a constant. Everything else had to be
|
|
11
|
+
* installed by hand, or from the web app.
|
|
12
|
+
*
|
|
13
|
+
* `skrr harnesses install-token` made that worse rather than neutral. It is the
|
|
14
|
+
* only entry in `harnesses --help` with "install" in its name, so a user
|
|
15
|
+
* scanning for "how do I install a harness" lands on it — and it mints a daemon
|
|
16
|
+
* enrolment token for another machine, which is a different thing entirely.
|
|
17
|
+
*
|
|
18
|
+
* ## The provider name is validated here, against the shared vocabulary
|
|
19
|
+
*
|
|
20
|
+
* Unlike `harnesses list --provider`, where the set is open because a daemon
|
|
21
|
+
* registers a row per capability it detects, the INSTALLABLE set is closed and
|
|
22
|
+
* owned: `MANAGED_CLI_PROVIDER_IDS` in `@skrr-ai/data-provider`, which the
|
|
23
|
+
* daemon's own list is pinned against by `managedCliProviders.spec.ts`. So a
|
|
24
|
+
* typo can be rejected with the real options, rather than sent to the daemon to
|
|
25
|
+
* come back as an opaque refusal.
|
|
26
|
+
*/
|
|
27
|
+
export default class HarnessesInstall extends BaseCommand {
|
|
28
|
+
static description: string;
|
|
29
|
+
static examples: string[];
|
|
30
|
+
static args: {
|
|
31
|
+
provider: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
32
|
+
};
|
|
33
|
+
static flags: {
|
|
34
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
35
|
+
daemon: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
36
|
+
};
|
|
37
|
+
run(): Promise<void>;
|
|
38
|
+
/** What the daemon says about this provider right now, best effort. */
|
|
39
|
+
private installerNote;
|
|
40
|
+
private daemonIdFor;
|
|
41
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
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
|
+
const cli_installers_1 = require("../../lib/cli-installers");
|
|
7
|
+
const daemon_ref_1 = require("../../lib/daemon-ref");
|
|
8
|
+
const daemon_target_1 = require("../../lib/daemon-target");
|
|
9
|
+
/**
|
|
10
|
+
* Install one managed coding-agent CLI on a machine.
|
|
11
|
+
*
|
|
12
|
+
* ## Why this did not exist
|
|
13
|
+
*
|
|
14
|
+
* The daemon has installed any of seven providers since `d878b79581`, and
|
|
15
|
+
* `POST /api/daemons/:id/cli-installers/:provider/install` is the request the
|
|
16
|
+
* web app's Install button sends. From the CLI only ONE of them was reachable:
|
|
17
|
+
* `skrr code install`, whose provider is a constant. Everything else had to be
|
|
18
|
+
* installed by hand, or from the web app.
|
|
19
|
+
*
|
|
20
|
+
* `skrr harnesses install-token` made that worse rather than neutral. It is the
|
|
21
|
+
* only entry in `harnesses --help` with "install" in its name, so a user
|
|
22
|
+
* scanning for "how do I install a harness" lands on it — and it mints a daemon
|
|
23
|
+
* enrolment token for another machine, which is a different thing entirely.
|
|
24
|
+
*
|
|
25
|
+
* ## The provider name is validated here, against the shared vocabulary
|
|
26
|
+
*
|
|
27
|
+
* Unlike `harnesses list --provider`, where the set is open because a daemon
|
|
28
|
+
* registers a row per capability it detects, the INSTALLABLE set is closed and
|
|
29
|
+
* owned: `MANAGED_CLI_PROVIDER_IDS` in `@skrr-ai/data-provider`, which the
|
|
30
|
+
* daemon's own list is pinned against by `managedCliProviders.spec.ts`. So a
|
|
31
|
+
* typo can be rejected with the real options, rather than sent to the daemon to
|
|
32
|
+
* come back as an opaque refusal.
|
|
33
|
+
*/
|
|
34
|
+
class HarnessesInstall extends base_command_1.BaseCommand {
|
|
35
|
+
static description = 'Install a managed coding-agent CLI (claude, codex, devin, …) on one of your machines';
|
|
36
|
+
static examples = [
|
|
37
|
+
'<%= config.bin %> harnesses install devin',
|
|
38
|
+
'<%= config.bin %> harnesses install codex --daemon daemon_07c086e3c249_cli_default',
|
|
39
|
+
];
|
|
40
|
+
static args = {
|
|
41
|
+
provider: core_1.Args.string({
|
|
42
|
+
ignoreStdin: true,
|
|
43
|
+
required: true,
|
|
44
|
+
description: `Which CLI to install (${data_provider_1.MANAGED_CLI_PROVIDER_IDS.join(', ')})`,
|
|
45
|
+
}),
|
|
46
|
+
};
|
|
47
|
+
static flags = {
|
|
48
|
+
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
49
|
+
daemon: core_1.Flags.string({
|
|
50
|
+
description: 'Which machine to install on. Defaults to your only active daemon; required when several are active.',
|
|
51
|
+
}),
|
|
52
|
+
};
|
|
53
|
+
async run() {
|
|
54
|
+
this.requireAuth();
|
|
55
|
+
const { args, flags } = await this.parse(HarnessesInstall);
|
|
56
|
+
// Case-insensitive, and every accepted spelling of the first-party harness
|
|
57
|
+
// resolves to its canonical id — the same normalization the route applies.
|
|
58
|
+
const provider = (0, data_provider_1.normalizeManagedCliProvider)(args.provider);
|
|
59
|
+
if (!provider) {
|
|
60
|
+
this.error(`"${args.provider}" is not a managed CLI provider. Installable: ${data_provider_1.MANAGED_CLI_PROVIDER_IDS.join(', ')}.`, { exit: 2 });
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const target = await (0, daemon_target_1.resolveDaemonTarget)({
|
|
64
|
+
explicit: flags.daemon,
|
|
65
|
+
local: (0, daemon_target_1.localMachine)(),
|
|
66
|
+
listActiveDaemons: () => (0, daemon_target_1.listActiveDaemons)(this.resolvedCredential),
|
|
67
|
+
});
|
|
68
|
+
const daemonId = this.daemonIdFor(target);
|
|
69
|
+
let start;
|
|
70
|
+
try {
|
|
71
|
+
start = await (0, cli_installers_1.startManagedCliInstall)(daemonId, provider, this.resolvedCredential);
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
this.handleApiError(err);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const jobId = start.job?.id;
|
|
78
|
+
if (!start.started || !jobId) {
|
|
79
|
+
// The daemon declined and already knows why. Read its own reason off the
|
|
80
|
+
// provider state rather than inventing an explanation for the silence —
|
|
81
|
+
// "Already installed." and "Not available on this platform." want very
|
|
82
|
+
// different responses, and a generic "install failed" hides both.
|
|
83
|
+
const reason = start.provider?.installDisabledReason?.trim() ||
|
|
84
|
+
(await this.installerNote(daemonId, provider));
|
|
85
|
+
this.log(reason ? `${provider}: ${reason}` : `${provider}: the daemon started no install job.`);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
if (!flags.json)
|
|
89
|
+
this.logToStderr(`Installing ${provider} on ${(0, daemon_ref_1.formatDaemonRef)(daemonId)}…`);
|
|
90
|
+
const outcome = await (0, cli_installers_1.followManagedCliInstallJob)({
|
|
91
|
+
daemonId,
|
|
92
|
+
jobId,
|
|
93
|
+
credential: this.resolvedCredential,
|
|
94
|
+
onLogLine: flags.json ? undefined : (line) => this.logToStderr(` ${line}`),
|
|
95
|
+
});
|
|
96
|
+
if (outcome.kind === 'missing') {
|
|
97
|
+
this.error(`The daemon no longer has install job ${jobId}.`, { exit: 1 });
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (outcome.kind === 'timeout') {
|
|
101
|
+
// Not a failure: the daemon is still working, and calling this failed
|
|
102
|
+
// would send someone to debug a download that is going fine.
|
|
103
|
+
this.error(`Still installing after ${Math.round(cli_installers_1.INSTALL_MAX_WAIT_MS / 60000)} minutes — the daemon is still working on job ${jobId}. Check \`${this.config.bin} harnesses installers\` in a while.`, { exit: 1 });
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
const job = outcome.job;
|
|
107
|
+
if (flags.json) {
|
|
108
|
+
this.log(JSON.stringify({ daemonId, provider, job }, null, 2));
|
|
109
|
+
if (job.status !== 'succeeded')
|
|
110
|
+
process.exitCode = 1;
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
if (job.status === 'failed') {
|
|
114
|
+
this.error(`Installing ${provider} failed: ${job.error || 'the daemon gave no reason.'}`, {
|
|
115
|
+
exit: 1,
|
|
116
|
+
});
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
// Report the state the install actually produced, not "done". Installing a
|
|
120
|
+
// binary is not the same as being able to run it: Devin lands
|
|
121
|
+
// `interactive-required`, and a user told only "installed" would find that
|
|
122
|
+
// out on their first turn instead.
|
|
123
|
+
const state = await this.installerNote(daemonId, provider, true);
|
|
124
|
+
this.log(`${provider} installed.${state ? ` ${state}` : ''}`);
|
|
125
|
+
}
|
|
126
|
+
/** What the daemon says about this provider right now, best effort. */
|
|
127
|
+
async installerNote(daemonId, provider, readiness = false) {
|
|
128
|
+
try {
|
|
129
|
+
const res = await (0, cli_installers_1.listCliInstallers)(daemonId, this.resolvedCredential);
|
|
130
|
+
const row = (res.providers ?? []).find((p) => (0, data_provider_1.normalizeManagedCliProvider)(p.provider) === provider);
|
|
131
|
+
if (!row)
|
|
132
|
+
return null;
|
|
133
|
+
if (readiness) {
|
|
134
|
+
const verdict = (0, cli_installers_1.readinessOf)(row);
|
|
135
|
+
return `${verdict.label}: ${verdict.detail}`;
|
|
136
|
+
}
|
|
137
|
+
const reason = row.installDisabledReason?.trim();
|
|
138
|
+
if (!reason)
|
|
139
|
+
return null;
|
|
140
|
+
return row.version ? `${reason} (${row.version})` : reason;
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
daemonIdFor(target) {
|
|
147
|
+
if (target.kind === 'daemon')
|
|
148
|
+
return target.daemonId;
|
|
149
|
+
if (target.kind === 'this-machine') {
|
|
150
|
+
if (target.daemonId)
|
|
151
|
+
return target.daemonId;
|
|
152
|
+
this.error('This machine is a Dedicated Runtime whose daemon has not published an id this process can read. Name a machine with --daemon.', { exit: 1 });
|
|
153
|
+
}
|
|
154
|
+
if (target.kind === 'none') {
|
|
155
|
+
this.error(`No active daemon is registered for this account, so nothing can perform the install. Start the local runtime with \`${this.config.bin} daemon start\`.`, { exit: 1 });
|
|
156
|
+
}
|
|
157
|
+
const choices = target.daemons
|
|
158
|
+
.slice(0, 10)
|
|
159
|
+
.map((d) => ` ${(0, daemon_ref_1.formatDaemonRef)(d.id)} ${d.name || '—'}`)
|
|
160
|
+
.join('\n');
|
|
161
|
+
this.error(`${target.daemons.length} active daemons — say which machine to install on:\n${choices}\n` +
|
|
162
|
+
`Pass one with --daemon, or see them all with \`${this.config.bin} list-daemons\`.`, { exit: 1 });
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
exports.default = HarnessesInstall;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base-command';
|
|
2
|
+
/**
|
|
3
|
+
* What each managed provider's state is on one machine.
|
|
4
|
+
*
|
|
5
|
+
* ## Why this command exists
|
|
6
|
+
*
|
|
7
|
+
* `d878b79581` replaced "is the binary there" with four states — installed,
|
|
8
|
+
* ready, interactive-required, headless-key-required — and routed them from
|
|
9
|
+
* `cli-installers` through health to the web harness create modal. It reached
|
|
10
|
+
* exactly one surface. From the CLI there was no way to ask.
|
|
11
|
+
*
|
|
12
|
+
* That gap is not cosmetic, because `skrr harnesses list` answers a DIFFERENT
|
|
13
|
+
* question and looks like it answers this one. Its `status` is the daemon's
|
|
14
|
+
* socket, so on this account `skrr-code` read `online` with no binary installed
|
|
15
|
+
* at all, and `harnesses ping` answered it in 78ms — the daemon was there, the
|
|
16
|
+
* harness was not. A user could not discover that from inside the product; it
|
|
17
|
+
* took `command -v` in a shell.
|
|
18
|
+
*
|
|
19
|
+
* So this prints what the DAEMON says about each provider: whether the binary
|
|
20
|
+
* is present, which one and where, and whether it is signed in. The four states
|
|
21
|
+
* keep their server-side names here rather than being re-prosed, so that a
|
|
22
|
+
* message quoted from the CLI matches the one in the modal.
|
|
23
|
+
*
|
|
24
|
+
* `unknown` is a first-class answer and is not `ready`. A provider whose recipe
|
|
25
|
+
* declares no credential resolver genuinely cannot be assessed from here, and
|
|
26
|
+
* saying so is the point — the failure this whole vocabulary exists to prevent
|
|
27
|
+
* is a surface that reports ready for a harness that will refuse on first use.
|
|
28
|
+
*/
|
|
29
|
+
export default class HarnessesInstallers extends BaseCommand {
|
|
30
|
+
static description: string;
|
|
31
|
+
static examples: string[];
|
|
32
|
+
static flags: {
|
|
33
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
34
|
+
daemon: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
35
|
+
};
|
|
36
|
+
run(): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Refuse rather than guess which machine to report on.
|
|
39
|
+
*
|
|
40
|
+
* Reading is harmless, but naming the wrong machine is not: the whole value
|
|
41
|
+
* here is "is the thing on MY laptop usable", and an answer about a sandbox
|
|
42
|
+
* the user forgot about is worse than no answer, because it looks like one.
|
|
43
|
+
*/
|
|
44
|
+
private daemonIdFor;
|
|
45
|
+
}
|