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.
Files changed (54) hide show
  1. package/README.md +53 -6
  2. package/dist/activity.js +178 -0
  3. package/dist/agent-feed.js +133 -0
  4. package/dist/agent-templates.js +144 -0
  5. package/dist/agents.js +671 -152
  6. package/dist/auth.js +3 -1
  7. package/dist/collab/baseline.js +84 -0
  8. package/dist/collab/dispatcher.js +45 -10
  9. package/dist/collab/hub.js +1392 -384
  10. package/dist/collab/pi-extension.js +322 -65
  11. package/dist/collab/review-flow.js +197 -48
  12. package/dist/collab/routes.js +94 -23
  13. package/dist/collab/schemas.js +69 -13
  14. package/dist/collab/scoring-flow.js +145 -39
  15. package/dist/collab/similarity.js +15 -0
  16. package/dist/collab/store.js +467 -112
  17. package/dist/collab/types.js +94 -10
  18. package/dist/collab/validate.js +62 -25
  19. package/dist/drafts.js +26 -6
  20. package/dist/http/agent-routes.js +222 -0
  21. package/dist/http/login-limiter.js +53 -0
  22. package/dist/http/mail-settings-routes.js +53 -0
  23. package/dist/http/system-prompt-routes.js +52 -0
  24. package/dist/http/utils.js +47 -0
  25. package/dist/http/web-assets.js +64 -0
  26. package/dist/http/workspace-routes.js +58 -0
  27. package/dist/mail-notifier.js +63 -17
  28. package/dist/main.js +61 -16
  29. package/dist/mcp.js +24 -5
  30. package/dist/metadata-store.js +203 -56
  31. package/dist/paths.js +10 -0
  32. package/dist/sdk-backend.js +249 -45
  33. package/dist/server.js +488 -614
  34. package/dist/session-namer.js +66 -17
  35. package/dist/session-performance.js +137 -0
  36. package/dist/sotto-stt.js +217 -0
  37. package/dist/terminals.js +94 -27
  38. package/dist/timeline.js +185 -0
  39. package/dist/voice.js +153 -35
  40. package/dist/workspaces.js +91 -26
  41. package/dist/ws/agent-socket.js +256 -0
  42. package/dist/ws/terminal-socket.js +46 -0
  43. package/npm-shrinkwrap.json +3685 -0
  44. package/package.json +11 -1
  45. package/packages/protocol/openapi.yaml +24 -2
  46. package/packages/protocol/websocket.schema.json +58 -15
  47. package/web/activity-view.js +121 -0
  48. package/web/app.js +3647 -756
  49. package/web/backend-state.js +59 -27
  50. package/web/collab.js +684 -257
  51. package/web/hid-keyboard.js +173 -140
  52. package/web/index.html +7 -2
  53. package/web/styles.css +21 -2
  54. package/web/voice-pcm.js +36 -0
@@ -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 => String(value || '').split('\\').join('/').replace(/\/+/g, '/').replace(/\/$/, '') || '/';
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, bestLength = -1;
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) { best = workspace; bestLength = root.length; }
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(bindings.map(binding => {
85
- const agentId = String(binding?.agentId || '');
86
- return {...binding, agentId:agentId.includes(':') ? agentId : resourceKey(LEGACY_BACKEND_ID, agentId)};
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 => ({id:entry.id, name:String(entry.name || ''), base:normalizeBase(entry.base), token:String(entry.token || '')}));
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 [{id:LEGACY_BACKEND_ID, name:'本机', base:normalizeBase(storage.rpBase || origin), token:String(storage.rpToken || '')}];
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 (wanted && items.find(item => item.base === wanted)) || items.find(item => item.token) || items[0] || null;
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(next.map(item => ({id:item.id, name:item.name, base:item.base, token:item.token})));
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 => createBackend({...entry, saved:Boolean(entry.token)}));
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(this.items.map(backend => ({
186
- id: backend.id,
187
- name: backend.name,
188
- base: backend.base,
189
- token: backend.saved ? backend.token : '',
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
  })();