@axhub/genie 0.2.8 → 0.2.9

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 (83) hide show
  1. package/LICENSE +21 -675
  2. package/dist/api-docs.html +2 -2
  3. package/dist/assets/App-GBcTeeUS.js +460 -0
  4. package/dist/assets/ReviewApp-C9K--AQE.js +1 -0
  5. package/dist/assets/{_basePickBy-CqJbRZ9y.js → _basePickBy-DR_8uFCo.js} +1 -1
  6. package/dist/assets/{_baseUniq-BS8YH8jO.js → _baseUniq-D0njlQ_7.js} +1 -1
  7. package/dist/assets/{arc-BBmKEN-S.js → arc-CKlr_Rec.js} +1 -1
  8. package/dist/assets/{architectureDiagram-2XIMDMQ5-N5lcb82R.js → architectureDiagram-2XIMDMQ5-BmO_uLUH.js} +1 -1
  9. package/dist/assets/{blockDiagram-WCTKOSBZ-DTMwHuLn.js → blockDiagram-WCTKOSBZ-DhAeO-56.js} +1 -1
  10. package/dist/assets/{c4Diagram-IC4MRINW-BTKlkXI9.js → c4Diagram-IC4MRINW-C67kFoXx.js} +1 -1
  11. package/dist/assets/channel-V3MBjKys.js +1 -0
  12. package/dist/assets/{chunk-4BX2VUAB-DUdoTxAc.js → chunk-4BX2VUAB-mLLagvJi.js} +1 -1
  13. package/dist/assets/{chunk-55IACEB6-Bm_92xe4.js → chunk-55IACEB6-Lx-hOjlM.js} +1 -1
  14. package/dist/assets/{chunk-FMBD7UC4-CGW0g62g.js → chunk-FMBD7UC4-Bt-XmVUV.js} +1 -1
  15. package/dist/assets/{chunk-JSJVCQXG-DYkTH3w1.js → chunk-JSJVCQXG-Cya6gaDV.js} +1 -1
  16. package/dist/assets/{chunk-KX2RTZJC-C9oTlISU.js → chunk-KX2RTZJC-Bd7Ig6tF.js} +1 -1
  17. package/dist/assets/{chunk-NQ4KR5QH-CM50ygWP.js → chunk-NQ4KR5QH-5UAE0Vg-.js} +1 -1
  18. package/dist/assets/{chunk-QZHKN3VN-7dzpYeNJ.js → chunk-QZHKN3VN-BAxZ8m7w.js} +1 -1
  19. package/dist/assets/{chunk-WL4C6EOR-Cm9nQrsr.js → chunk-WL4C6EOR-DjDPvUUP.js} +1 -1
  20. package/dist/assets/classDiagram-VBA2DB6C-C790yYiY.js +1 -0
  21. package/dist/assets/classDiagram-v2-RAHNMMFH-C790yYiY.js +1 -0
  22. package/dist/assets/clone-BbMGfZwt.js +1 -0
  23. package/dist/assets/{cose-bilkent-S5V4N54A-Ccp_p0JZ.js → cose-bilkent-S5V4N54A-D-60XrkJ.js} +1 -1
  24. package/dist/assets/{dagre-KLK3FWXG-fBwTLUp9.js → dagre-KLK3FWXG-bqu3ZS4K.js} +1 -1
  25. package/dist/assets/{diagram-E7M64L7V-CeNVmFUp.js → diagram-E7M64L7V-BueeqoYm.js} +1 -1
  26. package/dist/assets/{diagram-IFDJBPK2-CtavyLGa.js → diagram-IFDJBPK2-D4fDv2E7.js} +1 -1
  27. package/dist/assets/{diagram-P4PSJMXO-CpQTjQwc.js → diagram-P4PSJMXO-WqipY3fN.js} +1 -1
  28. package/dist/assets/{erDiagram-INFDFZHY-B8R5vwhd.js → erDiagram-INFDFZHY-D0oVnO-x.js} +1 -1
  29. package/dist/assets/{flowDiagram-PKNHOUZH-BvkVVwIQ.js → flowDiagram-PKNHOUZH-DzbGyxrr.js} +1 -1
  30. package/dist/assets/{ganttDiagram-A5KZAMGK-DOu3hSNa.js → ganttDiagram-A5KZAMGK-BwhbbgCP.js} +1 -1
  31. package/dist/assets/{gitGraphDiagram-K3NZZRJ6-C7zT67YE.js → gitGraphDiagram-K3NZZRJ6-DZgAh_KM.js} +1 -1
  32. package/dist/assets/{graph-D11wiwHo.js → graph-DzKos-N0.js} +1 -1
  33. package/dist/assets/{highlighted-body-TPN3WLV5-Babpthg-.js → highlighted-body-TPN3WLV5-CKDMgz3X.js} +1 -1
  34. package/dist/assets/{index-DFxzgWoO.js → index-DiQlHzGj.js} +2 -2
  35. package/dist/assets/index-Drat2nB9.css +1 -0
  36. package/dist/assets/{infoDiagram-LFFYTUFH-BmA7IpQG.js → infoDiagram-LFFYTUFH-BFicZbTf.js} +1 -1
  37. package/dist/assets/{ishikawaDiagram-PHBUUO56-BEquZd3E.js → ishikawaDiagram-PHBUUO56-CtihxDxl.js} +1 -1
  38. package/dist/assets/{journeyDiagram-4ABVD52K-BfemGz7f.js → journeyDiagram-4ABVD52K-Du00J8_d.js} +1 -1
  39. package/dist/assets/{kanban-definition-K7BYSVSG-CWja3mln.js → kanban-definition-K7BYSVSG-BJi9S0iQ.js} +1 -1
  40. package/dist/assets/{layout-BLUNf-PJ.js → layout-B80Sityu.js} +1 -1
  41. package/dist/assets/{linear-DukIV_Xv.js → linear-sRQLOf5H.js} +1 -1
  42. package/dist/assets/{mermaid-O7DHMXV3-SgtM28qI.js → mermaid-O7DHMXV3-CBuVs4eJ.js} +6 -6
  43. package/dist/assets/{mindmap-definition-YRQLILUH-4UjqXITU.js → mindmap-definition-YRQLILUH-C5IL_xi-.js} +1 -1
  44. package/dist/assets/{pieDiagram-SKSYHLDU-8AxqJd0M.js → pieDiagram-SKSYHLDU-CeTwlJ8z.js} +1 -1
  45. package/dist/assets/{quadrantDiagram-337W2JSQ-D60m8V8r.js → quadrantDiagram-337W2JSQ-COfUcLWt.js} +1 -1
  46. package/dist/assets/{requirementDiagram-Z7DCOOCP-zqh9jBVf.js → requirementDiagram-Z7DCOOCP-DSb-CJ5B.js} +1 -1
  47. package/dist/assets/{sankeyDiagram-WA2Y5GQK-CDZILTLI.js → sankeyDiagram-WA2Y5GQK-8jtuVb45.js} +1 -1
  48. package/dist/assets/{sequenceDiagram-2WXFIKYE-7BReFd0L.js → sequenceDiagram-2WXFIKYE-C2VpkMwA.js} +1 -1
  49. package/dist/assets/{stateDiagram-RAJIS63D-HPTVdIG4.js → stateDiagram-RAJIS63D-fmwMqxxc.js} +1 -1
  50. package/dist/assets/stateDiagram-v2-FVOUBMTO-9GGXVWrR.js +1 -0
  51. package/dist/assets/{timeline-definition-YZTLITO2-CTVllFgr.js → timeline-definition-YZTLITO2-Dx1hP5lg.js} +1 -1
  52. package/dist/assets/{treemap-KZPCXAKY-BtyxboJZ.js → treemap-KZPCXAKY-CkLOdYCZ.js} +1 -1
  53. package/dist/assets/{vendor-codemirror-Dz7_EqNA.js → vendor-codemirror-BxPY6emf.js} +1 -1
  54. package/dist/assets/{vendor-react-Cpt6D04s.js → vendor-react-xmA_f8ig.js} +1 -1
  55. package/dist/assets/{vennDiagram-LZ73GAT5-D96ZI6Mg.js → vennDiagram-LZ73GAT5-D6KWcnln.js} +1 -1
  56. package/dist/assets/{xychartDiagram-JWTSCODW-eRk-39YO.js → xychartDiagram-JWTSCODW-6fh6qmzN.js} +1 -1
  57. package/dist/index.html +5 -5
  58. package/package.json +3 -3
  59. package/server/acp-runtime/client.js +9 -2
  60. package/server/acp-runtime/session-store.js +4 -4
  61. package/server/cli.js +23 -2
  62. package/server/external-agent/service.js +24 -6
  63. package/server/external-agent/ws.js +63 -3
  64. package/server/index.js +34 -5
  65. package/server/projects.js +536 -161
  66. package/server/routes/session-core.js +149 -86
  67. package/server/session-core/eventStore.js +45 -18
  68. package/server/session-core/providerAdapters.js +50 -13
  69. package/server/session-core/runtimeState.js +8 -0
  70. package/shared/conversationEvents.js +78 -14
  71. package/dist/assets/App-CTKZtqB1.js +0 -460
  72. package/dist/assets/ReviewApp-DM6BNAzR.js +0 -1
  73. package/dist/assets/channel-1oJBvF-0.js +0 -1
  74. package/dist/assets/classDiagram-VBA2DB6C-d5TeKFM4.js +0 -1
  75. package/dist/assets/classDiagram-v2-RAHNMMFH-d5TeKFM4.js +0 -1
  76. package/dist/assets/clone-CinxIlEu.js +0 -1
  77. package/dist/assets/index-YCFGDVKw.css +0 -1
  78. package/dist/assets/stateDiagram-v2-FVOUBMTO-DTUf5_gC.js +0 -1
  79. package/server/_legacy-providers/README.md +0 -30
  80. package/server/_legacy-providers/claude-sdk.js +0 -956
  81. package/server/_legacy-providers/gemini-cli.js +0 -368
  82. package/server/_legacy-providers/openai-codex.js +0 -705
  83. package/server/_legacy-providers/opencode-cli.js +0 -674
