pi2web 0.2.1 → 0.2.8
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 +53 -6
- package/dist/activity.js +178 -0
- package/dist/agent-feed.js +133 -0
- package/dist/agent-templates.js +144 -0
- package/dist/agents.js +671 -152
- package/dist/auth.js +3 -1
- package/dist/collab/baseline.js +84 -0
- package/dist/collab/dispatcher.js +45 -10
- package/dist/collab/hub.js +1392 -384
- package/dist/collab/pi-extension.js +322 -65
- package/dist/collab/review-flow.js +197 -48
- package/dist/collab/routes.js +94 -23
- package/dist/collab/schemas.js +69 -13
- package/dist/collab/scoring-flow.js +145 -39
- package/dist/collab/similarity.js +15 -0
- package/dist/collab/store.js +467 -112
- package/dist/collab/types.js +94 -10
- package/dist/collab/validate.js +62 -25
- package/dist/drafts.js +26 -6
- package/dist/http/agent-routes.js +222 -0
- package/dist/http/login-limiter.js +53 -0
- package/dist/http/mail-settings-routes.js +53 -0
- package/dist/http/system-prompt-routes.js +52 -0
- package/dist/http/utils.js +47 -0
- package/dist/http/web-assets.js +64 -0
- package/dist/http/workspace-routes.js +58 -0
- package/dist/mail-notifier.js +63 -17
- package/dist/main.js +61 -16
- package/dist/mcp.js +24 -5
- package/dist/metadata-store.js +203 -56
- package/dist/paths.js +10 -0
- package/dist/sdk-backend.js +249 -45
- package/dist/server.js +488 -614
- package/dist/session-namer.js +66 -17
- package/dist/session-performance.js +137 -0
- package/dist/sotto-stt.js +217 -0
- package/dist/terminals.js +94 -27
- package/dist/timeline.js +185 -0
- package/dist/voice.js +153 -35
- package/dist/workspaces.js +91 -26
- package/dist/ws/agent-socket.js +256 -0
- package/dist/ws/terminal-socket.js +46 -0
- package/npm-shrinkwrap.json +3685 -0
- package/package.json +11 -1
- package/packages/protocol/openapi.yaml +24 -2
- package/packages/protocol/websocket.schema.json +58 -15
- package/web/activity-view.js +121 -0
- package/web/app.js +3647 -756
- package/web/backend-state.js +59 -27
- package/web/collab.js +684 -257
- package/web/hid-keyboard.js +173 -140
- package/web/index.html +7 -2
- package/web/styles.css +21 -2
- package/web/voice-pcm.js +36 -0
package/web/backend-state.js
CHANGED
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
reconnectTimer: null,
|
|
26
26
|
reconnectAttempt: 0,
|
|
27
27
|
manuallyClosed: false,
|
|
28
|
-
reconnecting: false
|
|
28
|
+
reconnecting: false
|
|
29
29
|
};
|
|
30
30
|
}
|
|
31
31
|
|
|
@@ -37,7 +37,12 @@
|
|
|
37
37
|
return `${backendId}:${remoteId}`;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
const normalizePath = value =>
|
|
40
|
+
const normalizePath = value =>
|
|
41
|
+
String(value || '')
|
|
42
|
+
.split('\\')
|
|
43
|
+
.join('/')
|
|
44
|
+
.replace(/\/+/g, '/')
|
|
45
|
+
.replace(/\/$/, '') || '/';
|
|
41
46
|
const isInsidePath = (file, dir) => file === dir || file.startsWith(`${dir}/`);
|
|
42
47
|
|
|
43
48
|
/**
|
|
@@ -47,11 +52,15 @@
|
|
|
47
52
|
*/
|
|
48
53
|
function matchWorkspace(workspaces, cwd) {
|
|
49
54
|
const target = normalizePath(cwd);
|
|
50
|
-
let best = null,
|
|
55
|
+
let best = null,
|
|
56
|
+
bestLength = -1;
|
|
51
57
|
for (const workspace of workspaces || []) {
|
|
52
58
|
const root = normalizePath(workspace.rootPath);
|
|
53
59
|
if (!isInsidePath(target, root)) continue;
|
|
54
|
-
if (root.length > bestLength) {
|
|
60
|
+
if (root.length > bestLength) {
|
|
61
|
+
best = workspace;
|
|
62
|
+
bestLength = root.length;
|
|
63
|
+
}
|
|
55
64
|
}
|
|
56
65
|
return best;
|
|
57
66
|
}
|
|
@@ -68,11 +77,6 @@
|
|
|
68
77
|
if (selectedAgentId && !selectedAgentId.includes(':')) {
|
|
69
78
|
const compositeId = resourceKey(LEGACY_BACKEND_ID, selectedAgentId);
|
|
70
79
|
storage.rpAgentId = compositeId;
|
|
71
|
-
const cursorKey = `rpSeq:${selectedAgentId}`;
|
|
72
|
-
if (storage[cursorKey] !== undefined) {
|
|
73
|
-
storage[`rpSeq:${compositeId}`] = storage[cursorKey];
|
|
74
|
-
delete storage[cursorKey];
|
|
75
|
-
}
|
|
76
80
|
}
|
|
77
81
|
for (const key of ['rpTerminalId', 'rpWorkspaceId']) {
|
|
78
82
|
const value = String(storage[key] || '');
|
|
@@ -81,10 +85,15 @@
|
|
|
81
85
|
try {
|
|
82
86
|
const bindings = JSON.parse(storage.rpSessionKeyboardBindings || '[]');
|
|
83
87
|
if (!Array.isArray(bindings)) return;
|
|
84
|
-
storage.rpSessionKeyboardBindings = JSON.stringify(
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
+
storage.rpSessionKeyboardBindings = JSON.stringify(
|
|
89
|
+
bindings.map(binding => {
|
|
90
|
+
const agentId = String(binding?.agentId || '');
|
|
91
|
+
return {
|
|
92
|
+
...binding,
|
|
93
|
+
agentId: agentId.includes(':') ? agentId : resourceKey(LEGACY_BACKEND_ID, agentId)
|
|
94
|
+
};
|
|
95
|
+
})
|
|
96
|
+
);
|
|
88
97
|
} catch {}
|
|
89
98
|
}
|
|
90
99
|
|
|
@@ -98,7 +107,12 @@
|
|
|
98
107
|
if (!Array.isArray(entries)) return null;
|
|
99
108
|
return entries
|
|
100
109
|
.filter(entry => entry && typeof entry.id === 'string' && typeof entry.base === 'string')
|
|
101
|
-
.map(entry => ({
|
|
110
|
+
.map(entry => ({
|
|
111
|
+
id: entry.id,
|
|
112
|
+
name: String(entry.name || ''),
|
|
113
|
+
base: normalizeBase(entry.base),
|
|
114
|
+
token: String(entry.token || '')
|
|
115
|
+
}));
|
|
102
116
|
} catch {
|
|
103
117
|
return null;
|
|
104
118
|
}
|
|
@@ -116,14 +130,26 @@
|
|
|
116
130
|
// Migrating without a code keeps their Backend id, so those keep matching after pairing again.
|
|
117
131
|
if (!storage.rpToken && !storage.rpBase) return [];
|
|
118
132
|
migrateLegacySelections(storage);
|
|
119
|
-
return [
|
|
133
|
+
return [
|
|
134
|
+
{
|
|
135
|
+
id: LEGACY_BACKEND_ID,
|
|
136
|
+
name: '本机',
|
|
137
|
+
base: normalizeBase(storage.rpBase || origin),
|
|
138
|
+
token: String(storage.rpToken || '')
|
|
139
|
+
}
|
|
140
|
+
];
|
|
120
141
|
}
|
|
121
142
|
|
|
122
143
|
/** Connection a page should offer first: the one for `base`, else any with a saved pairing code. */
|
|
123
144
|
function selectConnection(storage, origin, base = '') {
|
|
124
145
|
const items = savedConnections(storage, origin);
|
|
125
146
|
const wanted = normalizeBase(base);
|
|
126
|
-
return (
|
|
147
|
+
return (
|
|
148
|
+
(wanted && items.find(item => item.base === wanted)) ||
|
|
149
|
+
items.find(item => item.token) ||
|
|
150
|
+
items[0] ||
|
|
151
|
+
null
|
|
152
|
+
);
|
|
127
153
|
}
|
|
128
154
|
|
|
129
155
|
/** Upserts a connection without touching the other entries. The code is stored only on request. */
|
|
@@ -132,12 +158,14 @@
|
|
|
132
158
|
if (!value) return null;
|
|
133
159
|
const items = savedConnections(storage, value);
|
|
134
160
|
const existing = items.find(item => item.base === value);
|
|
135
|
-
const entry = existing || {id:createBackendId(), name:'', base:value, token:''};
|
|
161
|
+
const entry = existing || {id: createBackendId(), name: '', base: value, token: ''};
|
|
136
162
|
if (name) entry.name = String(name);
|
|
137
163
|
if (!entry.name) entry.name = value;
|
|
138
164
|
entry.token = remember ? String(token || '') : '';
|
|
139
165
|
const next = existing ? items : [...items, entry];
|
|
140
|
-
storage[CONNECTIONS_KEY] = JSON.stringify(
|
|
166
|
+
storage[CONNECTIONS_KEY] = JSON.stringify(
|
|
167
|
+
next.map(item => ({id: item.id, name: item.name, base: item.base, token: item.token}))
|
|
168
|
+
);
|
|
141
169
|
// The list is authoritative from here on, so the migrated single-backend copy of the code must not
|
|
142
170
|
// survive: keeping it would leave a pairing code behind that the user just asked to forget.
|
|
143
171
|
delete storage.rpToken;
|
|
@@ -145,7 +173,9 @@
|
|
|
145
173
|
}
|
|
146
174
|
|
|
147
175
|
function loadStoredBackends(storage, origin) {
|
|
148
|
-
return savedConnections(storage, origin).map(entry =>
|
|
176
|
+
return savedConnections(storage, origin).map(entry =>
|
|
177
|
+
createBackend({...entry, saved: Boolean(entry.token)})
|
|
178
|
+
);
|
|
149
179
|
}
|
|
150
180
|
|
|
151
181
|
class BackendRegistry {
|
|
@@ -182,12 +212,14 @@
|
|
|
182
212
|
}
|
|
183
213
|
|
|
184
214
|
persist() {
|
|
185
|
-
this.storage[CONNECTIONS_KEY] = JSON.stringify(
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
215
|
+
this.storage[CONNECTIONS_KEY] = JSON.stringify(
|
|
216
|
+
this.items.map(backend => ({
|
|
217
|
+
id: backend.id,
|
|
218
|
+
name: backend.name,
|
|
219
|
+
base: backend.base,
|
|
220
|
+
token: backend.saved ? backend.token : ''
|
|
221
|
+
}))
|
|
222
|
+
);
|
|
191
223
|
// The list is authoritative now, so the migrated single-backend copy of the code must not survive.
|
|
192
224
|
delete this.storage.rpToken;
|
|
193
225
|
}
|
|
@@ -214,7 +246,7 @@
|
|
|
214
246
|
backendId: backend.id,
|
|
215
247
|
backendName: backend.name,
|
|
216
248
|
remoteId,
|
|
217
|
-
[idProperty]: resourceKey(backend.id, remoteId)
|
|
249
|
+
[idProperty]: resourceKey(backend.id, remoteId)
|
|
218
250
|
};
|
|
219
251
|
}
|
|
220
252
|
}
|
|
@@ -232,6 +264,6 @@
|
|
|
232
264
|
splitResourceKey,
|
|
233
265
|
normalizePath,
|
|
234
266
|
isInsidePath,
|
|
235
|
-
matchWorkspace
|
|
267
|
+
matchWorkspace
|
|
236
268
|
};
|
|
237
269
|
})();
|