claude-simple 0.2.6 → 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 (60) hide show
  1. package/README.md +2 -0
  2. package/dist/app.0.2.8.min.js +1080 -0
  3. package/dist/index.html +2 -2
  4. package/dist/style.0.2.8.min.css +1598 -0
  5. package/gateway.js +0 -0
  6. package/package.json +1 -1
  7. package/public/addon-fit.min.js +0 -0
  8. package/public/agent-panel.js +245 -1
  9. package/public/api.js +4 -0
  10. package/public/app.js +0 -0
  11. package/public/base.css +0 -0
  12. package/public/cache.js +0 -0
  13. package/public/chat.js +118 -17
  14. package/public/files.js +0 -0
  15. package/public/git.js +0 -0
  16. package/public/icons/icon-180.png +0 -0
  17. package/public/icons/icon-192.png +0 -0
  18. package/public/icons/icon-512.png +0 -0
  19. package/public/icons/icon-maskable-512.png +0 -0
  20. package/public/index.html +2 -2
  21. package/public/lib.js +0 -0
  22. package/public/manifest.webmanifest +0 -0
  23. package/public/mobile.js +0 -0
  24. package/public/notifications.js +215 -0
  25. package/public/offline.html +0 -0
  26. package/public/pwa.js +0 -0
  27. package/public/router.js +0 -0
  28. package/public/settings.js +0 -0
  29. package/public/shell/boot.js +0 -0
  30. package/public/shell/dashboard.js +72 -23
  31. package/public/shell/hub.js +0 -0
  32. package/public/shell/layout.js +41 -12
  33. package/public/shell/notes.js +0 -0
  34. package/public/shell/session-context.js +0 -0
  35. package/public/shell/session-list.js +27 -28
  36. package/public/shell/session-nav.js +36 -1
  37. package/public/shell/templates.js +45 -7
  38. package/public/shell/util.js +0 -0
  39. package/public/shell.js +56 -7
  40. package/public/state.js +53 -13
  41. package/public/style.css +100 -6
  42. package/public/sw.js +2 -2
  43. package/public/terminal.js +77 -3
  44. package/public/wake-lock.js +0 -0
  45. package/public/xterm.min.css +0 -0
  46. package/public/xterm.min.js +0 -0
  47. package/src/agents/claude.js +1 -1
  48. package/src/agents/codex.js +1 -0
  49. package/src/agents/grok.js +180 -298
  50. package/src/agents/meta-agent.js +332 -1
  51. package/src/agents/models.js +0 -0
  52. package/src/agents/sessions.js +106 -26
  53. package/src/agents/stream-batch.js +0 -0
  54. package/src/app.js +88 -11
  55. package/src/auto-update.js +0 -0
  56. package/src/runtime/approvals.js +0 -0
  57. package/src/runtime/outbox.js +0 -0
  58. package/src/runtime/protocol.js +0 -0
  59. package/dist/app.0.2.6.min.js +0 -953
  60. package/dist/style.0.2.6.min.css +0 -1504
package/src/app.js CHANGED
@@ -18,6 +18,8 @@ import {
18
18
  scanAllSessions,
19
19
  loadSessionMessages,
20
20
  loadSessionMemory,
21
+ readSessionMemoryFile,
22
+ loadSessionJsonl,
21
23
  loadSessionUsage,
22
24
  searchActivity,
23
25
  groupByProject,
@@ -1008,19 +1010,37 @@ export function createApp() {
1008
1010
  codexHome: CODEX_HOME,
1009
1011
  grokHome: GROK_HOME,
1010
1012
  };
1011
- const order = [...new Set([preferred, ...ENABLED_AGENTS, 'claude', 'codex', 'grok'].filter(Boolean))];
1013
+ // A selected session already knows its agent. Do not fall back to another
1014
+ // agent's account-level memory (especially Codex) when that session has none.
1015
+ const order = preferred
1016
+ ? [preferred]
1017
+ : [...new Set([...ENABLED_AGENTS, 'claude', 'codex', 'grok'])];
1012
1018
  let memory = null;
1013
1019
  for (const a of order) {
1014
1020
  memory = await loadSessionMemory(sessionId, a, opts);
1015
1021
  if (memory) break;
1016
1022
  }
1017
- // Memory is Claude-centric; return empty instead of 404 so the tab doesn't hard-fail
1018
- res.json(memory || { index: null, files: [] });
1023
+ res.json(memory || { agent: preferred || null, files: [] });
1019
1024
  } catch (e) {
1020
1025
  res.status(500).json({ error: e.message });
1021
1026
  }
1022
1027
  });
1023
1028
 
