@ashwin-pc/pi-web 0.1.2
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/.pi/extensions/auto-session-name.ts +82 -0
- package/LICENSE +21 -0
- package/README.md +162 -0
- package/bin/pi-web.js +35 -0
- package/contexts/web-ui.md +18 -0
- package/dist/apple-touch-icon.png +0 -0
- package/dist/assets/index-BNqFbA4l.css +1 -0
- package/dist/assets/index-RfnHuF-b.js +79 -0
- package/dist/icon.svg +4 -0
- package/dist/index.html +174 -0
- package/dist/manifest.webmanifest +1 -0
- package/dist/pwa-192x192.png +0 -0
- package/dist/pwa-512x512.png +0 -0
- package/dist/registerSW.js +1 -0
- package/dist/sw.js +128 -0
- package/dist/workbox-a24bf94b.js +3645 -0
- package/docs/frontend-architecture.md +72 -0
- package/package.json +55 -0
- package/server/extensions.ts +121 -0
- package/server/mock.ts +402 -0
- package/server/settings.ts +155 -0
- package/server/types.ts +76 -0
- package/server.ts +1789 -0
- package/supervisor.ts +205 -0
package/dist/icon.svg
ADDED
package/dist/index.html
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
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" />
|
|
6
|
+
<title>pi web</title>
|
|
7
|
+
<meta name="theme-color" content="#1a1a1a" />
|
|
8
|
+
<meta name="apple-mobile-web-app-capable" content="yes" />
|
|
9
|
+
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
|
10
|
+
<meta name="apple-mobile-web-app-title" content="pi" />
|
|
11
|
+
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
|
|
12
|
+
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
|
|
13
|
+
<script type="module" crossorigin src="/assets/index-RfnHuF-b.js"></script>
|
|
14
|
+
<link rel="stylesheet" crossorigin href="/assets/index-BNqFbA4l.css">
|
|
15
|
+
<link rel="manifest" href="/manifest.webmanifest"><script id="vite-plugin-pwa:register-sw" src="/registerSW.js"></script></head>
|
|
16
|
+
<body>
|
|
17
|
+
<div id="tokenOverlay" class="tokenOverlay" hidden>
|
|
18
|
+
<form id="tokenForm" class="tokenForm">
|
|
19
|
+
<label for="tokenInput">Enter PI_WEB_TOKEN to continue</label>
|
|
20
|
+
<input id="tokenInput" type="password" placeholder="Token" autocomplete="current-password" />
|
|
21
|
+
<button type="submit" class="primaryAction">Connect</button>
|
|
22
|
+
</form>
|
|
23
|
+
</div>
|
|
24
|
+
<main class="app">
|
|
25
|
+
<div id="statusBar" class="statusBar">
|
|
26
|
+
<button id="sessionButton" class="iconButton statusBarButton" type="button" aria-label="Sessions" title="Sessions">
|
|
27
|
+
<span data-icon="menu"></span>
|
|
28
|
+
</button>
|
|
29
|
+
<span id="statusTitle" class="statusTitle"></span>
|
|
30
|
+
<span id="statusPath" class="statusPath"></span>
|
|
31
|
+
<span id="connectionStatus" class="connectionStatus" aria-live="polite" hidden></span>
|
|
32
|
+
<button id="newSessionHeaderButton" class="iconButton statusBarButton" type="button" aria-label="New session" title="New session">
|
|
33
|
+
<span data-icon="square-pen"></span>
|
|
34
|
+
</button>
|
|
35
|
+
<button id="conversationTreeButton" class="iconButton statusBarButton" type="button" aria-label="Conversation tree" title="Conversation tree">
|
|
36
|
+
<span data-icon="git-fork"></span>
|
|
37
|
+
</button>
|
|
38
|
+
<button id="gitButton" class="iconButton statusBarButton" type="button" aria-label="Git" title="Git">
|
|
39
|
+
<span data-icon="git-branch"></span>
|
|
40
|
+
</button>
|
|
41
|
+
<button id="settingsButton" class="iconButton statusBarButton" type="button" aria-label="Settings" title="Settings">
|
|
42
|
+
<span data-icon="settings"></span>
|
|
43
|
+
</button>
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
<aside id="gitPanel" class="gitPanel" aria-label="Git" hidden>
|
|
47
|
+
<div class="gitPanelHeader">
|
|
48
|
+
<h2>Git</h2>
|
|
49
|
+
<div class="gitTabs" role="tablist" aria-label="Git views">
|
|
50
|
+
<button id="gitStatusTab" type="button" class="gitTab active">Status</button>
|
|
51
|
+
<button id="gitGraphTab" type="button" class="gitTab">Graph</button>
|
|
52
|
+
</div>
|
|
53
|
+
<button id="gitCloseButton" class="iconButton" type="button" aria-label="Close Git" title="Close Git">×</button>
|
|
54
|
+
</div>
|
|
55
|
+
<div class="gitPanelBody">
|
|
56
|
+
<div id="gitPrimaryPane" class="gitPrimaryPane"></div>
|
|
57
|
+
<div id="gitDetailPane" class="gitDetailPane"></div>
|
|
58
|
+
</div>
|
|
59
|
+
</aside>
|
|
60
|
+
|
|
61
|
+
<section id="messages" class="messages" aria-live="polite"></section>
|
|
62
|
+
<div id="emptyCwdChooser" class="emptyCwdChooser" hidden>
|
|
63
|
+
<div class="emptyCwdInner">
|
|
64
|
+
<div class="emptyCwdLabel">Working directory</div>
|
|
65
|
+
<div class="emptyCwdPath"></div>
|
|
66
|
+
<button type="button" class="emptyCwdButton">Change folder</button>
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
|
|
70
|
+
<div id="sessionBackdrop" class="sessionBackdrop" hidden></div>
|
|
71
|
+
<aside id="sessionDrawer" class="sessionDrawer" aria-label="Sessions" hidden>
|
|
72
|
+
<div class="sessionDrawerHeader">
|
|
73
|
+
<h2>Sessions</h2>
|
|
74
|
+
<button id="sessionCloseButton" class="iconButton" type="button" aria-label="Close sessions" title="Close sessions">×</button>
|
|
75
|
+
</div>
|
|
76
|
+
<div id="sessionList" class="sessionList" aria-live="polite"></div>
|
|
77
|
+
<button id="sessionNewButton" class="sessionNewButton" type="button">+ New session</button>
|
|
78
|
+
</aside>
|
|
79
|
+
|
|
80
|
+
<div id="settingsBackdrop" class="settingsBackdrop" hidden></div>
|
|
81
|
+
<aside id="settingsPanel" class="settingsPanel" aria-label="Settings" hidden>
|
|
82
|
+
<div class="settingsHeader">
|
|
83
|
+
<h2>Settings</h2>
|
|
84
|
+
<button id="settingsCloseButton" class="iconButton" type="button" aria-label="Close settings" title="Close settings">×</button>
|
|
85
|
+
</div>
|
|
86
|
+
<section class="settingsSection">
|
|
87
|
+
<h3>Appearance</h3>
|
|
88
|
+
<label class="settingsField">
|
|
89
|
+
<span>Density</span>
|
|
90
|
+
<select id="settingDensitySelect">
|
|
91
|
+
<option value="comfortable">Comfortable</option>
|
|
92
|
+
<option value="compact">Compact</option>
|
|
93
|
+
</select>
|
|
94
|
+
</label>
|
|
95
|
+
</section>
|
|
96
|
+
<section class="settingsSection">
|
|
97
|
+
<h3>Composer</h3>
|
|
98
|
+
<label class="settingsField">
|
|
99
|
+
<span>Default queue mode</span>
|
|
100
|
+
<select id="settingQueueModeSelect">
|
|
101
|
+
<option value="steer">Steer while running</option>
|
|
102
|
+
<option value="followUp">Follow up after running</option>
|
|
103
|
+
</select>
|
|
104
|
+
</label>
|
|
105
|
+
<label class="settingsCheckbox">
|
|
106
|
+
<input id="settingComposerExpandedCheckbox" type="checkbox" />
|
|
107
|
+
<span>Keep composer expanded</span>
|
|
108
|
+
</label>
|
|
109
|
+
</section>
|
|
110
|
+
<section class="settingsSection">
|
|
111
|
+
<h3>New sessions</h3>
|
|
112
|
+
<p class="settingsHint">Saved model defaults are applied when starting a new session.</p>
|
|
113
|
+
<div class="settingsValue" id="settingModelDefaultsValue">No default model saved</div>
|
|
114
|
+
<div class="settingsActions">
|
|
115
|
+
<button id="settingSaveModelDefaultsButton" type="button">Use current model</button>
|
|
116
|
+
<button id="settingClearModelDefaultsButton" type="button">Clear</button>
|
|
117
|
+
</div>
|
|
118
|
+
</section>
|
|
119
|
+
<span id="settingsStatus" class="settingsStatus" aria-live="polite"></span>
|
|
120
|
+
</aside>
|
|
121
|
+
|
|
122
|
+
<form id="promptForm" class="composer">
|
|
123
|
+
<button id="contextMeter" class="contextMeter unknown" type="button" aria-haspopup="dialog" aria-expanded="false" aria-controls="contextMeterPopover" title="Context usage unavailable">
|
|
124
|
+
<span class="contextMeterTrack" aria-hidden="true"><span id="contextMeterFill" class="contextMeterFill"></span></span>
|
|
125
|
+
<span id="contextMeterLabel" class="contextMeterLabel">ctx —</span>
|
|
126
|
+
</button>
|
|
127
|
+
<div id="contextMeterPopover" class="contextMeterPopover" role="dialog" aria-label="Context usage" hidden></div>
|
|
128
|
+
<textarea id="prompt" rows="2" placeholder="Ask pi…" aria-controls="slashCommands" aria-expanded="false"></textarea>
|
|
129
|
+
<div id="slashCommands" class="slashCommandsPopover" role="listbox" aria-label="Slash commands" hidden></div>
|
|
130
|
+
<button id="expandButton" class="iconButton expandButton" type="button" aria-label="Expand editor" title="Expand editor">
|
|
131
|
+
<span data-icon="maximize-2"></span>
|
|
132
|
+
</button>
|
|
133
|
+
<div id="attachments" class="attachments" aria-live="polite"></div>
|
|
134
|
+
<input id="imageInput" type="file" accept="image/png,image/jpeg,image/gif,image/webp" multiple hidden />
|
|
135
|
+
<div class="composerFooter">
|
|
136
|
+
<div id="modelControl" class="modelControl">
|
|
137
|
+
<button id="modelSettingsButton" class="modelSettingsButton" type="button" aria-haspopup="dialog" aria-expanded="false" aria-controls="modelSettingsPopover" title="Model and reasoning settings">
|
|
138
|
+
<span id="modelSettingsLabel" class="modelSettingsLabel">Loading models…</span>
|
|
139
|
+
<span id="modelSettingsThinking" class="modelSettingsThinking">off</span>
|
|
140
|
+
</button>
|
|
141
|
+
<div id="modelSettingsPopover" class="modelSettingsPopover" role="dialog" aria-label="Model and reasoning settings" hidden>
|
|
142
|
+
<label class="modelSettingsField">
|
|
143
|
+
<span>Model</span>
|
|
144
|
+
<select id="modelSelect" title="Select model" aria-label="Select model">
|
|
145
|
+
<option value="">Loading models…</option>
|
|
146
|
+
</select>
|
|
147
|
+
</label>
|
|
148
|
+
<label class="modelSettingsField">
|
|
149
|
+
<span>Reasoning</span>
|
|
150
|
+
<select id="thinkingSelect" title="Select reasoning level" aria-label="Select reasoning level">
|
|
151
|
+
<option value="off">off</option>
|
|
152
|
+
</select>
|
|
153
|
+
</label>
|
|
154
|
+
<p class="modelSettingsHint">Choose <strong>off</strong> to disable reasoning when the model supports it.</p>
|
|
155
|
+
</div>
|
|
156
|
+
</div>
|
|
157
|
+
<button id="queueToggle" class="iconButton" type="button" aria-pressed="true" aria-label="Queue mode: steer" title="Queue mode: steer">
|
|
158
|
+
<span data-icon="route"></span>
|
|
159
|
+
</button>
|
|
160
|
+
<button id="attachButton" class="iconButton" type="button" aria-label="Attach images" title="Attach images">
|
|
161
|
+
<span data-icon="paperclip"></span>
|
|
162
|
+
</button>
|
|
163
|
+
<button id="stopButton" class="iconButton dangerAction" type="button" aria-label="Stop streaming" title="Stop streaming" style="display:none">
|
|
164
|
+
<span data-icon="square"></span>
|
|
165
|
+
</button>
|
|
166
|
+
<button id="primaryButton" class="iconButton primaryAction" type="submit" aria-label="Send" title="Send">
|
|
167
|
+
<span data-icon="send-horizontal"></span>
|
|
168
|
+
</button>
|
|
169
|
+
</div>
|
|
170
|
+
</form>
|
|
171
|
+
<div id="sessionBar" class="sessionBar" hidden></div>
|
|
172
|
+
</main>
|
|
173
|
+
</body>
|
|
174
|
+
</html>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"name":"pi web","short_name":"pi","description":"pi coding agent web UI","start_url":"/","display":"standalone","background_color":"#1a1a1a","theme_color":"#1a1a1a","lang":"en","scope":"/","icons":[{"src":"pwa-192x192.png","sizes":"192x192","type":"image/png"},{"src":"pwa-512x512.png","sizes":"512x512","type":"image/png","purpose":"any maskable"}]}
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
if('serviceWorker' in navigator) {window.addEventListener('load', () => {navigator.serviceWorker.register('/sw.js', { scope: '/' })})}
|
package/dist/sw.js
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2018 Google Inc. All Rights Reserved.
|
|
3
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License.
|
|
5
|
+
* You may obtain a copy of the License at
|
|
6
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
8
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
9
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
10
|
+
* See the License for the specific language governing permissions and
|
|
11
|
+
* limitations under the License.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
// If the loader is already loaded, just stop.
|
|
15
|
+
if (!self.define) {
|
|
16
|
+
let registry = {};
|
|
17
|
+
|
|
18
|
+
// Used for `eval` and `importScripts` where we can't get script URL by other means.
|
|
19
|
+
// In both cases, it's safe to use a global var because those functions are synchronous.
|
|
20
|
+
let nextDefineUri;
|
|
21
|
+
|
|
22
|
+
const singleRequire = (uri, parentUri) => {
|
|
23
|
+
uri = new URL(uri + ".js", parentUri).href;
|
|
24
|
+
return registry[uri] || (
|
|
25
|
+
|
|
26
|
+
new Promise(resolve => {
|
|
27
|
+
if ("document" in self) {
|
|
28
|
+
const script = document.createElement("script");
|
|
29
|
+
script.src = uri;
|
|
30
|
+
script.onload = resolve;
|
|
31
|
+
document.head.appendChild(script);
|
|
32
|
+
} else {
|
|
33
|
+
nextDefineUri = uri;
|
|
34
|
+
importScripts(uri);
|
|
35
|
+
resolve();
|
|
36
|
+
}
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
.then(() => {
|
|
40
|
+
let promise = registry[uri];
|
|
41
|
+
if (!promise) {
|
|
42
|
+
throw new Error(`Module ${uri} didn’t register its module`);
|
|
43
|
+
}
|
|
44
|
+
return promise;
|
|
45
|
+
})
|
|
46
|
+
);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
self.define = (depsNames, factory) => {
|
|
50
|
+
const uri = nextDefineUri || ("document" in self ? document.currentScript.src : "") || location.href;
|
|
51
|
+
if (registry[uri]) {
|
|
52
|
+
// Module is already loading or loaded.
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
let exports = {};
|
|
56
|
+
const require = depUri => singleRequire(depUri, uri);
|
|
57
|
+
const specialDeps = {
|
|
58
|
+
module: { uri },
|
|
59
|
+
exports,
|
|
60
|
+
require
|
|
61
|
+
};
|
|
62
|
+
registry[uri] = Promise.all(depsNames.map(
|
|
63
|
+
depName => specialDeps[depName] || require(depName)
|
|
64
|
+
)).then(deps => {
|
|
65
|
+
factory(...deps);
|
|
66
|
+
return exports;
|
|
67
|
+
});
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
define(['./workbox-a24bf94b'], (function (workbox) { 'use strict';
|
|
71
|
+
|
|
72
|
+
self.skipWaiting();
|
|
73
|
+
workbox.clientsClaim();
|
|
74
|
+
/**
|
|
75
|
+
* The precacheAndRoute() method efficiently caches and responds to
|
|
76
|
+
* requests for URLs in the manifest.
|
|
77
|
+
* See https://goo.gl/S9QRab
|
|
78
|
+
*/
|
|
79
|
+
workbox.precacheAndRoute([{
|
|
80
|
+
"url": "registerSW.js",
|
|
81
|
+
"revision": "1872c500de691dce40960bb85481de07"
|
|
82
|
+
}, {
|
|
83
|
+
"url": "pwa-512x512.png",
|
|
84
|
+
"revision": "a3b6e257d5f88d21847670b8a945414d"
|
|
85
|
+
}, {
|
|
86
|
+
"url": "pwa-192x192.png",
|
|
87
|
+
"revision": "f31b8a5e9d558a2705b4aa105bf0746d"
|
|
88
|
+
}, {
|
|
89
|
+
"url": "index.html",
|
|
90
|
+
"revision": "9d33046e5c8053fa498e1119ba755d65"
|
|
91
|
+
}, {
|
|
92
|
+
"url": "icon.svg",
|
|
93
|
+
"revision": "6d0b7529947ef4fc567cf4d4753c7f28"
|
|
94
|
+
}, {
|
|
95
|
+
"url": "apple-touch-icon.png",
|
|
96
|
+
"revision": "e7f5e0d5552e5ba16aceb226e2eb7f65"
|
|
97
|
+
}, {
|
|
98
|
+
"url": "assets/index-RfnHuF-b.js",
|
|
99
|
+
"revision": null
|
|
100
|
+
}, {
|
|
101
|
+
"url": "assets/index-BNqFbA4l.css",
|
|
102
|
+
"revision": null
|
|
103
|
+
}, {
|
|
104
|
+
"url": "apple-touch-icon.png",
|
|
105
|
+
"revision": "e7f5e0d5552e5ba16aceb226e2eb7f65"
|
|
106
|
+
}, {
|
|
107
|
+
"url": "icon.svg",
|
|
108
|
+
"revision": "6d0b7529947ef4fc567cf4d4753c7f28"
|
|
109
|
+
}, {
|
|
110
|
+
"url": "pwa-192x192.png",
|
|
111
|
+
"revision": "f31b8a5e9d558a2705b4aa105bf0746d"
|
|
112
|
+
}, {
|
|
113
|
+
"url": "pwa-512x512.png",
|
|
114
|
+
"revision": "a3b6e257d5f88d21847670b8a945414d"
|
|
115
|
+
}, {
|
|
116
|
+
"url": "manifest.webmanifest",
|
|
117
|
+
"revision": "7b2c8583d476b0aca4076855a98fac4b"
|
|
118
|
+
}], {});
|
|
119
|
+
workbox.cleanupOutdatedCaches();
|
|
120
|
+
workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("/index.html")));
|
|
121
|
+
workbox.registerRoute(({
|
|
122
|
+
request
|
|
123
|
+
}) => request.mode === "navigate", new workbox.NetworkFirst({
|
|
124
|
+
"cacheName": "pages",
|
|
125
|
+
plugins: []
|
|
126
|
+
}), 'GET');
|
|
127
|
+
|
|
128
|
+
}));
|