@chainingintention/pi-web-cn 1.202606.3 → 1.202606.4
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/LICENSE +21 -21
- package/README.md +364 -364
- package/dist/cli.js +32 -32
- package/dist/client/assets/{CodeViewer-B4nxYc0g.js → CodeViewer-BNKhIElN.js} +1 -1
- package/dist/client/assets/{TerminalPanel-htr2dU1I.js → TerminalPanel-VPiiPQfC.js} +1 -1
- package/dist/client/assets/{index-BjUH4a8R.js → index-Csx3hC75.js} +135 -135
- package/dist/client/favicon.svg +11 -11
- package/dist/client/index.html +17 -17
- package/dist/client/manifest.webmanifest +24 -24
- package/dist/pi-web-plugins/info/package.json +9 -9
- package/dist/pi-web-plugins/info/pi-web-plugin.js +14 -14
- package/dist/pi-web-plugins/updates/package.json +9 -9
- package/dist/pi-web-plugins/updates/pi-web-plugin.js +75 -75
- package/dist/pi-web-plugins/workspace-tasks/config.js +1 -1
- package/dist/pi-web-plugins/workspace-tasks/package.json +9 -9
- package/dist/pi-web-plugins/workspace-tasks/pi-web-plugin.js +10 -10
- package/dist/pi-web-plugins/workspace-tasks/taskRunner.js +1 -1
- package/dist/pi-web-plugins/workspace-tasks/tasksPanelElement.js +58 -58
- package/dist/pi-web-plugins/workspace-tasks/workspaceTasksClient.js +1 -1
- package/docs/assets/favicon.svg +11 -11
- package/docs/plugins.md +762 -762
- package/extensions/pi-web.ts +133 -133
- package/install.sh +5 -5
- package/package.json +127 -127
- package/plugin-api/unstable.d.ts +1 -1
- package/plugin-api.d.ts +1 -1
package/dist/client/favicon.svg
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" role="img" aria-labelledby="title desc">
|
|
2
|
-
<title id="title">PI WEB mark</title>
|
|
3
|
-
<desc id="desc">A horizontal brand bar.</desc>
|
|
4
|
-
<style>
|
|
5
|
-
.bar { fill: #00f0d8; }
|
|
6
|
-
@media (prefers-color-scheme: light) {
|
|
7
|
-
.bar { fill: #008c82; }
|
|
8
|
-
}
|
|
9
|
-
</style>
|
|
10
|
-
<rect class="bar" x="128" y="448" width="768" height="128"/>
|
|
11
|
-
</svg>
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" role="img" aria-labelledby="title desc">
|
|
2
|
+
<title id="title">PI WEB mark</title>
|
|
3
|
+
<desc id="desc">A horizontal brand bar.</desc>
|
|
4
|
+
<style>
|
|
5
|
+
.bar { fill: #00f0d8; }
|
|
6
|
+
@media (prefers-color-scheme: light) {
|
|
7
|
+
.bar { fill: #008c82; }
|
|
8
|
+
}
|
|
9
|
+
</style>
|
|
10
|
+
<rect class="bar" x="128" y="448" width="768" height="128"/>
|
|
11
|
+
</svg>
|
package/dist/client/index.html
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8" />
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
|
|
6
|
-
<title>PI WEB</title>
|
|
7
|
-
<meta name="theme-color" content="#0d1117" />
|
|
8
|
-
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
9
|
-
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
|
|
10
|
-
<link rel="manifest" href="/manifest.webmanifest" />
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
|
|
6
|
+
<title>PI WEB</title>
|
|
7
|
+
<meta name="theme-color" content="#0d1117" />
|
|
8
|
+
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
9
|
+
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
|
|
10
|
+
<link rel="manifest" href="/manifest.webmanifest" />
|
|
11
11
|
<style>
|
|
12
12
|
:root {
|
|
13
13
|
color-scheme: dark;
|
|
@@ -49,12 +49,12 @@
|
|
|
49
49
|
}
|
|
50
50
|
html, body { margin: 0; height: 100%; overflow: hidden; background: var(--pi-bg); color: var(--pi-text); }
|
|
51
51
|
body { min-height: 100dvh; }
|
|
52
|
-
</style>
|
|
53
|
-
<script type="module" crossorigin src="/assets/index-
|
|
52
|
+
</style>
|
|
53
|
+
<script type="module" crossorigin src="/assets/index-Csx3hC75.js"></script>
|
|
54
54
|
<link rel="modulepreload" crossorigin href="/assets/vendor-editor-core-B4Sq6exx.js">
|
|
55
55
|
<link rel="modulepreload" crossorigin href="/assets/vendor-editor-languages-DznYbTkJ.js">
|
|
56
|
-
</head>
|
|
57
|
-
<body>
|
|
58
|
-
<pi-web-app></pi-web-app>
|
|
59
|
-
</body>
|
|
60
|
-
</html>
|
|
56
|
+
</head>
|
|
57
|
+
<body>
|
|
58
|
+
<pi-web-app></pi-web-app>
|
|
59
|
+
</body>
|
|
60
|
+
</html>
|
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "PI WEB",
|
|
3
|
-
"short_name": "PI WEB",
|
|
4
|
-
"description": "Remote web UI and browser control plane for persistent Pi Coding Agent sessions.",
|
|
5
|
-
"start_url": "/",
|
|
6
|
-
"scope": "/",
|
|
7
|
-
"display": "standalone",
|
|
8
|
-
"background_color": "#0d1117",
|
|
9
|
-
"theme_color": "#0d1117",
|
|
10
|
-
"icons": [
|
|
11
|
-
{
|
|
12
|
-
"src": "/pwa-icon-192.png",
|
|
13
|
-
"sizes": "192x192",
|
|
14
|
-
"type": "image/png",
|
|
15
|
-
"purpose": "any maskable"
|
|
16
|
-
},
|
|
17
|
-
{
|
|
18
|
-
"src": "/pwa-icon-512.png",
|
|
19
|
-
"sizes": "512x512",
|
|
20
|
-
"type": "image/png",
|
|
21
|
-
"purpose": "any maskable"
|
|
22
|
-
}
|
|
23
|
-
]
|
|
24
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "PI WEB",
|
|
3
|
+
"short_name": "PI WEB",
|
|
4
|
+
"description": "Remote web UI and browser control plane for persistent Pi Coding Agent sessions.",
|
|
5
|
+
"start_url": "/",
|
|
6
|
+
"scope": "/",
|
|
7
|
+
"display": "standalone",
|
|
8
|
+
"background_color": "#0d1117",
|
|
9
|
+
"theme_color": "#0d1117",
|
|
10
|
+
"icons": [
|
|
11
|
+
{
|
|
12
|
+
"src": "/pwa-icon-192.png",
|
|
13
|
+
"sizes": "192x192",
|
|
14
|
+
"type": "image/png",
|
|
15
|
+
"purpose": "any maskable"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"src": "/pwa-icon-512.png",
|
|
19
|
+
"sizes": "512x512",
|
|
20
|
+
"type": "image/png",
|
|
21
|
+
"purpose": "any maskable"
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@pi-web/info-plugin",
|
|
3
|
-
"private": true,
|
|
4
|
-
"piWeb": {
|
|
5
|
-
"plugins": [
|
|
6
|
-
{ "id": "info", "module": "pi-web-plugin.js" }
|
|
7
|
-
]
|
|
8
|
-
}
|
|
9
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@pi-web/info-plugin",
|
|
3
|
+
"private": true,
|
|
4
|
+
"piWeb": {
|
|
5
|
+
"plugins": [
|
|
6
|
+
{ "id": "info", "module": "pi-web-plugin.js" }
|
|
7
|
+
]
|
|
8
|
+
}
|
|
9
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Generated from pi-web-plugins
|
|
1
|
+
// Generated from pi-web-plugins/info/pi-web-plugin.ts. Do not edit directly.
|
|
2
2
|
const plugin = {
|
|
3
3
|
apiVersion: 1,
|
|
4
4
|
name: "信息插件",
|
|
@@ -27,21 +27,21 @@ const plugin = {
|
|
|
27
27
|
{
|
|
28
28
|
id: "workspace.info",
|
|
29
29
|
title: "信息",
|
|
30
|
-
icon: svg `
|
|
31
|
-
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
32
|
-
<circle cx="12" cy="12" r="9"></circle>
|
|
33
|
-
<path d="M12 11v5"></path>
|
|
34
|
-
<path d="M12 8h.01"></path>
|
|
35
|
-
</svg>
|
|
30
|
+
icon: svg `
|
|
31
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
32
|
+
<circle cx="12" cy="12" r="9"></circle>
|
|
33
|
+
<path d="M12 11v5"></path>
|
|
34
|
+
<path d="M12 8h.01"></path>
|
|
35
|
+
</svg>
|
|
36
36
|
`,
|
|
37
37
|
order: 1000,
|
|
38
|
-
render: (context) => html `
|
|
39
|
-
<section class="toolbar"><strong>信息</strong></section>
|
|
40
|
-
<section class="viewer">
|
|
41
|
-
<p><strong>工作区</strong></p>
|
|
42
|
-
<p class="muted">${context.workspace.label}</p>
|
|
43
|
-
<p class="muted">${context.workspace.path}</p>
|
|
44
|
-
</section>
|
|
38
|
+
render: (context) => html `
|
|
39
|
+
<section class="toolbar"><strong>信息</strong></section>
|
|
40
|
+
<section class="viewer">
|
|
41
|
+
<p><strong>工作区</strong></p>
|
|
42
|
+
<p class="muted">${context.workspace.label}</p>
|
|
43
|
+
<p class="muted">${context.workspace.path}</p>
|
|
44
|
+
</section>
|
|
45
45
|
`,
|
|
46
46
|
},
|
|
47
47
|
],
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@pi-web/updates-plugin",
|
|
3
|
-
"private": true,
|
|
4
|
-
"piWeb": {
|
|
5
|
-
"plugins": [
|
|
6
|
-
{ "id": "updates", "module": "pi-web-plugin.js" }
|
|
7
|
-
]
|
|
8
|
-
}
|
|
9
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@pi-web/updates-plugin",
|
|
3
|
+
"private": true,
|
|
4
|
+
"piWeb": {
|
|
5
|
+
"plugins": [
|
|
6
|
+
{ "id": "updates", "module": "pi-web-plugin.js" }
|
|
7
|
+
]
|
|
8
|
+
}
|
|
9
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Generated from pi-web-plugins
|
|
1
|
+
// Generated from pi-web-plugins/updates/pi-web-plugin.ts. Do not edit directly.
|
|
2
2
|
function messagesFor(state) {
|
|
3
3
|
return state?.piWebStatus?.messages ?? [];
|
|
4
4
|
}
|
|
@@ -57,22 +57,22 @@ function renderComponent(html, component) {
|
|
|
57
57
|
: component.stale
|
|
58
58
|
? "需要重启"
|
|
59
59
|
: "当前版本";
|
|
60
|
-
return html `
|
|
61
|
-
<div class="updates-version-row">
|
|
62
|
-
<strong>${componentLabel(component.label)}</strong>
|
|
63
|
-
<span>${status}</span>
|
|
64
|
-
<small>运行中 ${formatVersion(component.runtimeVersion)} · 已安装 ${formatVersion(component.installedVersion)}</small>
|
|
65
|
-
<small>${installationLabel(component.installation)}${component.installation?.path === undefined ? "" : ` · ${component.installation.path}`}</small>
|
|
66
|
-
</div>
|
|
60
|
+
return html `
|
|
61
|
+
<div class="updates-version-row">
|
|
62
|
+
<strong>${componentLabel(component.label)}</strong>
|
|
63
|
+
<span>${status}</span>
|
|
64
|
+
<small>运行中 ${formatVersion(component.runtimeVersion)} · 已安装 ${formatVersion(component.installedVersion)}</small>
|
|
65
|
+
<small>${installationLabel(component.installation)}${component.installation?.path === undefined ? "" : ` · ${component.installation.path}`}</small>
|
|
66
|
+
</div>
|
|
67
67
|
`;
|
|
68
68
|
}
|
|
69
69
|
function renderCommand(html, label, command) {
|
|
70
|
-
return html `
|
|
71
|
-
<div class="updates-command">
|
|
72
|
-
<span>${label}</span>
|
|
73
|
-
<code>${command}</code>
|
|
74
|
-
<button @click=${() => { void navigator.clipboard.writeText(command); }}>复制</button>
|
|
75
|
-
</div>
|
|
70
|
+
return html `
|
|
71
|
+
<div class="updates-command">
|
|
72
|
+
<span>${label}</span>
|
|
73
|
+
<code>${command}</code>
|
|
74
|
+
<button @click=${() => { void navigator.clipboard.writeText(command); }}>复制</button>
|
|
75
|
+
</div>
|
|
76
76
|
`;
|
|
77
77
|
}
|
|
78
78
|
function renderCommands(html, status) {
|
|
@@ -85,68 +85,68 @@ function renderCommands(html, status) {
|
|
|
85
85
|
].filter((entry) => typeof entry[1] === "string" && entry[1] !== "");
|
|
86
86
|
if (commands.length === 0)
|
|
87
87
|
return undefined;
|
|
88
|
-
return html `
|
|
89
|
-
<section>
|
|
90
|
-
<strong>建议命令</strong>
|
|
91
|
-
${commands.map(([label, command]) => renderCommand(html, label, command))}
|
|
92
|
-
</section>
|
|
88
|
+
return html `
|
|
89
|
+
<section>
|
|
90
|
+
<strong>建议命令</strong>
|
|
91
|
+
${commands.map(([label, command]) => renderCommand(html, label, command))}
|
|
92
|
+
</section>
|
|
93
93
|
`;
|
|
94
94
|
}
|
|
95
95
|
function renderUpdatesPanel(html, state) {
|
|
96
96
|
const status = statusFor(state);
|
|
97
97
|
if (status === undefined) {
|
|
98
|
-
return html `
|
|
99
|
-
<section class="toolbar"><strong>更新</strong></section>
|
|
100
|
-
<section class="viewer"><p class="muted">正在检查 PI WEB 更新状态…</p></section>
|
|
98
|
+
return html `
|
|
99
|
+
<section class="toolbar"><strong>更新</strong></section>
|
|
100
|
+
<section class="viewer"><p class="muted">正在检查 PI WEB 更新状态…</p></section>
|
|
101
101
|
`;
|
|
102
102
|
}
|
|
103
103
|
const messages = status.messages;
|
|
104
|
-
return html `
|
|
105
|
-
<style>
|
|
106
|
-
.viewer.updates-status { flex: 1 1 auto; min-height: 0; box-sizing: border-box; display: flex; flex-direction: column; gap: 14px; padding: 12px; overflow-y: auto; overflow-x: hidden; }
|
|
107
|
-
.viewer.updates-status section { flex: 0 0 auto; min-width: 0; display: grid; gap: 8px; }
|
|
108
|
-
.updates-message { display: grid; gap: 5px; border: 1px solid var(--pi-border); border-radius: 8px; padding: 10px; background: var(--pi-surface); }
|
|
109
|
-
.updates-message.warning { border-color: var(--pi-warning-border); background: var(--pi-warning-surface); }
|
|
110
|
-
.updates-message.error { border-color: var(--pi-danger); }
|
|
111
|
-
.updates-message-title { display: flex; gap: 8px; align-items: baseline; }
|
|
112
|
-
.updates-message-title span { color: var(--pi-muted); font-size: 12px; text-transform: uppercase; }
|
|
113
|
-
.updates-version-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 3px 10px; border-bottom: 1px solid var(--pi-border-muted); padding: 6px 0; }
|
|
114
|
-
.updates-version-row small { grid-column: 1 / -1; color: var(--pi-muted); }
|
|
115
|
-
.updates-command { min-width: 0; display: grid; grid-template-columns: minmax(90px, auto) minmax(0, 1fr) auto; gap: 8px; align-items: center; }
|
|
116
|
-
.updates-command code { overflow: auto; border: 1px solid var(--pi-border-muted); border-radius: 6px; background: var(--pi-bg); padding: 5px 7px; white-space: nowrap; }
|
|
117
|
-
.updates-meta { display: grid; gap: 2px; color: var(--pi-muted); font-size: 12px; }
|
|
118
|
-
@media (max-width: 520px) {
|
|
119
|
-
.updates-command { grid-template-columns: minmax(0, 1fr) auto; }
|
|
120
|
-
.updates-command > span { grid-column: 1 / -1; }
|
|
121
|
-
}
|
|
122
|
-
</style>
|
|
123
|
-
<section class="toolbar"><strong>更新</strong><span class="stale">测试版</span>${messages.length > 0 ? html `<span class="stale">${String(messages.length)}</span>` : null}</section>
|
|
124
|
-
<section class="viewer updates-status">
|
|
125
|
-
<section>
|
|
126
|
-
${messages.length === 0 ? html `<p class="muted">没有 PI WEB 更新或重启消息。</p>` : messages.map((message) => html `
|
|
127
|
-
<article class=${`updates-message ${message.severity}`}>
|
|
128
|
-
<div class="updates-message-title"><strong>${message.title}</strong><span>${severityLabel(message.severity)}</span></div>
|
|
129
|
-
<p>${message.body}</p>
|
|
130
|
-
${message.command === undefined ? null : html `<code>${message.command}</code>`}
|
|
131
|
-
</article>
|
|
132
|
-
`)}
|
|
133
|
-
</section>
|
|
134
|
-
|
|
135
|
-
<section>
|
|
136
|
-
<strong>已安装服务</strong>
|
|
137
|
-
${renderComponent(html, status.components.web)}
|
|
138
|
-
${renderComponent(html, status.components.sessiond)}
|
|
139
|
-
</section>
|
|
140
|
-
|
|
141
|
-
${renderCommands(html, status)}
|
|
142
|
-
|
|
143
|
-
<section class="updates-meta">
|
|
144
|
-
<span>生成时间 ${status.generatedAt}</span>
|
|
145
|
-
${status.release.latestVersion === undefined ? null : html `<span>最新 npm 版本 ${status.release.latestVersion}</span>`}
|
|
146
|
-
${status.release.skipped === true ? html `<span>远程版本检查已跳过。</span>` : null}
|
|
147
|
-
${status.release.error === undefined ? null : html `<span>远程版本检查失败:${status.release.error}</span>`}
|
|
148
|
-
</section>
|
|
149
|
-
</section>
|
|
104
|
+
return html `
|
|
105
|
+
<style>
|
|
106
|
+
.viewer.updates-status { flex: 1 1 auto; min-height: 0; box-sizing: border-box; display: flex; flex-direction: column; gap: 14px; padding: 12px; overflow-y: auto; overflow-x: hidden; }
|
|
107
|
+
.viewer.updates-status section { flex: 0 0 auto; min-width: 0; display: grid; gap: 8px; }
|
|
108
|
+
.updates-message { display: grid; gap: 5px; border: 1px solid var(--pi-border); border-radius: 8px; padding: 10px; background: var(--pi-surface); }
|
|
109
|
+
.updates-message.warning { border-color: var(--pi-warning-border); background: var(--pi-warning-surface); }
|
|
110
|
+
.updates-message.error { border-color: var(--pi-danger); }
|
|
111
|
+
.updates-message-title { display: flex; gap: 8px; align-items: baseline; }
|
|
112
|
+
.updates-message-title span { color: var(--pi-muted); font-size: 12px; text-transform: uppercase; }
|
|
113
|
+
.updates-version-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 3px 10px; border-bottom: 1px solid var(--pi-border-muted); padding: 6px 0; }
|
|
114
|
+
.updates-version-row small { grid-column: 1 / -1; color: var(--pi-muted); }
|
|
115
|
+
.updates-command { min-width: 0; display: grid; grid-template-columns: minmax(90px, auto) minmax(0, 1fr) auto; gap: 8px; align-items: center; }
|
|
116
|
+
.updates-command code { overflow: auto; border: 1px solid var(--pi-border-muted); border-radius: 6px; background: var(--pi-bg); padding: 5px 7px; white-space: nowrap; }
|
|
117
|
+
.updates-meta { display: grid; gap: 2px; color: var(--pi-muted); font-size: 12px; }
|
|
118
|
+
@media (max-width: 520px) {
|
|
119
|
+
.updates-command { grid-template-columns: minmax(0, 1fr) auto; }
|
|
120
|
+
.updates-command > span { grid-column: 1 / -1; }
|
|
121
|
+
}
|
|
122
|
+
</style>
|
|
123
|
+
<section class="toolbar"><strong>更新</strong><span class="stale">测试版</span>${messages.length > 0 ? html `<span class="stale">${String(messages.length)}</span>` : null}</section>
|
|
124
|
+
<section class="viewer updates-status">
|
|
125
|
+
<section>
|
|
126
|
+
${messages.length === 0 ? html `<p class="muted">没有 PI WEB 更新或重启消息。</p>` : messages.map((message) => html `
|
|
127
|
+
<article class=${`updates-message ${message.severity}`}>
|
|
128
|
+
<div class="updates-message-title"><strong>${message.title}</strong><span>${severityLabel(message.severity)}</span></div>
|
|
129
|
+
<p>${message.body}</p>
|
|
130
|
+
${message.command === undefined ? null : html `<code>${message.command}</code>`}
|
|
131
|
+
</article>
|
|
132
|
+
`)}
|
|
133
|
+
</section>
|
|
134
|
+
|
|
135
|
+
<section>
|
|
136
|
+
<strong>已安装服务</strong>
|
|
137
|
+
${renderComponent(html, status.components.web)}
|
|
138
|
+
${renderComponent(html, status.components.sessiond)}
|
|
139
|
+
</section>
|
|
140
|
+
|
|
141
|
+
${renderCommands(html, status)}
|
|
142
|
+
|
|
143
|
+
<section class="updates-meta">
|
|
144
|
+
<span>生成时间 ${status.generatedAt}</span>
|
|
145
|
+
${status.release.latestVersion === undefined ? null : html `<span>最新 npm 版本 ${status.release.latestVersion}</span>`}
|
|
146
|
+
${status.release.skipped === true ? html `<span>远程版本检查已跳过。</span>` : null}
|
|
147
|
+
${status.release.error === undefined ? null : html `<span>远程版本检查失败:${status.release.error}</span>`}
|
|
148
|
+
</section>
|
|
149
|
+
</section>
|
|
150
150
|
`;
|
|
151
151
|
}
|
|
152
152
|
const plugin = {
|
|
@@ -158,13 +158,13 @@ const plugin = {
|
|
|
158
158
|
{
|
|
159
159
|
id: "workspace.updates",
|
|
160
160
|
title: "更新",
|
|
161
|
-
icon: svg `
|
|
162
|
-
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
163
|
-
<path d="M20 6v5h-5"></path>
|
|
164
|
-
<path d="M4 18v-5h5"></path>
|
|
165
|
-
<path d="M18.4 9A7 7 0 0 0 6.1 6.7L4 8.8"></path>
|
|
166
|
-
<path d="M5.6 15A7 7 0 0 0 17.9 17.3L20 15.2"></path>
|
|
167
|
-
</svg>
|
|
161
|
+
icon: svg `
|
|
162
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
163
|
+
<path d="M20 6v5h-5"></path>
|
|
164
|
+
<path d="M4 18v-5h5"></path>
|
|
165
|
+
<path d="M18.4 9A7 7 0 0 0 6.1 6.7L4 8.8"></path>
|
|
166
|
+
<path d="M5.6 15A7 7 0 0 0 17.9 17.3L20 15.2"></path>
|
|
167
|
+
</svg>
|
|
168
168
|
`,
|
|
169
169
|
order: 100,
|
|
170
170
|
visible: (context) => shouldShowUpdatesPanel(context.state),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Generated from pi-web-plugins
|
|
1
|
+
// Generated from pi-web-plugins/workspace-tasks/config.ts. Do not edit directly.
|
|
2
2
|
export const TASKS_CONFIG_PATH = ".pi-web/tasks.json";
|
|
3
3
|
export const TASKS_CONFIG_VERSION = 1;
|
|
4
4
|
const taskIdPattern = /^[a-z][a-z0-9.-]*$/u;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@pi-web/workspace-tasks-plugin",
|
|
3
|
-
"private": true,
|
|
4
|
-
"piWeb": {
|
|
5
|
-
"plugins": [
|
|
6
|
-
{ "id": "workspace-tasks", "module": "pi-web-plugin.js" }
|
|
7
|
-
]
|
|
8
|
-
}
|
|
9
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@pi-web/workspace-tasks-plugin",
|
|
3
|
+
"private": true,
|
|
4
|
+
"piWeb": {
|
|
5
|
+
"plugins": [
|
|
6
|
+
{ "id": "workspace-tasks", "module": "pi-web-plugin.js" }
|
|
7
|
+
]
|
|
8
|
+
}
|
|
9
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Generated from pi-web-plugins
|
|
1
|
+
// Generated from pi-web-plugins/workspace-tasks/pi-web-plugin.ts. Do not edit directly.
|
|
2
2
|
import { TASKS_CONFIG_PATH } from "./config.js";
|
|
3
3
|
import { defineTasksPanelElement, tasksPanelBadge } from "./tasksPanelElement.js";
|
|
4
4
|
const plugin = {
|
|
@@ -26,15 +26,15 @@ const plugin = {
|
|
|
26
26
|
{
|
|
27
27
|
id: "workspace.tasks",
|
|
28
28
|
title: "任务",
|
|
29
|
-
icon: svg `
|
|
30
|
-
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
31
|
-
<path d="M9 6h11"></path>
|
|
32
|
-
<path d="M9 12h11"></path>
|
|
33
|
-
<path d="M9 18h11"></path>
|
|
34
|
-
<path d="m4 6 .8 .8L6.5 5"></path>
|
|
35
|
-
<path d="m4 12 .8 .8 1.7-1.8"></path>
|
|
36
|
-
<path d="m4 18 .8 .8 1.7-1.8"></path>
|
|
37
|
-
</svg>
|
|
29
|
+
icon: svg `
|
|
30
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
31
|
+
<path d="M9 6h11"></path>
|
|
32
|
+
<path d="M9 12h11"></path>
|
|
33
|
+
<path d="M9 18h11"></path>
|
|
34
|
+
<path d="m4 6 .8 .8L6.5 5"></path>
|
|
35
|
+
<path d="m4 12 .8 .8 1.7-1.8"></path>
|
|
36
|
+
<path d="m4 18 .8 .8 1.7-1.8"></path>
|
|
37
|
+
</svg>
|
|
38
38
|
`,
|
|
39
39
|
order: 40,
|
|
40
40
|
badge: (context) => tasksPanelBadge(context),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Generated from pi-web-plugins
|
|
1
|
+
// Generated from pi-web-plugins/workspace-tasks/taskRunner.ts. Do not edit directly.
|
|
2
2
|
export function runWorkspaceTaskInTerminal(terminal, task) {
|
|
3
3
|
return terminal.runCommand({
|
|
4
4
|
title: task.title,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Generated from pi-web-plugins
|
|
1
|
+
// Generated from pi-web-plugins/workspace-tasks/tasksPanelElement.ts. Do not edit directly.
|
|
2
2
|
import { TASKS_CONFIG_PATH } from "./config.js";
|
|
3
3
|
import { runWorkspaceTaskInTerminal } from "./taskRunner.js";
|
|
4
4
|
import { loadWorkspaceTasksConfig, tasksConfigRefreshHint, tasksConfigUnavailableMessage } from "./workspaceTasksClient.js";
|
|
@@ -55,19 +55,19 @@ class PiWebTasksPanel extends HTMLElement {
|
|
|
55
55
|
return;
|
|
56
56
|
}
|
|
57
57
|
const state = getOrLoadWorkspaceConfig(context);
|
|
58
|
-
this.root.innerHTML = `
|
|
59
|
-
${taskStyles()}
|
|
60
|
-
<section class="toolbar">
|
|
61
|
-
<strong>工作区任务</strong>
|
|
62
|
-
<span class="toolbar-tasks">
|
|
63
|
-
<button class="secondary" data-refresh-config ${state.kind === "loading" ? "disabled" : ""}>刷新</button>
|
|
64
|
-
<button class="secondary" data-open-terminal>打开终端</button>
|
|
65
|
-
</span>
|
|
66
|
-
</section>
|
|
67
|
-
${this.renderStatus()}
|
|
68
|
-
<section class="viewer tasks-viewer">
|
|
69
|
-
${this.renderConfigState(state)}
|
|
70
|
-
</section>
|
|
58
|
+
this.root.innerHTML = `
|
|
59
|
+
${taskStyles()}
|
|
60
|
+
<section class="toolbar">
|
|
61
|
+
<strong>工作区任务</strong>
|
|
62
|
+
<span class="toolbar-tasks">
|
|
63
|
+
<button class="secondary" data-refresh-config ${state.kind === "loading" ? "disabled" : ""}>刷新</button>
|
|
64
|
+
<button class="secondary" data-open-terminal>打开终端</button>
|
|
65
|
+
</span>
|
|
66
|
+
</section>
|
|
67
|
+
${this.renderStatus()}
|
|
68
|
+
<section class="viewer tasks-viewer">
|
|
69
|
+
${this.renderConfigState(state)}
|
|
70
|
+
</section>
|
|
71
71
|
`;
|
|
72
72
|
this.root.querySelector("button[data-refresh-config]")?.addEventListener("click", () => {
|
|
73
73
|
void this.refreshConfig(context);
|
|
@@ -104,9 +104,9 @@ class PiWebTasksPanel extends HTMLElement {
|
|
|
104
104
|
return renderUnavailableState(state);
|
|
105
105
|
if (state.config.tasks.length === 0)
|
|
106
106
|
return `<p class="muted">${escapeHtml(state.path)} 中没有定义任务。请在文件中添加任务,然后点击刷新。</p>`;
|
|
107
|
-
return `
|
|
108
|
-
<p class="muted">任务会在专用工作区终端中运行,并切换到该终端。编辑 ${escapeHtml(state.path)} 后点击刷新重新加载。</p>
|
|
109
|
-
${renderTaskGroups(state.config.tasks, this.runningTaskId)}
|
|
107
|
+
return `
|
|
108
|
+
<p class="muted">任务会在专用工作区终端中运行,并切换到该终端。编辑 ${escapeHtml(state.path)} 后点击刷新重新加载。</p>
|
|
109
|
+
${renderTaskGroups(state.config.tasks, this.runningTaskId)}
|
|
110
110
|
`;
|
|
111
111
|
}
|
|
112
112
|
renderStatus() {
|
|
@@ -233,15 +233,15 @@ function renderTask(task, runningTaskId) {
|
|
|
233
233
|
const running = runningTaskId === task.id;
|
|
234
234
|
const disabled = runningTaskId !== undefined;
|
|
235
235
|
const description = task.description === undefined ? "" : `<span>${escapeHtml(task.description)}</span>`;
|
|
236
|
-
return `
|
|
237
|
-
<article class="task-card">
|
|
238
|
-
<div class="task-copy">
|
|
239
|
-
<strong>${escapeHtml(task.title)}</strong>
|
|
240
|
-
${description}
|
|
241
|
-
<code>${escapeHtml(task.command)}</code>
|
|
242
|
-
</div>
|
|
243
|
-
<button data-task-id="${escapeAttr(task.id)}" ${disabled ? "disabled" : ""}>${running ? "正在分发…" : "运行"}</button>
|
|
244
|
-
</article>
|
|
236
|
+
return `
|
|
237
|
+
<article class="task-card">
|
|
238
|
+
<div class="task-copy">
|
|
239
|
+
<strong>${escapeHtml(task.title)}</strong>
|
|
240
|
+
${description}
|
|
241
|
+
<code>${escapeHtml(task.command)}</code>
|
|
242
|
+
</div>
|
|
243
|
+
<button data-task-id="${escapeAttr(task.id)}" ${disabled ? "disabled" : ""}>${running ? "正在分发…" : "运行"}</button>
|
|
244
|
+
</article>
|
|
245
245
|
`;
|
|
246
246
|
}
|
|
247
247
|
function taskFromConfigState(state, taskId) {
|
|
@@ -250,38 +250,38 @@ function taskFromConfigState(state, taskId) {
|
|
|
250
250
|
return state.config.tasks.find((task) => task.id === taskId);
|
|
251
251
|
}
|
|
252
252
|
function taskStyles() {
|
|
253
|
-
return `
|
|
254
|
-
<style>
|
|
255
|
-
:host { display: contents; }
|
|
256
|
-
.toolbar { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 10px 12px; border-bottom: 1px solid var(--pi-border-muted); }
|
|
257
|
-
.toolbar-tasks { display: inline-flex; flex-wrap: wrap; justify-content: flex-end; gap: 8px; }
|
|
258
|
-
.viewer { box-sizing: border-box; min-height: 0; overflow: auto; padding: 12px; }
|
|
259
|
-
.tasks-viewer { display: grid; align-content: start; gap: 12px; }
|
|
260
|
-
.tasks { display: grid; gap: 14px; }
|
|
261
|
-
.task-group { display: grid; gap: 10px; }
|
|
262
|
-
.task-group h3 { margin: 4px 0 0; color: var(--pi-text-secondary); font-size: 13px; text-transform: uppercase; letter-spacing: 0.04em; }
|
|
263
|
-
.task-card { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 12px; align-items: center; border: 1px solid var(--pi-border); border-radius: 10px; background: var(--pi-surface); padding: 12px; }
|
|
264
|
-
.task-copy { display: grid; min-width: 0; gap: 5px; }
|
|
265
|
-
.task-copy span, .muted { color: var(--pi-muted); }
|
|
266
|
-
code, pre { border: 1px solid var(--pi-border-muted); border-radius: 6px; background: var(--pi-bg); color: var(--pi-text-secondary); font: 12px ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
|
|
267
|
-
code { overflow: auto; padding: 5px 7px; white-space: nowrap; }
|
|
268
|
-
pre { margin: 8px 0 0; overflow: auto; padding: 8px; white-space: pre-wrap; }
|
|
269
|
-
button { border: 1px solid var(--pi-accent-border); border-radius: 7px; background: var(--pi-accent); color: var(--pi-bg); cursor: pointer; padding: 6px 10px; font: inherit; }
|
|
270
|
-
button.secondary { border-color: var(--pi-border); background: var(--pi-surface); color: var(--pi-text); }
|
|
271
|
-
button:disabled { cursor: wait; opacity: 0.65; }
|
|
272
|
-
.empty-state { border: 1px dashed var(--pi-border-muted); border-radius: 8px; color: var(--pi-muted); padding: 12px; }
|
|
273
|
-
.empty-state p { margin: 6px 0 0; }
|
|
274
|
-
.panel-status { margin: 12px 12px 0; }
|
|
275
|
-
.status { border: 1px solid var(--pi-border); border-radius: 8px; padding: 10px; }
|
|
276
|
-
.status.info { border-color: var(--pi-accent-border); background: var(--pi-bg-overlay-soft); }
|
|
277
|
-
.status.success { border-color: var(--pi-success-border); background: var(--pi-success-surface); color: var(--pi-success); }
|
|
278
|
-
.status.error { border-color: var(--pi-danger); color: var(--pi-danger); }
|
|
279
|
-
.empty { padding: 16px; color: var(--pi-muted); }
|
|
280
|
-
@media (max-width: 760px) {
|
|
281
|
-
.task-card { grid-template-columns: 1fr; }
|
|
282
|
-
.task-card button { justify-self: start; }
|
|
283
|
-
}
|
|
284
|
-
</style>
|
|
253
|
+
return `
|
|
254
|
+
<style>
|
|
255
|
+
:host { display: contents; }
|
|
256
|
+
.toolbar { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 10px 12px; border-bottom: 1px solid var(--pi-border-muted); }
|
|
257
|
+
.toolbar-tasks { display: inline-flex; flex-wrap: wrap; justify-content: flex-end; gap: 8px; }
|
|
258
|
+
.viewer { box-sizing: border-box; min-height: 0; overflow: auto; padding: 12px; }
|
|
259
|
+
.tasks-viewer { display: grid; align-content: start; gap: 12px; }
|
|
260
|
+
.tasks { display: grid; gap: 14px; }
|
|
261
|
+
.task-group { display: grid; gap: 10px; }
|
|
262
|
+
.task-group h3 { margin: 4px 0 0; color: var(--pi-text-secondary); font-size: 13px; text-transform: uppercase; letter-spacing: 0.04em; }
|
|
263
|
+
.task-card { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 12px; align-items: center; border: 1px solid var(--pi-border); border-radius: 10px; background: var(--pi-surface); padding: 12px; }
|
|
264
|
+
.task-copy { display: grid; min-width: 0; gap: 5px; }
|
|
265
|
+
.task-copy span, .muted { color: var(--pi-muted); }
|
|
266
|
+
code, pre { border: 1px solid var(--pi-border-muted); border-radius: 6px; background: var(--pi-bg); color: var(--pi-text-secondary); font: 12px ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
|
|
267
|
+
code { overflow: auto; padding: 5px 7px; white-space: nowrap; }
|
|
268
|
+
pre { margin: 8px 0 0; overflow: auto; padding: 8px; white-space: pre-wrap; }
|
|
269
|
+
button { border: 1px solid var(--pi-accent-border); border-radius: 7px; background: var(--pi-accent); color: var(--pi-bg); cursor: pointer; padding: 6px 10px; font: inherit; }
|
|
270
|
+
button.secondary { border-color: var(--pi-border); background: var(--pi-surface); color: var(--pi-text); }
|
|
271
|
+
button:disabled { cursor: wait; opacity: 0.65; }
|
|
272
|
+
.empty-state { border: 1px dashed var(--pi-border-muted); border-radius: 8px; color: var(--pi-muted); padding: 12px; }
|
|
273
|
+
.empty-state p { margin: 6px 0 0; }
|
|
274
|
+
.panel-status { margin: 12px 12px 0; }
|
|
275
|
+
.status { border: 1px solid var(--pi-border); border-radius: 8px; padding: 10px; }
|
|
276
|
+
.status.info { border-color: var(--pi-accent-border); background: var(--pi-bg-overlay-soft); }
|
|
277
|
+
.status.success { border-color: var(--pi-success-border); background: var(--pi-success-surface); color: var(--pi-success); }
|
|
278
|
+
.status.error { border-color: var(--pi-danger); color: var(--pi-danger); }
|
|
279
|
+
.empty { padding: 16px; color: var(--pi-muted); }
|
|
280
|
+
@media (max-width: 760px) {
|
|
281
|
+
.task-card { grid-template-columns: 1fr; }
|
|
282
|
+
.task-card button { justify-self: start; }
|
|
283
|
+
}
|
|
284
|
+
</style>
|
|
285
285
|
`;
|
|
286
286
|
}
|
|
287
287
|
function escapeHtml(value) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Generated from pi-web-plugins
|
|
1
|
+
// Generated from pi-web-plugins/workspace-tasks/workspaceTasksClient.ts. Do not edit directly.
|
|
2
2
|
import { TASKS_CONFIG_PATH, parseTasksConfigText } from "./config.js";
|
|
3
3
|
export const tasksConfigMissingMessage = "这里还没有配置工作区任务。";
|
|
4
4
|
export const tasksConfigMissingHint = `${TASKS_CONFIG_PATH} 是可选文件。如果需要自定义任务,请在当前工作区创建它。`;
|
package/docs/assets/favicon.svg
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" role="img" aria-labelledby="title desc">
|
|
2
|
-
<title id="title">PI WEB mark</title>
|
|
3
|
-
<desc id="desc">A horizontal brand bar.</desc>
|
|
4
|
-
<style>
|
|
5
|
-
.bar { fill: #00f0d8; }
|
|
6
|
-
@media (prefers-color-scheme: light) {
|
|
7
|
-
.bar { fill: #008c82; }
|
|
8
|
-
}
|
|
9
|
-
</style>
|
|
10
|
-
<rect class="bar" x="128" y="448" width="768" height="128"/>
|
|
11
|
-
</svg>
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" role="img" aria-labelledby="title desc">
|
|
2
|
+
<title id="title">PI WEB mark</title>
|
|
3
|
+
<desc id="desc">A horizontal brand bar.</desc>
|
|
4
|
+
<style>
|
|
5
|
+
.bar { fill: #00f0d8; }
|
|
6
|
+
@media (prefers-color-scheme: light) {
|
|
7
|
+
.bar { fill: #008c82; }
|
|
8
|
+
}
|
|
9
|
+
</style>
|
|
10
|
+
<rect class="bar" x="128" y="448" width="768" height="128"/>
|
|
11
|
+
</svg>
|