@orbitpanel/cli 0.5.0 → 0.6.0
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/lib/ai-stream.d.ts +34 -0
- package/dist/lib/ai-stream.js +131 -0
- package/dist/lib/ai-stream.js.map +1 -0
- package/dist/lib/risk.d.ts +38 -0
- package/dist/lib/risk.js +82 -0
- package/dist/lib/risk.js.map +1 -0
- package/dist/lib/runtime.d.ts +11 -0
- package/dist/lib/runtime.js +34 -0
- package/dist/lib/runtime.js.map +1 -0
- package/dist/lib/shell-commands.d.ts +19 -0
- package/dist/lib/shell-commands.js +407 -0
- package/dist/lib/shell-commands.js.map +1 -0
- package/dist/lib/shell-render.d.ts +25 -0
- package/dist/lib/shell-render.js +53 -0
- package/dist/lib/shell-render.js.map +1 -0
- package/dist/lib/shell.d.ts +1 -1
- package/dist/lib/shell.js +149 -489
- package/dist/lib/shell.js.map +1 -1
- package/dist/lib/stream-state.d.ts +28 -0
- package/dist/lib/stream-state.js +69 -0
- package/dist/lib/stream-state.js.map +1 -0
- package/dist/lib/ui.d.ts +13 -0
- package/dist/lib/ui.js +33 -0
- package/dist/lib/ui.js.map +1 -1
- package/dist/state/store.d.ts +29 -0
- package/dist/state/store.js +84 -0
- package/dist/state/store.js.map +1 -0
- package/dist/state/types.d.ts +43 -0
- package/dist/state/types.js +6 -0
- package/dist/state/types.js.map +1 -0
- package/oclif.manifest.json +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSE streaming client for @orbitpanel/cli.
|
|
3
|
+
* Consumes /api/v1/ai/chat/stream and emits typed events.
|
|
4
|
+
* Falls back to non-streaming sendChat() on failure.
|
|
5
|
+
*/
|
|
6
|
+
import type { OrbitConfig, SiteLink } from '../types.js';
|
|
7
|
+
/** SSE event types matching the backend's stream protocol */
|
|
8
|
+
export type StreamEventType = 'status' | 'thinking' | 'delta' | 'metadata' | 'done' | 'error';
|
|
9
|
+
export interface StreamEvent {
|
|
10
|
+
type: StreamEventType;
|
|
11
|
+
data: Record<string, unknown>;
|
|
12
|
+
}
|
|
13
|
+
/** Handler called for each streaming event */
|
|
14
|
+
export type StreamHandler = (event: StreamEvent) => void;
|
|
15
|
+
/**
|
|
16
|
+
* Parse a chunk of SSE text into typed events.
|
|
17
|
+
*
|
|
18
|
+
* SSE format:
|
|
19
|
+
* event: <type>
|
|
20
|
+
* data: <json>
|
|
21
|
+
* (empty line separates events)
|
|
22
|
+
*/
|
|
23
|
+
export declare function parseSSEChunk(text: string): StreamEvent[];
|
|
24
|
+
/**
|
|
25
|
+
* Send a chat message and receive streaming SSE events.
|
|
26
|
+
* The handler is called for each event as it arrives.
|
|
27
|
+
*
|
|
28
|
+
* Returns the accumulated text response for compatibility.
|
|
29
|
+
*/
|
|
30
|
+
export declare function sendChatStream(message: string, handler: StreamHandler, config: OrbitConfig, siteLink: SiteLink | null): Promise<{
|
|
31
|
+
text: string;
|
|
32
|
+
provider?: string;
|
|
33
|
+
error?: string;
|
|
34
|
+
}>;
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSE streaming client for @orbitpanel/cli.
|
|
3
|
+
* Consumes /api/v1/ai/chat/stream and emits typed events.
|
|
4
|
+
* Falls back to non-streaming sendChat() on failure.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Parse a chunk of SSE text into typed events.
|
|
8
|
+
*
|
|
9
|
+
* SSE format:
|
|
10
|
+
* event: <type>
|
|
11
|
+
* data: <json>
|
|
12
|
+
* (empty line separates events)
|
|
13
|
+
*/
|
|
14
|
+
export function parseSSEChunk(text) {
|
|
15
|
+
if (!text.trim())
|
|
16
|
+
return [];
|
|
17
|
+
const events = [];
|
|
18
|
+
const blocks = text.split('\n\n');
|
|
19
|
+
for (const block of blocks) {
|
|
20
|
+
const trimmed = block.trim();
|
|
21
|
+
if (!trimmed)
|
|
22
|
+
continue;
|
|
23
|
+
let eventType = null;
|
|
24
|
+
let dataStr = null;
|
|
25
|
+
for (const line of trimmed.split('\n')) {
|
|
26
|
+
if (line.startsWith('event:')) {
|
|
27
|
+
eventType = line.slice(6).trim();
|
|
28
|
+
}
|
|
29
|
+
else if (line.startsWith('data:')) {
|
|
30
|
+
dataStr = line.slice(5).trim();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (eventType && dataStr) {
|
|
34
|
+
try {
|
|
35
|
+
const data = JSON.parse(dataStr);
|
|
36
|
+
events.push({ type: eventType, data });
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// Skip events with invalid JSON
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return events;
|
|
44
|
+
}
|
|
45
|
+
const STREAM_TIMEOUT_MS = 120_000; // Streaming can be slow with large contexts
|
|
46
|
+
/**
|
|
47
|
+
* Send a chat message and receive streaming SSE events.
|
|
48
|
+
* The handler is called for each event as it arrives.
|
|
49
|
+
*
|
|
50
|
+
* Returns the accumulated text response for compatibility.
|
|
51
|
+
*/
|
|
52
|
+
export async function sendChatStream(message, handler, config, siteLink) {
|
|
53
|
+
const defaultSite = config.default_site;
|
|
54
|
+
const tokenEntry = defaultSite ? config.tokens[defaultSite] : undefined;
|
|
55
|
+
if (!tokenEntry) {
|
|
56
|
+
return { text: '', error: 'Non autenticato. Usa /auth o /login.' };
|
|
57
|
+
}
|
|
58
|
+
const context = {};
|
|
59
|
+
if (siteLink) {
|
|
60
|
+
context.site_id = siteLink.orbit_site_id;
|
|
61
|
+
}
|
|
62
|
+
const controller = new AbortController();
|
|
63
|
+
const timer = setTimeout(() => controller.abort(), STREAM_TIMEOUT_MS);
|
|
64
|
+
let accumulatedText = '';
|
|
65
|
+
let provider;
|
|
66
|
+
try {
|
|
67
|
+
const res = await fetch(`${config.api_url}/api/v1/ai/chat/stream`, {
|
|
68
|
+
method: 'POST',
|
|
69
|
+
headers: {
|
|
70
|
+
'Authorization': `Bearer ${tokenEntry.token}`,
|
|
71
|
+
'Content-Type': 'application/json',
|
|
72
|
+
'User-Agent': '@orbitpanel/cli',
|
|
73
|
+
'Accept': 'text/event-stream',
|
|
74
|
+
},
|
|
75
|
+
body: JSON.stringify({
|
|
76
|
+
message,
|
|
77
|
+
context,
|
|
78
|
+
use_kb: true,
|
|
79
|
+
}),
|
|
80
|
+
signal: controller.signal,
|
|
81
|
+
});
|
|
82
|
+
if (!res.ok) {
|
|
83
|
+
const body = await res.json().catch(() => ({}));
|
|
84
|
+
const detail = body.detail || `HTTP ${res.status}`;
|
|
85
|
+
return { text: '', error: detail };
|
|
86
|
+
}
|
|
87
|
+
if (!res.body) {
|
|
88
|
+
return { text: '', error: 'Nessun body nella risposta streaming.' };
|
|
89
|
+
}
|
|
90
|
+
const reader = res.body.getReader();
|
|
91
|
+
const decoder = new TextDecoder();
|
|
92
|
+
let buffer = '';
|
|
93
|
+
while (true) {
|
|
94
|
+
const { done, value } = await reader.read();
|
|
95
|
+
if (done)
|
|
96
|
+
break;
|
|
97
|
+
buffer += decoder.decode(value, { stream: true });
|
|
98
|
+
// Process complete events in the buffer
|
|
99
|
+
while (buffer.includes('\n\n')) {
|
|
100
|
+
const eventEnd = buffer.indexOf('\n\n') + 2;
|
|
101
|
+
const eventText = buffer.slice(0, eventEnd);
|
|
102
|
+
buffer = buffer.slice(eventEnd);
|
|
103
|
+
const events = parseSSEChunk(eventText);
|
|
104
|
+
for (const event of events) {
|
|
105
|
+
handler(event);
|
|
106
|
+
// Accumulate text from delta events
|
|
107
|
+
if (event.type === 'delta' && typeof event.data.content === 'string') {
|
|
108
|
+
accumulatedText += event.data.content;
|
|
109
|
+
}
|
|
110
|
+
// Capture provider from metadata
|
|
111
|
+
if (event.type === 'metadata') {
|
|
112
|
+
const model = event.data.model;
|
|
113
|
+
const prov = event.data.provider;
|
|
114
|
+
provider = model ? `${prov}/${model}` : prov;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return { text: accumulatedText, provider };
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
if (err instanceof Error && err.name === 'AbortError') {
|
|
123
|
+
return { text: accumulatedText, error: 'Timeout — risposta streaming troppo lenta.' };
|
|
124
|
+
}
|
|
125
|
+
return { text: accumulatedText, error: err instanceof Error ? err.message : String(err) };
|
|
126
|
+
}
|
|
127
|
+
finally {
|
|
128
|
+
clearTimeout(timer);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=ai-stream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-stream.js","sourceRoot":"","sources":["../../src/lib/ai-stream.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Risk awareness system for @orbitpanel/cli.
|
|
3
|
+
* Classifies operations by risk level and enforces confirmation policies.
|
|
4
|
+
*/
|
|
5
|
+
import type { RuntimeMode } from './runtime.js';
|
|
6
|
+
export type RiskLevel = 'LOW' | 'MEDIUM' | 'HIGH';
|
|
7
|
+
export interface RiskyAction {
|
|
8
|
+
name: string;
|
|
9
|
+
description: string;
|
|
10
|
+
risk: RiskLevel;
|
|
11
|
+
scope?: string;
|
|
12
|
+
}
|
|
13
|
+
/** Classify a named operation by risk level. */
|
|
14
|
+
export declare function classifyRisk(operationName: string): RiskLevel;
|
|
15
|
+
/**
|
|
16
|
+
* Whether a risky action requires user confirmation.
|
|
17
|
+
*
|
|
18
|
+
* - HIGH: always confirm (any runtime)
|
|
19
|
+
* - MEDIUM: confirm only in interactive (tty)
|
|
20
|
+
* - LOW: never confirm
|
|
21
|
+
*/
|
|
22
|
+
export declare function shouldConfirm(action: RiskyAction, runtime: RuntimeMode): boolean;
|
|
23
|
+
/** Format a colored risk badge for terminal output. */
|
|
24
|
+
export declare function formatRiskBadge(risk: RiskLevel): string;
|
|
25
|
+
/** Format a complete action description with risk indicator. */
|
|
26
|
+
export declare function formatActionWithRisk(action: RiskyAction): string;
|
|
27
|
+
/** Injectable prompt function — returns true if user confirms. */
|
|
28
|
+
export type PromptFn = (message: string) => Promise<boolean>;
|
|
29
|
+
/**
|
|
30
|
+
* Interactive confirmation for risky actions.
|
|
31
|
+
*
|
|
32
|
+
* - LOW: auto-approve, never prompt
|
|
33
|
+
* - MEDIUM: prompt in TTY, auto-approve in pipe/CI
|
|
34
|
+
* - HIGH: prompt in TTY, refuse in pipe/CI (requires explicit --confirm flag)
|
|
35
|
+
*
|
|
36
|
+
* @param promptFn Injectable prompt — in shell, backed by readline.question()
|
|
37
|
+
*/
|
|
38
|
+
export declare function confirmAction(action: RiskyAction, runtime: RuntimeMode, promptFn?: PromptFn): Promise<boolean>;
|
package/dist/lib/risk.js
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Risk awareness system for @orbitpanel/cli.
|
|
3
|
+
* Classifies operations by risk level and enforces confirmation policies.
|
|
4
|
+
*/
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
/** Operations classified by risk level */
|
|
7
|
+
const HIGH_RISK_PATTERNS = [
|
|
8
|
+
'database_restore', 'database_drop', 'database_truncate',
|
|
9
|
+
'search_replace', 'core_update', 'file_delete',
|
|
10
|
+
'site_delete', 'backup_restore', 'migration',
|
|
11
|
+
];
|
|
12
|
+
const LOW_RISK_PATTERNS = [
|
|
13
|
+
'site_info', 'list_plugins', 'list_themes', 'get_status',
|
|
14
|
+
'health_check', 'get_option', 'list_users', 'list_options',
|
|
15
|
+
'get_debug_log', 'get_error_log', 'db_size',
|
|
16
|
+
];
|
|
17
|
+
/** Classify a named operation by risk level. */
|
|
18
|
+
export function classifyRisk(operationName) {
|
|
19
|
+
const lower = operationName.toLowerCase();
|
|
20
|
+
if (HIGH_RISK_PATTERNS.some(p => lower.includes(p)))
|
|
21
|
+
return 'HIGH';
|
|
22
|
+
if (LOW_RISK_PATTERNS.some(p => lower.includes(p)))
|
|
23
|
+
return 'LOW';
|
|
24
|
+
return 'MEDIUM';
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Whether a risky action requires user confirmation.
|
|
28
|
+
*
|
|
29
|
+
* - HIGH: always confirm (any runtime)
|
|
30
|
+
* - MEDIUM: confirm only in interactive (tty)
|
|
31
|
+
* - LOW: never confirm
|
|
32
|
+
*/
|
|
33
|
+
export function shouldConfirm(action, runtime) {
|
|
34
|
+
if (action.risk === 'HIGH')
|
|
35
|
+
return true;
|
|
36
|
+
if (action.risk === 'MEDIUM' && runtime === 'tty')
|
|
37
|
+
return true;
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
/** Format a colored risk badge for terminal output. */
|
|
41
|
+
export function formatRiskBadge(risk) {
|
|
42
|
+
switch (risk) {
|
|
43
|
+
case 'HIGH':
|
|
44
|
+
return chalk.bgRed.white.bold(` HIGH `);
|
|
45
|
+
case 'MEDIUM':
|
|
46
|
+
return chalk.bgYellow.black(` MEDIUM `);
|
|
47
|
+
case 'LOW':
|
|
48
|
+
return chalk.bgGreen.black(` LOW `);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/** Format a complete action description with risk indicator. */
|
|
52
|
+
export function formatActionWithRisk(action) {
|
|
53
|
+
const badge = formatRiskBadge(action.risk);
|
|
54
|
+
const scope = action.scope ? chalk.dim(` [${action.scope}]`) : '';
|
|
55
|
+
return `${badge} ${chalk.white(action.description)}${scope}`;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Interactive confirmation for risky actions.
|
|
59
|
+
*
|
|
60
|
+
* - LOW: auto-approve, never prompt
|
|
61
|
+
* - MEDIUM: prompt in TTY, auto-approve in pipe/CI
|
|
62
|
+
* - HIGH: prompt in TTY, refuse in pipe/CI (requires explicit --confirm flag)
|
|
63
|
+
*
|
|
64
|
+
* @param promptFn Injectable prompt — in shell, backed by readline.question()
|
|
65
|
+
*/
|
|
66
|
+
export async function confirmAction(action, runtime, promptFn) {
|
|
67
|
+
// LOW risk → always approve
|
|
68
|
+
if (!shouldConfirm(action, runtime))
|
|
69
|
+
return true;
|
|
70
|
+
// Non-interactive or no prompt available
|
|
71
|
+
if (runtime !== 'tty' || !promptFn) {
|
|
72
|
+
// HIGH risk cannot be auto-approved
|
|
73
|
+
if (action.risk === 'HIGH')
|
|
74
|
+
return false;
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
// Interactive confirmation
|
|
78
|
+
console.log('');
|
|
79
|
+
console.log(` ${formatActionWithRisk(action)}`);
|
|
80
|
+
return promptFn(` Procedi? (s/N) `);
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=risk.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"risk.js","sourceRoot":"","sources":["../../src/lib/risk.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime detection for @orbitpanel/cli.
|
|
3
|
+
* Identifies the execution environment to enable safe TTY/non-TTY behavior.
|
|
4
|
+
*/
|
|
5
|
+
export type RuntimeMode = 'tty' | 'pipe' | 'ci' | 'unknown';
|
|
6
|
+
/** Detect the current runtime environment. CI takes priority over TTY. */
|
|
7
|
+
export declare function detectRuntime(): RuntimeMode;
|
|
8
|
+
/** Whether the current runtime supports interactive features (prompts, spinners, etc.) */
|
|
9
|
+
export declare function isInteractive(): boolean;
|
|
10
|
+
/** Whether raw mode is available on stdin (needed for advanced keyboard input). */
|
|
11
|
+
export declare function isRawModeSupported(): boolean;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime detection for @orbitpanel/cli.
|
|
3
|
+
* Identifies the execution environment to enable safe TTY/non-TTY behavior.
|
|
4
|
+
*/
|
|
5
|
+
/** Detect the current runtime environment. CI takes priority over TTY. */
|
|
6
|
+
export function detectRuntime() {
|
|
7
|
+
// CI environments (check first — CI runners may have TTY)
|
|
8
|
+
if (process.env.CI === 'true' ||
|
|
9
|
+
process.env.CI === '1' ||
|
|
10
|
+
process.env.CONTINUOUS_INTEGRATION !== undefined ||
|
|
11
|
+
process.env.GITHUB_ACTIONS !== undefined ||
|
|
12
|
+
process.env.GITLAB_CI !== undefined ||
|
|
13
|
+
process.env.JENKINS_URL !== undefined) {
|
|
14
|
+
return 'ci';
|
|
15
|
+
}
|
|
16
|
+
// Piped input (stdin is not a TTY)
|
|
17
|
+
if (!process.stdin.isTTY) {
|
|
18
|
+
return 'pipe';
|
|
19
|
+
}
|
|
20
|
+
// Interactive terminal
|
|
21
|
+
if (process.stdout.isTTY && process.stdin.isTTY) {
|
|
22
|
+
return 'tty';
|
|
23
|
+
}
|
|
24
|
+
return 'unknown';
|
|
25
|
+
}
|
|
26
|
+
/** Whether the current runtime supports interactive features (prompts, spinners, etc.) */
|
|
27
|
+
export function isInteractive() {
|
|
28
|
+
return detectRuntime() === 'tty';
|
|
29
|
+
}
|
|
30
|
+
/** Whether raw mode is available on stdin (needed for advanced keyboard input). */
|
|
31
|
+
export function isRawModeSupported() {
|
|
32
|
+
return process.stdin.isTTY === true && typeof process.stdin.setRawMode === 'function';
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/lib/runtime.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,0EAA0E;AAC1E,MAAM,UAAU,aAAa;IAC3B,0DAA0D;IAC1D,IACE,OAAO,CAAC,GAAG,CAAC,EAAE,KAAK,MAAM;QACzB,OAAO,CAAC,GAAG,CAAC,EAAE,KAAK,GAAG;QACtB,OAAO,CAAC,GAAG,CAAC,sBAAsB,KAAK,SAAS;QAChD,OAAO,CAAC,GAAG,CAAC,cAAc,KAAK,SAAS;QACxC,OAAO,CAAC,GAAG,CAAC,SAAS,KAAK,SAAS;QACnC,OAAO,CAAC,GAAG,CAAC,WAAW,KAAK,SAAS,EACrC,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,mCAAmC;IACnC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACzB,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,uBAAuB;IACvB,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QAChD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,0FAA0F;AAC1F,MAAM,UAAU,aAAa;IAC3B,OAAO,aAAa,EAAE,KAAK,KAAK,CAAC;AACnC,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,kBAAkB;IAChC,OAAO,OAAO,CAAC,KAAK,CAAC,KAAK,KAAK,IAAI,IAAI,OAAO,OAAO,CAAC,KAAK,CAAC,UAAU,KAAK,UAAU,CAAC;AACxF,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shell command handlers for @orbitpanel/cli.
|
|
3
|
+
* Extracted from shell.ts for maintainability.
|
|
4
|
+
* Each function handles one slash command.
|
|
5
|
+
*/
|
|
6
|
+
import { type PromptFn } from './risk.js';
|
|
7
|
+
export declare function cmdStatus(): Promise<void>;
|
|
8
|
+
export declare function cmdDoctor(): Promise<void>;
|
|
9
|
+
export declare function cmdSessionStart(): Promise<void>;
|
|
10
|
+
export declare function cmdSessionEnd(): Promise<void>;
|
|
11
|
+
export declare function cmdSessionInfo(): Promise<void>;
|
|
12
|
+
export declare function cmdNoteAdd(text: string): Promise<void>;
|
|
13
|
+
export declare function cmdReport(promptFn?: PromptFn): Promise<void>;
|
|
14
|
+
export declare function cmdList(): Promise<void>;
|
|
15
|
+
export declare function cmdGet(id: string): Promise<void>;
|
|
16
|
+
export declare function cmdSites(selectNum?: string): Promise<void>;
|
|
17
|
+
export declare function cmdAuth(): Promise<void>;
|
|
18
|
+
export declare function cmdLogin(token: string): Promise<void>;
|
|
19
|
+
export declare function cmdLink(siteId: string): Promise<void>;
|