@@ -12,6 +12,7 @@ import {
12
12
  import {
13
13
  buildSessionRuntimeSnapshot,
14
14
  createSessionRuntimeSubscriptionKey,
15
+ seedSessionRuntimeSubscriptionSnapshot,
15
16
  subscribeToSessionRuntimeStateChanges
16
17
  } from '../session-core/runtimeState.js';
17
18
  import { SUPPORTED_PROVIDERS } from '../../shared/conversationEvents.js';
@@ -24,6 +25,7 @@ const INTEGRATION_PING_TIMEOUT_MS = 1500;
24
25
  const INTEGRATION_EDITOR_REQUEST_TIMEOUT_MS = 15000;
25
26
  const INTEGRATION_EDITOR_TYPE_PREFIX = 'integration.editor.';
26
27
  const INTEGRATION_EDITOR_RESULT_SUFFIX = '.result';
28
+ const VALID_EDITING_STATES = Object.freeze(['editing', 'idle', 'completed', 'error']);
27
29
  const INTEGRATION_EDITOR_CAPABILITIES = Object.freeze({
28
30
  'integration.editor.snapshot.get': 'editor.snapshot',
29
31
  'integration.editor.nodes.list': 'editor.nodes.list',
@@ -38,6 +40,35 @@ const pendingIntegrationPings = new Map();
38
40
  const sessionStateSubscriptionsByWs = new Map();
39
41
  const sessionStateSubscribersByKey = new Map();
40
42
 
43
+ // Editing state cache for resilience across connection drops
44
+ const recentEditingStates = new Map();
45
+ const EDITING_STATE_TTL_MS = 30 * 60 * 1000;
46
+ const EDITING_STATE_CLEANUP_INTERVAL_MS = 5 * 60 * 1000;
47
+
48
+ function cacheEditingState(channel, targetClientId, elementKey, state, taskRef) {
49
+ const key = `${channel}::${targetClientId}::${elementKey}`;
50
+ recentEditingStates.set(key, {
51
+ channel,
52
+ targetClientId,
53
+ elementKey,
54
+ state,
55
+ taskRef: taskRef || null,
56
+ updatedAt: Date.now(),
57
+ });
58
+ }
59
+
60
+ function cleanupExpiredEditingStates() {
61
+ const now = Date.now();
62
+ for (const [key, entry] of recentEditingStates.entries()) {
63
+ if (now - entry.updatedAt > EDITING_STATE_TTL_MS) {
64
+ recentEditingStates.delete(key);
65
+ }
66
+ }
67
+ }
68
+
69
+ const editingStateCleanupTimer = setInterval(cleanupExpiredEditingStates, EDITING_STATE_CLEANUP_INTERVAL_MS);
70
+ editingStateCleanupTimer.unref?.();
71
+
41
72
  function sendJson(ws, payload) {
42
73
  if (ws.readyState === WebSocket.OPEN) {
43
74
  ws.send(JSON.stringify(payload));
@@ -258,6 +289,7 @@ async function handleAgentStateSubscribe(ws, data) {
258
289
  }
259
290
 
260
291
  const subscriptionKey = createSessionRuntimeSubscriptionKey(normalized.provider, normalized.sessionId);
292
+ seedSessionRuntimeSubscriptionSnapshot(subscriptionKey, snapshot);
261
293
  addSessionStateSubscription(ws, subscriptionKey);
262
294
 
263
295
  sendJson(ws, {
@@ -369,6 +401,7 @@ function buildEditorClientSummary(meta) {
369
401
  return {
370
402
  channel: meta.channel,
371
403
  clientId: meta.clientId,
404
+ source: meta.source || null,
372
405
  sessionId: meta.sessionId || null,
373
406
  pageUrl: meta.pageUrl || null,
374
407
  lastSeenAt: meta.lastSeenAt || null,
@@ -565,6 +598,7 @@ function validateIntegrationConnectPayload(payload) {
565
598
  role,
566
599
  channel,
567
600
  clientId,
601
+ source: normalizeNonEmptyString(payload.source) || null,
568
602
  pageUrl: normalizeNonEmptyString(payload.pageUrl) || null,
569
603
  sessionId: normalizeNonEmptyString(payload.sessionId) || null,
570
604
  capabilities: Array.isArray(payload.capabilities)
@@ -948,8 +982,12 @@ function validateEditorEditingSetPayload(payload) {
948
982
  }
949
983
 
950
984
  const state = normalizeNonEmptyString(payload.state);
951
- if (state !== 'editing' && state !== 'idle') {
952
- return { ok: false, code: 'INVALID_PAYLOAD', message: 'state must be editing or idle' };
985
+ if (!VALID_EDITING_STATES.includes(state)) {
986
+ return {
987
+ ok: false,
988
+ code: 'INVALID_PAYLOAD',
989
+ message: `state must be one of: ${VALID_EDITING_STATES.join(', ')}`
990
+ };
953
991
  }
954
992
 
955
993
  return validateEditorTargetPayload(payload, {
@@ -1137,6 +1175,24 @@ async function forwardIntegrationResponseToOrigin(data) {
1137
1175
  outgoingData?.type === 'integration.error'
1138
1176
  || isEditorResultMessageType(outgoingData?.type)
1139
1177
  || (outgoingData?.type === 'integration.ack' && pendingRequest.awaitResult !== true);
1178
+
1179
+ // Cache successful editing state changes for resilience
1180
+ if (
1181
+ outgoingData?.type === 'integration.editor.editing.result'
1182
+ && isPlainObject(outgoingData?.payload)
1183
+ && outgoingData.payload.applied === true
1184
+ && pendingRequest.requestPayload
1185
+ ) {
1186
+ const rp = pendingRequest.requestPayload;
1187
+ cacheEditingState(
1188
+ rp.channel,
1189
+ rp.targetClientId,
1190
+ outgoingData.payload.elementKey || rp.elementKey,
1191
+ outgoingData.payload.state,
1192
+ outgoingData.payload.taskRef || rp.taskRef,
1193
+ );
1194
+ }
1195
+
1140
1196
  if (isTerminal) {
1141
1197
  clearPendingIntegrationRequest(requestId);
1142
1198
  }
@@ -1173,7 +1229,11 @@ class ExternalAgentWebSocketWriter {
1173
1229
  requestId: this.requestId,
1174
1230
  provider: payload.provider || this.provider,
1175
1231
  sessionId,
1176
- ...buildSessionNavigation(sessionId)
1232
+ ...buildSessionNavigation({
1233
+ provider: payload.provider || this.provider,
1234
+ sessionId,
1235
+ projectPath: payload.projectPath || null
1236
+ })
1177
1237
  });
1178
1238
  return;
1179
1239
  }
package/server/index.js CHANGED
@@ -96,7 +96,7 @@ async function getPty() {
96
96
  import fetch from 'node-fetch';
97
97
  import mime from 'mime-types';
98
98
 
99
- import { getProjects, getSessions, getSessionMessages, renameProject, deleteSession, deleteProject, addProjectManually, extractProjectDirectory, clearProjectDirectoryCache, clearProviderSessionLookupCaches, getGeminiSessionMessages } from './projects.js';
99
+ import { getProjects, getProjectsList, getProjectDetails, getSessions, getSessionMessages, renameProject, deleteSession, deleteProject, addProjectManually, extractProjectDirectory, clearProjectDirectoryCache, clearProviderSessionLookupCaches, getGeminiSessionMessages } from './projects.js';
100
100
  import {
101
101
  executeAgentPrompt,
102
102
  getActiveAgentSessions,
@@ -333,8 +333,8 @@ async function setupProjectsWatcher() {
333
333
  clearProjectDirectoryCache();
334
334
  clearProviderSessionLookupCaches();
335
335
 
336
- // Get updated projects list
337
- const updatedProjects = await getProjects(broadcastProgress);
336
+ // Get updated lightweight projects list
337
+ const updatedProjects = await getProjectsList(broadcastProgress);
338
338
 
339
339
  // Notify all connected clients about the project changes
340
340
  const changedProvider = filePath.startsWith(codexSessionsPath)
@@ -343,14 +343,21 @@ async function setupProjectsWatcher() {
343
343
  const changedFileRoot = changedProvider === 'codex'
344
344
  ? codexSessionsPath
345
345
  : claudeProjectsPath;
346
+ const normalizedRelativePath = path.relative(changedFileRoot, filePath);
347
+ const changedPathSegments = normalizedRelativePath.split(path.sep).filter(Boolean);
348
+ const affectedProjectName = changedProvider === 'claude'
349
+ ? (changedPathSegments[0] || null)
350
+ : null;
346
351
  const updateMessage = JSON.stringify({
347
352
  type: 'projects_updated',
348
353
  projects: updatedProjects,
349
354
  timestamp: new Date().toISOString(),
350
355
  changeType: eventType,
351
- changedFile: path.relative(changedFileRoot, filePath),
356
+ changedFile: normalizedRelativePath,
352
357
  changedProvider,
353
- changedSessionId: extractSessionIdFromChangedFile(filePath)
358
+ changedSessionId: extractSessionIdFromChangedFile(filePath),
359
+ affectedProjectName,
360
+ requiresDetailsRefresh: Boolean(affectedProjectName)
354
361
  });
355
362
 
356
363
  connectedClients.forEach(client => {
@@ -647,6 +654,7 @@ app.post('/api/system/update', authenticateToken, async (req, res) => {
647
654
 
648
655
  app.get('/api/projects', authenticateToken, async (req, res) => {
649
656
  try {
657
+ res.setHeader('Deprecation', 'true');
650
658
  const projects = await getProjects(broadcastProgress);
651
659
  res.json(projects);
652
660
  } catch (error) {
@@ -654,6 +662,27 @@ app.get('/api/projects', authenticateToken, async (req, res) => {
654
662
  }
655
663
  });
656
664
 
665
+ app.get('/api/projects/list', authenticateToken, async (req, res) => {
666
+ try {
667
+ const projects = await getProjectsList(broadcastProgress);
668
+ res.json(projects);
669
+ } catch (error) {
670
+ res.status(500).json({ error: error.message });
671
+ }
672
+ });
673
+
674
+ app.get('/api/projects/:projectName/details', authenticateToken, async (req, res) => {
675
+ try {
676
+ const project = await getProjectDetails(req.params.projectName);
677
+ res.json(project);
678
+ } catch (error) {
679
+ if (/Project not found/i.test(error.message)) {
680
+ return res.status(404).json({ error: error.message });
681
+ }
682
+ res.status(500).json({ error: error.message });
683
+ }
684
+ });
685
+
657
686
  app.get('/api/projects/:projectName/sessions', authenticateToken, async (req, res) => {
658
687
  try {
659
688
  const { limit = 5, offset = 0 } = req.query;