1029
+ app.get('/api/sessions/:sessionId/memory/file', authMiddleware, async (req, res) => {
1030
+ try {
1031
+ const { sessionId } = req.params;
1032
+ const agent = typeof req.query.agent === 'string' ? req.query.agent : 'claude';
1033
+ const file = typeof req.query.file === 'string' ? req.query.file : '';
1034
+ if (!/^[0-9a-f-]{36}$/i.test(sessionId)) return res.status(400).json({ error: 'Invalid session id' });
1035
+ const row = await readSessionMemoryFile(sessionId, agent, file, {
1036
+ claudeConfigDirs: CLAUDE_CONFIG_DIRS, codexHome: CODEX_HOME, grokHome: GROK_HOME,
1037
+ });
1038
+ if (!row) return res.status(404).json({ error: 'Memory file not found' });
1039
+ res.setHeader('Cache-Control', 'private, max-age=30');
1040
+ res.json(row);
1041
+ } catch (e) { res.status(500).json({ error: e.message }); }
1042
+ });
1043
+
1024
1044
  app.get('/api/projects/:id/git/log', authMiddleware, async (req, res) => {
1025
1045
  try {
1026
1046
  const projectPath = resolveProjectRoot(req);
@@ -1044,10 +1064,12 @@ export function createApp() {
1044
1064
  listSessions,
1045
1065
  searchActivity,
1046
1066
  loadSessionMessages,
1067
+ loadSessionJsonl,
1047
1068
  groupByProject,
1048
1069
  toClientSession,
1049
1070
  getProjectNotesStore: loadProjectNotes,
1050
1071
  saveProjectNotesStore: saveProjectNotes,
1072
+ getSessionMetaStore: loadSessionMeta,
1051
1073
  normalizeProjectEntry,
1052
1074
  git,
1053
1075
  isGitRepo,
@@ -1122,6 +1144,50 @@ export function createApp() {
1122
1144
  }
1123
1145
  });
1124
1146
 
1147
+ app.get('/api/ai/notes', authMiddleware, async (req, res) => {
1148
+ try {
1149
+ const limit = Math.min(parseInt(req.query.limit || '30', 10) || 30, 200);
1150
+ const scope = typeof req.query.scope === 'string' ? req.query.scope : 'all';
1151
+ const q = typeof req.query.q === 'string' ? req.query.q : '';
1152
+ const cwd = typeof req.query.cwd === 'string' ? req.query.cwd : '';
1153
+ const sessionId = typeof req.query.sessionId === 'string' ? req.query.sessionId : '';
1154
+ const agent = typeof req.query.agent === 'string' ? req.query.agent : '';
1155
+ res.json({
1156
+ notes: await meta.listMetaNotes({ limit, scope, q, cwd, sessionId, agent }),
1157
+ });
1158
+ } catch (e) {
1159
+ res.status(500).json({ error: e.message });
1160
+ }
1161
+ });
1162
+
1163
+ app.get('/api/ai/notes/:id', authMiddleware, async (req, res) => {
1164
+ try {
1165
+ const note = await meta.getMetaNote(req.params.id);
1166
+ if (!note) return res.status(404).json({ error: 'not found' });
1167
+ res.json(note);
1168
+ } catch (e) {
1169
+ res.status(500).json({ error: e.message });
1170
+ }
1171
+ });
1172
+
1173
+ app.post('/api/ai/notes', authMiddleware, async (req, res) => {
1174
+ try {
1175
+ const note = await meta.saveMetaNote(req.body || {});
1176
+ res.json(note);
1177
+ } catch (e) {
1178
+ res.status(500).json({ error: e.message });
1179
+ }
1180
+ });
1181
+
1182
+ app.delete('/api/ai/notes/:id', authMiddleware, async (req, res) => {
1183
+ try {
1184
+ const result = await meta.deleteMetaNote(req.params.id);
1185
+ res.json(result);
1186
+ } catch (e) {
1187
+ res.status(500).json({ error: e.message });
1188
+ }
1189
+ });
1190
+
1125
1191
  // SSE: generate work report
1126
1192
  app.post('/api/ai/report', authMiddleware, async (req, res) => {
1127
1193
  res.setHeader('Content-Type', 'text/event-stream; charset=utf-8');
@@ -1392,24 +1458,35 @@ export function createApp() {
1392
1458
  if (cmd.sessionId) options.sessionId = cmd.sessionId;
1393
1459
  if (cmd.cwd) options.cwd = cmd.cwd;
1394
1460
  if (options.sessionId) client.sessionId = options.sessionId;
1395
- const agentSend = createAgentSend(outbox, agent);
1461
+ // A socket may subscribe to another session while this agent is still
1462
+ // streaming. Keep this run's delivery target in its own closure rather
1463
+ // than consulting mutable client.sessionId in the shared socket outbox.
1464
+ let runSessionId = options.sessionId || client.sessionId || null;
1465
+ const runOutbox = createOutbox((data) => {
1466
+ broadcastChat(runSessionId, data, ws);
1467
+ }, {
1468
+ maxWait: 48,
1469
+ maxDeltaChars: 720,
1470
+ maxBatchItems: 10,
1471
+ maxBatchBytes: 10_000,
1472
+ });
1473
+ const agentSend = createAgentSend(runOutbox, agent);
1396
1474
  const runSend = (data) => {
1475
+ if (data?.sessionId) runSessionId = data.sessionId;
1397
1476
  if (data?.type === 'result' || data?.type === 'complete' || data?.type === 'error') {
1398
- markSessionIdle(data.sessionId || client.sessionId, options.sessionId);
1399
- outbox.flush();
1477
+ markSessionIdle(data.sessionId || runSessionId, options.sessionId);
1478
+ runOutbox.flush();
1400
1479
  }
1401
- if (data?.sessionId) client.sessionId = data.sessionId;
1402
- if (data?.type === 'session-created' && data.sessionId) client.sessionId = data.sessionId;
1403
1480
  // permission_request bypasses map filter double-pass carefully
1404
1481
  if (data?.type === 'permission_request' || data?.type === 'permission_resolved') {
1405
- outbox.send(data);
1406
- outbox.flush();
1482
+ runOutbox.send(data);
1483
+ runOutbox.flush();
1407
1484
  return;
1408
1485
  }
1409
1486
  agentSend(data);
1410
1487
  };
1411
1488
  await dispatchAgent(agent, cmd.command || '', options, runSend);
1412
- outbox.flush();
1489
+ runOutbox.flush();
1413
1490
  return;
1414
1491
  }
1415
1492
 
File without changes
File without changes
File without changes
File without changes