@jhytabest/plashboard 0.1.8 → 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -0
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/skills/plashboard-admin/SKILL.md +4 -0
- package/src/plugin.ts +197 -3
package/README.md
CHANGED
|
@@ -76,6 +76,8 @@ Use `fill_provider: "command"` only if you need a custom external runner.
|
|
|
76
76
|
```text
|
|
77
77
|
/plashboard setup [openclaw [agent_id]|mock|command <fill_command>]
|
|
78
78
|
/plashboard quickstart <description>
|
|
79
|
+
/plashboard doctor [local_url] [https_port] [repo_dir]
|
|
80
|
+
/plashboard web-guide [local_url] [repo_dir]
|
|
79
81
|
/plashboard expose-guide [local_url] [https_port]
|
|
80
82
|
/plashboard expose-check [local_url] [https_port]
|
|
81
83
|
/plashboard init
|
|
@@ -94,6 +96,14 @@ Recommended first run:
|
|
|
94
96
|
/plashboard quickstart "Focus on service health, priorities, blockers, and next actions."
|
|
95
97
|
```
|
|
96
98
|
|
|
99
|
+
If `quickstart` returns web/exposure warnings:
|
|
100
|
+
|
|
101
|
+
```text
|
|
102
|
+
/plashboard web-guide
|
|
103
|
+
/plashboard expose-guide
|
|
104
|
+
/plashboard doctor
|
|
105
|
+
```
|
|
106
|
+
|
|
97
107
|
Tailscale helper flow:
|
|
98
108
|
|
|
99
109
|
```text
|
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
|
@@ -20,6 +20,8 @@ Always use plugin tools:
|
|
|
20
20
|
- `plashboard_setup`
|
|
21
21
|
- `plashboard_exposure_guide`
|
|
22
22
|
- `plashboard_exposure_check`
|
|
23
|
+
- `plashboard_web_guide`
|
|
24
|
+
- `plashboard_doctor`
|
|
23
25
|
- `plashboard_init`
|
|
24
26
|
- `plashboard_quickstart`
|
|
25
27
|
- `plashboard_template_create`
|
|
@@ -42,6 +44,8 @@ Always use plugin tools:
|
|
|
42
44
|
## Command Shortcuts
|
|
43
45
|
- `/plashboard quickstart <description>`
|
|
44
46
|
- `/plashboard setup [openclaw [agent_id]|mock|command <fill_command>]`
|
|
47
|
+
- `/plashboard doctor [local_url] [https_port] [repo_dir]`
|
|
48
|
+
- `/plashboard web-guide [local_url] [repo_dir]`
|
|
45
49
|
- `/plashboard expose-guide [local_url] [https_port]`
|
|
46
50
|
- `/plashboard expose-check [local_url] [https_port]`
|
|
47
51
|
- `/plashboard init`
|
package/src/plugin.ts
CHANGED
|
@@ -117,6 +117,15 @@ type ExposureParams = {
|
|
|
117
117
|
dashboard_output_path?: string;
|
|
118
118
|
};
|
|
119
119
|
|
|
120
|
+
type WebGuideParams = {
|
|
121
|
+
local_url?: string;
|
|
122
|
+
repo_dir?: string;
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
type DoctorParams = ExposureParams & {
|
|
126
|
+
repo_dir?: string;
|
|
127
|
+
};
|
|
128
|
+
|
|
120
129
|
type CommandExecResult = {
|
|
121
130
|
ok: boolean;
|
|
122
131
|
stdout: string;
|
|
@@ -230,6 +239,40 @@ async function buildExposureGuide(resolvedConfig: ReturnType<typeof resolveConfi
|
|
|
230
239
|
} satisfies ToolResponse<Record<string, unknown>>;
|
|
231
240
|
}
|
|
232
241
|
|
|
242
|
+
function deriveRepoDir(raw?: string): string {
|
|
243
|
+
const value = (raw || '').trim();
|
|
244
|
+
return value || '/opt/plashboard';
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
async function buildWebGuide(resolvedConfig: ReturnType<typeof resolveConfig>, params: WebGuideParams = {}) {
|
|
248
|
+
const localUrl = normalizeLocalUrl(params.local_url);
|
|
249
|
+
const repoDir = deriveRepoDir(params.repo_dir);
|
|
250
|
+
const dashboardPath = resolvedConfig.dashboard_output_path;
|
|
251
|
+
|
|
252
|
+
return {
|
|
253
|
+
ok: true,
|
|
254
|
+
errors: [],
|
|
255
|
+
data: {
|
|
256
|
+
local_url: localUrl,
|
|
257
|
+
repo_dir: repoDir,
|
|
258
|
+
dashboard_output_path: dashboardPath,
|
|
259
|
+
commands: [
|
|
260
|
+
`git clone https://github.com/jhytabest/plashboard.git ${repoDir} || true`,
|
|
261
|
+
`git -C ${repoDir} pull --ff-only`,
|
|
262
|
+
`docker compose -f ${repoDir}/docker-compose.yml up -d`,
|
|
263
|
+
`docker ps --format "{{.Names}} {{.Ports}}" | grep -E "plash-web|18888"`,
|
|
264
|
+
`curl -I ${localUrl}`,
|
|
265
|
+
`curl -I ${localUrl}/healthz`
|
|
266
|
+
],
|
|
267
|
+
notes: [
|
|
268
|
+
'Plashboard writes dashboard JSON; a local web server must serve the UI and /data/dashboard.json.',
|
|
269
|
+
'The bundled docker-compose stack exposes nginx at 127.0.0.1:18888 by default.',
|
|
270
|
+
'If you host UI differently, update local_url in expose-check/expose-guide.'
|
|
271
|
+
]
|
|
272
|
+
}
|
|
273
|
+
} satisfies ToolResponse<Record<string, unknown>>;
|
|
274
|
+
}
|
|
275
|
+
|
|
233
276
|
async function runExposureCheck(resolvedConfig: ReturnType<typeof resolveConfig>, params: ExposureParams = {}) {
|
|
234
277
|
const localUrl = normalizeLocalUrl(params.local_url);
|
|
235
278
|
const httpsPort = normalizePort(asNumber(params.tailscale_https_port), 8444);
|
|
@@ -469,6 +512,101 @@ async function runSetup(api: UnknownApi, resolvedConfig: ReturnType<typeof resol
|
|
|
469
512
|
} satisfies ToolResponse<Record<string, unknown>>;
|
|
470
513
|
}
|
|
471
514
|
|
|
515
|
+
async function runQuickstart(
|
|
516
|
+
runtime: PlashboardRuntime,
|
|
517
|
+
resolvedConfig: ReturnType<typeof resolveConfig>,
|
|
518
|
+
params: QuickstartParams = {}
|
|
519
|
+
): Promise<ToolResponse<Record<string, unknown>>> {
|
|
520
|
+
const quickstart = await runtime.quickstart(params);
|
|
521
|
+
const exposure = await runExposureCheck(resolvedConfig, {});
|
|
522
|
+
const guide = await buildExposureGuide(resolvedConfig, {});
|
|
523
|
+
const webGuide = await buildWebGuide(resolvedConfig, {});
|
|
524
|
+
|
|
525
|
+
const warnings: string[] = [];
|
|
526
|
+
if (!exposure.ok) {
|
|
527
|
+
warnings.push(...exposure.errors);
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
return {
|
|
531
|
+
ok: quickstart.ok,
|
|
532
|
+
errors: quickstart.errors,
|
|
533
|
+
data: {
|
|
534
|
+
...(quickstart.data || {}),
|
|
535
|
+
postcheck: {
|
|
536
|
+
local_url: exposure.data?.local_url,
|
|
537
|
+
local_url_ok: exposure.data?.local_url_ok,
|
|
538
|
+
tailscale_port_configured: exposure.data?.tailscale_port_configured,
|
|
539
|
+
dashboard_exists: exposure.data?.dashboard_exists
|
|
540
|
+
},
|
|
541
|
+
warnings,
|
|
542
|
+
next_steps: warnings.length
|
|
543
|
+
? [
|
|
544
|
+
'run /plashboard web-guide and execute its commands',
|
|
545
|
+
'run /plashboard expose-guide and apply tailscale mapping',
|
|
546
|
+
'run /plashboard doctor'
|
|
547
|
+
]
|
|
548
|
+
: [
|
|
549
|
+
'dashboard generation is working',
|
|
550
|
+
'run /plashboard doctor for full readiness check'
|
|
551
|
+
],
|
|
552
|
+
exposure_guide: guide.data,
|
|
553
|
+
web_guide: webGuide.data
|
|
554
|
+
}
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
async function runDoctor(
|
|
559
|
+
runtime: PlashboardRuntime,
|
|
560
|
+
resolvedConfig: ReturnType<typeof resolveConfig>,
|
|
561
|
+
params: DoctorParams = {}
|
|
562
|
+
): Promise<ToolResponse<Record<string, unknown>>> {
|
|
563
|
+
const status = await runtime.status();
|
|
564
|
+
const exposure = await runExposureCheck(resolvedConfig, params);
|
|
565
|
+
const exposureGuide = await buildExposureGuide(resolvedConfig, params);
|
|
566
|
+
const webGuide = await buildWebGuide(resolvedConfig, params);
|
|
567
|
+
|
|
568
|
+
const issues: string[] = [];
|
|
569
|
+
const statusData = status.data;
|
|
570
|
+
const templateCount = Number(statusData?.template_count ?? 0);
|
|
571
|
+
const activeTemplateId = statusData?.active_template_id || null;
|
|
572
|
+
|
|
573
|
+
if (!status.ok) issues.push(...status.errors);
|
|
574
|
+
if (templateCount === 0) issues.push('no templates exist; run /plashboard quickstart "<description>"');
|
|
575
|
+
if (!activeTemplateId) issues.push('no active template; activate one with /plashboard activate <template-id>');
|
|
576
|
+
if (exposure.data?.dashboard_exists !== true) {
|
|
577
|
+
issues.push(`dashboard output missing at ${resolvedConfig.dashboard_output_path}`);
|
|
578
|
+
}
|
|
579
|
+
if (exposure.data?.local_url_ok !== true) {
|
|
580
|
+
issues.push(`local dashboard server is not reachable at ${String(exposure.data?.local_url || 'http://127.0.0.1:18888')}`);
|
|
581
|
+
}
|
|
582
|
+
if (exposure.data?.tailscale_status_ok !== true) {
|
|
583
|
+
issues.push('tailscale serve status failed');
|
|
584
|
+
} else if (exposure.data?.tailscale_port_configured !== true) {
|
|
585
|
+
issues.push(`tailscale serve mapping missing for port ${String(exposure.data?.tailscale_https_port || 8444)}`);
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
const ready = issues.length === 0;
|
|
589
|
+
return {
|
|
590
|
+
ok: ready,
|
|
591
|
+
errors: issues,
|
|
592
|
+
data: {
|
|
593
|
+
ready,
|
|
594
|
+
status: statusData,
|
|
595
|
+
exposure: exposure.data,
|
|
596
|
+
exposure_guide: exposureGuide.data,
|
|
597
|
+
web_guide: webGuide.data,
|
|
598
|
+
next_steps: ready
|
|
599
|
+
? ['dashboard runtime + web exposure look healthy']
|
|
600
|
+
: [
|
|
601
|
+
'run /plashboard quickstart "<description>" if no templates exist',
|
|
602
|
+
'run /plashboard web-guide and start local UI server',
|
|
603
|
+
'run /plashboard expose-guide and apply tailscale mapping',
|
|
604
|
+
're-run /plashboard doctor'
|
|
605
|
+
]
|
|
606
|
+
}
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
|
|
472
610
|
export function registerPlashboardPlugin(api: UnknownApi): void {
|
|
473
611
|
const config = resolveConfig(api);
|
|
474
612
|
const runtimeCommand = api.runtime?.system?.runCommandWithTimeout;
|
|
@@ -547,6 +685,40 @@ export function registerPlashboardPlugin(api: UnknownApi): void {
|
|
|
547
685
|
toToolResult(await runExposureCheck(config, params))
|
|
548
686
|
});
|
|
549
687
|
|
|
688
|
+
api.registerTool?.({
|
|
689
|
+
name: 'plashboard_web_guide',
|
|
690
|
+
description: 'Return exact commands to start the local plashboard web UI server.',
|
|
691
|
+
optional: true,
|
|
692
|
+
parameters: {
|
|
693
|
+
type: 'object',
|
|
694
|
+
properties: {
|
|
695
|
+
local_url: { type: 'string' },
|
|
696
|
+
repo_dir: { type: 'string' }
|
|
697
|
+
},
|
|
698
|
+
additionalProperties: false
|
|
699
|
+
},
|
|
700
|
+
execute: async (_toolCallId: unknown, params: WebGuideParams = {}) =>
|
|
701
|
+
toToolResult(await buildWebGuide(config, params))
|
|
702
|
+
});
|
|
703
|
+
|
|
704
|
+
api.registerTool?.({
|
|
705
|
+
name: 'plashboard_doctor',
|
|
706
|
+
description: 'Run full plashboard readiness checks (templates, local UI, and tailscale mapping).',
|
|
707
|
+
optional: true,
|
|
708
|
+
parameters: {
|
|
709
|
+
type: 'object',
|
|
710
|
+
properties: {
|
|
711
|
+
local_url: { type: 'string' },
|
|
712
|
+
tailscale_https_port: { type: 'number' },
|
|
713
|
+
dashboard_output_path: { type: 'string' },
|
|
714
|
+
repo_dir: { type: 'string' }
|
|
715
|
+
},
|
|
716
|
+
additionalProperties: false
|
|
717
|
+
},
|
|
718
|
+
execute: async (_toolCallId: unknown, params: DoctorParams = {}) =>
|
|
719
|
+
toToolResult(await runDoctor(runtime, config, params))
|
|
720
|
+
});
|
|
721
|
+
|
|
550
722
|
api.registerTool?.({
|
|
551
723
|
name: 'plashboard_setup',
|
|
552
724
|
description: 'Bootstrap or update plashboard plugin configuration in openclaw.json.',
|
|
@@ -603,7 +775,7 @@ export function registerPlashboardPlugin(api: UnknownApi): void {
|
|
|
603
775
|
additionalProperties: false
|
|
604
776
|
},
|
|
605
777
|
execute: async (_toolCallId: unknown, params: QuickstartParams = {}) =>
|
|
606
|
-
toToolResult(await runtime
|
|
778
|
+
toToolResult(await runQuickstart(runtime, config, params))
|
|
607
779
|
});
|
|
608
780
|
|
|
609
781
|
api.registerTool?.({
|
|
@@ -809,6 +981,28 @@ export function registerPlashboardPlugin(api: UnknownApi): void {
|
|
|
809
981
|
})
|
|
810
982
|
);
|
|
811
983
|
}
|
|
984
|
+
if (cmd === 'web-guide') {
|
|
985
|
+
const localUrl = rest.find((token) => token.startsWith('http://') || token.startsWith('https://'));
|
|
986
|
+
const repoDir = rest.find((token) => token.startsWith('/'));
|
|
987
|
+
return toCommandResult(
|
|
988
|
+
await buildWebGuide(config, {
|
|
989
|
+
local_url: localUrl,
|
|
990
|
+
repo_dir: repoDir
|
|
991
|
+
})
|
|
992
|
+
);
|
|
993
|
+
}
|
|
994
|
+
if (cmd === 'doctor') {
|
|
995
|
+
const localUrl = rest.find((token) => token.startsWith('http://') || token.startsWith('https://'));
|
|
996
|
+
const portToken = rest.find((token) => /^[0-9]+$/.test(token));
|
|
997
|
+
const repoDir = rest.find((token) => token.startsWith('/'));
|
|
998
|
+
return toCommandResult(
|
|
999
|
+
await runDoctor(runtime, config, {
|
|
1000
|
+
local_url: localUrl,
|
|
1001
|
+
tailscale_https_port: portToken ? Number(portToken) : undefined,
|
|
1002
|
+
repo_dir: repoDir
|
|
1003
|
+
})
|
|
1004
|
+
);
|
|
1005
|
+
}
|
|
812
1006
|
if (cmd === 'setup') {
|
|
813
1007
|
const mode = asString(rest[0]).toLowerCase();
|
|
814
1008
|
const fillProvider = mode === 'command' || mode === 'mock' || mode === 'openclaw' ? mode : undefined;
|
|
@@ -824,7 +1018,7 @@ export function registerPlashboardPlugin(api: UnknownApi): void {
|
|
|
824
1018
|
}
|
|
825
1019
|
if (cmd === 'quickstart') {
|
|
826
1020
|
const description = rest.join(' ').trim() || undefined;
|
|
827
|
-
return toCommandResult(await runtime
|
|
1021
|
+
return toCommandResult(await runQuickstart(runtime, config, { description }));
|
|
828
1022
|
}
|
|
829
1023
|
if (cmd === 'init') return toCommandResult(await runtime.init());
|
|
830
1024
|
if (cmd === 'status') return toCommandResult(await runtime.status());
|
|
@@ -850,7 +1044,7 @@ export function registerPlashboardPlugin(api: UnknownApi): void {
|
|
|
850
1044
|
return toCommandResult({
|
|
851
1045
|
ok: false,
|
|
852
1046
|
errors: [
|
|
853
|
-
'unknown command. supported: setup [openclaw [agent_id]|mock|command <fill_command>], quickstart <description>, expose-guide [local_url] [https_port], expose-check [local_url] [https_port], init, status, list, activate <id>, delete <id>, copy <src> <new-id> [new-name] [activate], run <id>, set-display <width> <height> <top> <bottom>'
|
|
1047
|
+
'unknown command. supported: setup [openclaw [agent_id]|mock|command <fill_command>], quickstart <description>, doctor [local_url] [https_port] [repo_dir], web-guide [local_url] [repo_dir], expose-guide [local_url] [https_port], expose-check [local_url] [https_port], init, status, list, activate <id>, delete <id>, copy <src> <new-id> [new-name] [activate], run <id>, set-display <width> <height> <top> <bottom>'
|
|
854
1048
|
]
|
|
855
1049
|
});
|
|
856
1050
|
}
|