@adhdev/daemon-core 0.5.25 → 0.5.27

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 (109) hide show
  1. package/dist/index.js +33 -28
  2. package/dist/index.js.map +1 -1
  3. package/package.json +1 -1
  4. package/providers/_builtin/COMPATIBILITY.md +1 -1
  5. package/providers/_builtin/README.md +1 -1
  6. package/providers/_builtin/cli/claude-cli/provider.json +2 -1
  7. package/providers/_builtin/docs/PROVIDER_GUIDE.md +3 -3
  8. package/providers/_builtin/extension/cline/provider.json +4 -2
  9. package/providers/_builtin/extension/codex/provider.json +4 -2
  10. package/providers/_builtin/extension/codex/scripts/{list_models.js → 1.0/list_models.js} +1 -0
  11. package/providers/_builtin/extension/codex/scripts/{read_chat.js → 1.0/read_chat.js} +36 -11
  12. package/providers/_builtin/extension/codex/scripts/{send_message.js → 1.0/send_message.js} +1 -1
  13. package/providers/_builtin/extension/codex/scripts/list_modes.js +138 -0
  14. package/providers/_builtin/extension/codex/scripts/set_mode.js +165 -0
  15. package/providers/_builtin/extension/roo-code/provider.json +4 -2
  16. package/providers/_builtin/ide/antigravity/scripts/1.106/read_chat.js +2 -1
  17. package/providers/_builtin/ide/antigravity/scripts/1.107/read_chat.js +2 -1
  18. package/providers/_builtin/ide/cursor/provider.json +1 -70
  19. package/providers/_builtin/ide/cursor/provider.json.bak +70 -0
  20. package/providers/_builtin/ide/cursor/scripts/0.49/list_sessions.js +1 -1
  21. package/providers/_builtin/ide/cursor/scripts/0.49/read_chat.js +1 -1
  22. package/providers/_builtin/ide/kiro/provider.json +4 -2
  23. package/providers/_builtin/ide/pearai/provider.json +4 -2
  24. package/providers/_builtin/ide/trae/provider.json +4 -2
  25. package/providers/_builtin/ide/windsurf/provider.json +4 -2
  26. package/providers/_builtin/ide/windsurf/scripts/{read_chat.js → 1.0/read_chat.js} +2 -1
  27. package/providers/_builtin/registry.json +1 -12
  28. package/src/cli-adapters/provider-cli-adapter.ts +42 -35
  29. package/providers/_builtin/extension/cline/scripts.js +0 -73
  30. package/providers/_builtin/extension/codex/scripts.js +0 -94
  31. package/providers/_builtin/ide/kiro/scripts.js +0 -62
  32. package/providers/_builtin/ide/pearai/scripts.js +0 -74
  33. package/providers/_builtin/ide/trae/scripts.js +0 -57
  34. package/providers/_builtin/ide/windsurf/scripts.js +0 -57
  35. /package/providers/_builtin/extension/cline/scripts/{focus_editor.js → 1.0/focus_editor.js} +0 -0
  36. /package/providers/_builtin/extension/cline/scripts/{list_chats.js → 1.0/list_chats.js} +0 -0
  37. /package/providers/_builtin/extension/cline/scripts/{list_models.js → 1.0/list_models.js} +0 -0
  38. /package/providers/_builtin/extension/cline/scripts/{list_modes.js → 1.0/list_modes.js} +0 -0
  39. /package/providers/_builtin/extension/cline/scripts/{new_session.js → 1.0/new_session.js} +0 -0
  40. /package/providers/_builtin/extension/cline/scripts/{open_panel.js → 1.0/open_panel.js} +0 -0
  41. /package/providers/_builtin/extension/cline/scripts/{read_chat.js → 1.0/read_chat.js} +0 -0
  42. /package/providers/_builtin/extension/cline/scripts/{resolve_action.js → 1.0/resolve_action.js} +0 -0
  43. /package/providers/_builtin/extension/cline/scripts/{send_message.js → 1.0/send_message.js} +0 -0
  44. /package/providers/_builtin/extension/cline/scripts/{set_mode.js → 1.0/set_mode.js} +0 -0
  45. /package/providers/_builtin/extension/cline/scripts/{set_model.js → 1.0/set_model.js} +0 -0
  46. /package/providers/_builtin/extension/cline/scripts/{switch_session.js → 1.0/switch_session.js} +0 -0
  47. /package/providers/_builtin/extension/codex/scripts/{click_conversation_webview.js → 1.0/click_conversation_webview.js} +0 -0
  48. /package/providers/_builtin/extension/codex/scripts/{explore_chat_webview.js → 1.0/explore_chat_webview.js} +0 -0
  49. /package/providers/_builtin/extension/codex/scripts/{explore_controls_webview.js → 1.0/explore_controls_webview.js} +0 -0
  50. /package/providers/_builtin/extension/codex/scripts/{explore_dom.js → 1.0/explore_dom.js} +0 -0
  51. /package/providers/_builtin/extension/codex/scripts/{explore_dropdown_webview.js → 1.0/explore_dropdown_webview.js} +0 -0
  52. /package/providers/_builtin/extension/codex/scripts/{inspect_code_webview.js → 1.0/inspect_code_webview.js} +0 -0
  53. /package/providers/_builtin/extension/codex/scripts/{message_structure_webview.js → 1.0/message_structure_webview.js} +0 -0
  54. /package/providers/_builtin/extension/codex/scripts/{new_session.js → 1.0/new_session.js} +0 -0
  55. /package/providers/_builtin/extension/codex/scripts/{resolve_action.js → 1.0/resolve_action.js} +0 -0
  56. /package/providers/_builtin/extension/codex/scripts/{set_model.js → 1.0/set_model.js} +0 -0
  57. /package/providers/_builtin/extension/roo-code/{scripts.js → scripts/1.0/scripts.js} +0 -0
  58. /package/providers/_builtin/ide/kiro/scripts/{focus_editor.js → 1.0/focus_editor.js} +0 -0
  59. /package/providers/_builtin/ide/kiro/scripts/{open_panel.js → 1.0/open_panel.js} +0 -0
  60. /package/providers/_builtin/ide/kiro/scripts/{resolve_action.js → 1.0/resolve_action.js} +0 -0
  61. /package/providers/_builtin/ide/kiro/scripts/{send_message.js → 1.0/send_message.js} +0 -0
  62. /package/providers/_builtin/ide/kiro/scripts/{webview_list_models.js → 1.0/webview_list_models.js} +0 -0
  63. /package/providers/_builtin/ide/kiro/scripts/{webview_list_modes.js → 1.0/webview_list_modes.js} +0 -0
  64. /package/providers/_builtin/ide/kiro/scripts/{webview_list_sessions.js → 1.0/webview_list_sessions.js} +0 -0
  65. /package/providers/_builtin/ide/kiro/scripts/{webview_new_session.js → 1.0/webview_new_session.js} +0 -0
  66. /package/providers/_builtin/ide/kiro/scripts/{webview_read_chat.js → 1.0/webview_read_chat.js} +0 -0
  67. /package/providers/_builtin/ide/kiro/scripts/{webview_send_message.js → 1.0/webview_send_message.js} +0 -0
  68. /package/providers/_builtin/ide/kiro/scripts/{webview_set_mode.js → 1.0/webview_set_mode.js} +0 -0
  69. /package/providers/_builtin/ide/kiro/scripts/{webview_set_model.js → 1.0/webview_set_model.js} +0 -0
  70. /package/providers/_builtin/ide/kiro/scripts/{webview_switch_session.js → 1.0/webview_switch_session.js} +0 -0
  71. /package/providers/_builtin/ide/pearai/scripts/{focus_editor.js → 1.0/focus_editor.js} +0 -0
  72. /package/providers/_builtin/ide/pearai/scripts/{list_sessions.js → 1.0/list_sessions.js} +0 -0
  73. /package/providers/_builtin/ide/pearai/scripts/{new_session.js → 1.0/new_session.js} +0 -0
  74. /package/providers/_builtin/ide/pearai/scripts/{open_panel.js → 1.0/open_panel.js} +0 -0
  75. /package/providers/_builtin/ide/pearai/scripts/{resolve_action.js → 1.0/resolve_action.js} +0 -0
  76. /package/providers/_builtin/ide/pearai/scripts/{send_message.js → 1.0/send_message.js} +0 -0
  77. /package/providers/_builtin/ide/pearai/scripts/{webview_list_models.js → 1.0/webview_list_models.js} +0 -0
  78. /package/providers/_builtin/ide/pearai/scripts/{webview_list_modes.js → 1.0/webview_list_modes.js} +0 -0
  79. /package/providers/_builtin/ide/pearai/scripts/{webview_list_sessions.js → 1.0/webview_list_sessions.js} +0 -0
  80. /package/providers/_builtin/ide/pearai/scripts/{webview_new_session.js → 1.0/webview_new_session.js} +0 -0
  81. /package/providers/_builtin/ide/pearai/scripts/{webview_read_chat.js → 1.0/webview_read_chat.js} +0 -0
  82. /package/providers/_builtin/ide/pearai/scripts/{webview_resolve_action.js → 1.0/webview_resolve_action.js} +0 -0
  83. /package/providers/_builtin/ide/pearai/scripts/{webview_send_message.js → 1.0/webview_send_message.js} +0 -0
  84. /package/providers/_builtin/ide/pearai/scripts/{webview_set_mode.js → 1.0/webview_set_mode.js} +0 -0
  85. /package/providers/_builtin/ide/pearai/scripts/{webview_set_model.js → 1.0/webview_set_model.js} +0 -0
  86. /package/providers/_builtin/ide/pearai/scripts/{webview_switch_session.js → 1.0/webview_switch_session.js} +0 -0
  87. /package/providers/_builtin/ide/trae/scripts/{focus_editor.js → 1.0/focus_editor.js} +0 -0
  88. /package/providers/_builtin/ide/trae/scripts/{list_chats.js → 1.0/list_chats.js} +0 -0
  89. /package/providers/_builtin/ide/trae/scripts/{list_models.js → 1.0/list_models.js} +0 -0
  90. /package/providers/_builtin/ide/trae/scripts/{list_modes.js → 1.0/list_modes.js} +0 -0
  91. /package/providers/_builtin/ide/trae/scripts/{new_session.js → 1.0/new_session.js} +0 -0
  92. /package/providers/_builtin/ide/trae/scripts/{open_panel.js → 1.0/open_panel.js} +0 -0
  93. /package/providers/_builtin/ide/trae/scripts/{read_chat.js → 1.0/read_chat.js} +0 -0
  94. /package/providers/_builtin/ide/trae/scripts/{resolve_action.js → 1.0/resolve_action.js} +0 -0
  95. /package/providers/_builtin/ide/trae/scripts/{send_message.js → 1.0/send_message.js} +0 -0
  96. /package/providers/_builtin/ide/trae/scripts/{set_mode.js → 1.0/set_mode.js} +0 -0
  97. /package/providers/_builtin/ide/trae/scripts/{set_model.js → 1.0/set_model.js} +0 -0
  98. /package/providers/_builtin/ide/trae/scripts/{switch_session.js → 1.0/switch_session.js} +0 -0
  99. /package/providers/_builtin/ide/windsurf/scripts/{focus_editor.js → 1.0/focus_editor.js} +0 -0
  100. /package/providers/_builtin/ide/windsurf/scripts/{list_chats.js → 1.0/list_chats.js} +0 -0
  101. /package/providers/_builtin/ide/windsurf/scripts/{list_models.js → 1.0/list_models.js} +0 -0
  102. /package/providers/_builtin/ide/windsurf/scripts/{list_modes.js → 1.0/list_modes.js} +0 -0
  103. /package/providers/_builtin/ide/windsurf/scripts/{new_session.js → 1.0/new_session.js} +0 -0
  104. /package/providers/_builtin/ide/windsurf/scripts/{open_panel.js → 1.0/open_panel.js} +0 -0
  105. /package/providers/_builtin/ide/windsurf/scripts/{resolve_action.js → 1.0/resolve_action.js} +0 -0
  106. /package/providers/_builtin/ide/windsurf/scripts/{send_message.js → 1.0/send_message.js} +0 -0
  107. /package/providers/_builtin/ide/windsurf/scripts/{set_mode.js → 1.0/set_mode.js} +0 -0
  108. /package/providers/_builtin/ide/windsurf/scripts/{set_model.js → 1.0/set_model.js} +0 -0
  109. /package/providers/_builtin/ide/windsurf/scripts/{switch_session.js → 1.0/switch_session.js} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhdev/daemon-core",
3
- "version": "0.5.25",
3
+ "version": "0.5.27",
4
4
  "description": "ADHDev daemon core — CDP, IDE detection, providers, command execution",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,6 +1,6 @@
1
1
  # ADHDev Provider Compatibility Matrix
2
2
 
3
- > **Last updated:** 2026-03-18
3
+ > **Last updated:** 2026-03-22
4
4
  > **How to contribute:** Submit a PR updating the status for your OS/version. See [Status Legend](#status-legend) below.
5
5
 
6
6
  ## Status Legend
@@ -8,7 +8,7 @@
8
8
  ├── ide/ — IDE providers (Cursor, Antigravity, Windsurf, Kiro, etc.)
9
9
  ├── cli/ — CLI agent providers (Gemini CLI, Claude Code, Codex CLI)
10
10
  ├── extension/ — VS Code extension providers (Cline, Roo Code)
11
- ├── acp/ — ACP agent providers (40+ agents)
11
+ ├── acp/ — ACP agent providers (35 agents)
12
12
  ├── registry.json — Auto-generated provider index (used by daemon)
13
13
  ├── validate.js — Provider schema validator
14
14
  ├── CONTRIBUTING.md — How to add a new provider
@@ -90,7 +90,8 @@
90
90
  { "source": "Allow\\s*tool", "flags": "i" },
91
91
  { "source": "Yes,?\\s*don'?t\\s*ask", "flags": "i" },
92
92
  { "source": "Deny", "flags": "i" },
93
- { "source": "Do you want to proceed", "flags": "i" }
93
+ { "source": "Do you want to proceed", "flags": "i" },
94
+ { "source": "Esc to cancel", "flags": "i" }
94
95
  ],
95
96
  "ready": [
96
97
  { "source": "for\\s*shortcuts", "flags": "i" },
@@ -28,7 +28,7 @@ ProviderLoader.loadAll() ← 3-tier priority loading
28
28
 
29
29
  | Priority | Directory | Auto-update | Purpose |
30
30
  |----------|-----------|-------------|---------|
31
- | 1 (lowest) | `packages/launcher/providers/_builtin/` | npm update only | Offline fallback |
31
+ | 1 (lowest) | `packages/daemon-core/providers/_builtin/` | npm update only | Offline fallback |
32
32
  | 2 | `~/.adhdev/providers/.upstream/` | ✅ On daemon start | Latest GitHub providers |
33
33
  | 3 (highest) | `~/.adhdev/providers/` (excl. _upstream) | ❌ **Never** | User custom |
34
34
 
@@ -219,7 +219,7 @@ scripts: {
219
219
  ## 3️⃣ Script Output Contract
220
220
 
221
221
  All scripts **must return a JSON string**.
222
- See [contracts.ts](file:///Users/vilmire/Work/remote_vs/packages/launcher/src/providers/contracts.ts) for reference.
222
+ See [contracts.ts](file:///Users/vilmire/Work/remote_vs/packages/daemon-core/src/providers/contracts.ts) for reference.
223
223
 
224
224
  ### Core Scripts
225
225
 
@@ -464,7 +464,7 @@ adhdev daemon --dev
464
464
 
465
465
  ## 5️⃣ Using _helpers (Optional)
466
466
 
467
- [_helpers/index.js](file:///Users/vilmire/Work/remote_vs/packages/launcher/providers/_helpers/index.js) provides common utilities you can use.
467
+ [_helpers/index.js](file:///Users/vilmire/Work/remote_vs/packages/daemon-core/providers/_helpers/index.js) provides common utilities you can use.
468
468
 
469
469
  | Helper | Purpose |
470
470
  |--------|---------|
@@ -31,5 +31,7 @@
31
31
  "min": 30,
32
32
  "max": 600
33
33
  }
34
- }
35
- }
34
+ },
35
+ "defaultScriptDir": "scripts/1.0",
36
+ "compatibility": []
37
+ }
@@ -32,5 +32,7 @@
32
32
  "min": 30,
33
33
  "max": 600
34
34
  }
35
- }
36
- }
35
+ },
36
+ "defaultScriptDir": "scripts/1.0",
37
+ "compatibility": []
38
+ }
@@ -51,6 +51,7 @@
51
51
 
52
52
  resolve(JSON.stringify({
53
53
  currentModel,
54
+ current: currentModel,
54
55
  models,
55
56
  count: models.length,
56
57
  }));
@@ -22,12 +22,34 @@
22
22
  */
23
23
  (() => {
24
24
  try {
25
- const root = document.getElementById('root');
25
+ // When executed via evaluateInSession, we're in the outer vscode-webview
26
+ // iframe. The Codex React app lives in a child iframe. Try to access it.
27
+ let doc = document;
28
+ let root = doc.getElementById('root');
29
+
30
+ if (!root) {
31
+ // Traverse into inner iframe(s)
32
+ const iframes = doc.querySelectorAll('iframe');
33
+ for (const iframe of iframes) {
34
+ try {
35
+ const innerDoc = iframe.contentDocument || iframe.contentWindow?.document;
36
+ if (innerDoc) {
37
+ const innerRoot = innerDoc.getElementById('root');
38
+ if (innerRoot) {
39
+ doc = innerDoc;
40
+ root = innerRoot;
41
+ break;
42
+ }
43
+ }
44
+ } catch (e) { /* cross-origin, skip */ }
45
+ }
46
+ }
47
+
26
48
  if (!root) return JSON.stringify({ error: 'no root element' });
27
49
 
28
50
  const isVisible = root.offsetHeight > 0;
29
51
 
30
- const headerEl = document.querySelector('[style*="view-transition-name: header-title"]');
52
+ const headerEl = doc.querySelector('[style*="view-transition-name: header-title"]');
31
53
  const headerText = (headerEl?.textContent || '').trim();
32
54
  const isTaskList = headerText === '작업' || headerText === 'Tasks';
33
55
 
@@ -216,7 +238,7 @@
216
238
 
217
239
  // ─── 1. Messages ───
218
240
  const messages = [];
219
- const turnEls = document.querySelectorAll('[data-content-search-turn-key]');
241
+ const turnEls = doc.querySelectorAll('[data-content-search-turn-key]');
220
242
 
221
243
  for (const turnEl of turnEls) {
222
244
  const turnKey = turnEl.getAttribute('data-content-search-turn-key');
@@ -243,7 +265,7 @@
243
265
 
244
266
  // Fallback
245
267
  if (messages.length === 0 && !isTaskList) {
246
- const threadArea = document.querySelector('[data-thread-find-target="conversation"]');
268
+ const threadArea = doc.querySelector('[data-thread-find-target="conversation"]');
247
269
  if (threadArea) {
248
270
  const text = extractRichContent(threadArea);
249
271
  if (text.length > 0) {
@@ -258,7 +280,7 @@
258
280
 
259
281
  // ─── 2. Input field ───
260
282
  let inputContent = '';
261
- const proseMirror = document.querySelector('.ProseMirror');
283
+ const proseMirror = doc.querySelector('.ProseMirror');
262
284
  if (proseMirror) {
263
285
  const placeholder = proseMirror.querySelector('.placeholder');
264
286
  const text = (proseMirror.textContent || '').trim();
@@ -269,7 +291,7 @@
269
291
 
270
292
  // ─── 3. Status ───
271
293
  let status = 'idle';
272
- const buttons = Array.from(document.querySelectorAll('button'))
294
+ const buttons = Array.from(doc.querySelectorAll('button'))
273
295
  .filter(b => b.offsetWidth > 0);
274
296
  const buttonTexts = buttons.map(b => (b.textContent || '').trim().toLowerCase());
275
297
  const buttonLabels = buttons.map(b => (b.getAttribute('aria-label') || '').toLowerCase());
@@ -279,9 +301,12 @@
279
301
  status = 'generating';
280
302
  }
281
303
 
282
- const approvalPatterns = /^(approve|accept|allow|confirm|run|proceed|yes|승인|허용|실행)/i;
283
- if (buttonTexts.some(b => approvalPatterns.test(b)) ||
284
- buttonLabels.some(l => approvalPatterns.test(l))) {
304
+ // Codex approval buttons appear as distinct action buttons (e.g. "Approve", "Always approve", "Deny")
305
+ // They typically appear at the bottom of a tool-call/action block
306
+ const approvalSpecificPatterns = /^(approve|always approve|deny|reject|승인|항상 승인|거부)/i;
307
+ const hasApprovalButton = buttonTexts.some(b => approvalSpecificPatterns.test(b)) ||
308
+ buttonLabels.some(l => approvalSpecificPatterns.test(l));
309
+ if (hasApprovalButton) {
285
310
  status = 'waiting_approval';
286
311
  }
287
312
 
@@ -293,7 +318,7 @@
293
318
  // ─── 4. Model / Mode ───
294
319
  let model = '';
295
320
  let mode = '';
296
- const footerButtons = document.querySelectorAll(
321
+ const footerButtons = doc.querySelectorAll(
297
322
  '[class*="thread-composer-max-width"] button, [class*="pb-2"] button'
298
323
  );
299
324
  for (const btn of footerButtons) {
@@ -318,7 +343,7 @@
318
343
  }
319
344
 
320
345
  // ─── 6. Task info ───
321
- const taskBtn = document.querySelector('[aria-label*="작업"], [aria-label*="task" i]');
346
+ const taskBtn = doc.querySelector('[aria-label*="작업"], [aria-label*="task" i]');
322
347
  const taskInfo = taskBtn ? (taskBtn.textContent || '').trim() : '';
323
348
 
324
349
  return JSON.stringify({
@@ -55,7 +55,7 @@
55
55
  editor.dispatchEvent(enterEvent);
56
56
  }, 100);
57
57
 
58
- return JSON.stringify({ success: true, message: message.substring(0, 100) });
58
+ return JSON.stringify({ sent: true, success: true, message: message.substring(0, 100) });
59
59
  } catch (e) {
60
60
  return JSON.stringify({ error: e.message || String(e) });
61
61
  }
@@ -0,0 +1,138 @@
1
+ /**
2
+ * Codex Extension — list_modes
3
+ *
4
+ * Finds the mode / autonomy dropdown next to the model chip in the composer footer,
5
+ * opens it (Radix), reads options, closes. UI expects `modes` + `current` (see ModelModeBar).
6
+ */
7
+ (() => {
8
+ try {
9
+ function resolveDoc() {
10
+ let doc = document;
11
+ let root = doc.getElementById('root');
12
+ if (!root) {
13
+ const iframes = doc.querySelectorAll('iframe');
14
+ for (const iframe of iframes) {
15
+ try {
16
+ const innerDoc = iframe.contentDocument || iframe.contentWindow?.document;
17
+ if (innerDoc?.getElementById('root')) {
18
+ doc = innerDoc;
19
+ root = innerDoc.getElementById('root');
20
+ break;
21
+ }
22
+ } catch (e) { /* cross-origin */ }
23
+ }
24
+ }
25
+ return { doc, root };
26
+ }
27
+
28
+ function isModelMenuButton(b) {
29
+ const text = (b.textContent || '').trim();
30
+ if (b.getAttribute('aria-haspopup') !== 'menu') return false;
31
+ return /^(GPT-|gpt-|o\d|claude-|sonnet|opus)/i.test(text);
32
+ }
33
+
34
+ /** Mode chip: menu trigger in composer that is not the model selector. */
35
+ function findModeMenuButton(doc) {
36
+ const composer =
37
+ doc.querySelector('[class*="thread-composer-max-width"]') ||
38
+ doc.querySelector('[class*="thread-composer"]') ||
39
+ doc.getElementById('root') ||
40
+ doc.body;
41
+
42
+ const buttons = Array.from(composer.querySelectorAll('button')).filter(
43
+ (b) => b.offsetWidth > 0 && b.offsetHeight > 0,
44
+ );
45
+
46
+ const menuTriggers = buttons.filter(
47
+ (b) => b.getAttribute('aria-haspopup') === 'menu' && !isModelMenuButton(b),
48
+ );
49
+
50
+ if (menuTriggers.length === 0) return null;
51
+
52
+ const byAria = menuTriggers.find((b) => {
53
+ const al = (b.getAttribute('aria-label') || '').toLowerCase();
54
+ return /mode|agent|ask|plan|autonomy|codex|모드|에이전트|플랜/i.test(al);
55
+ });
56
+ if (byAria) return byAria;
57
+
58
+ return menuTriggers[0];
59
+ }
60
+
61
+ function openMenu(btn) {
62
+ const rect = btn.getBoundingClientRect();
63
+ const cx = rect.left + rect.width / 2;
64
+ const cy = rect.top + rect.height / 2;
65
+ btn.dispatchEvent(
66
+ new PointerEvent('pointerdown', { bubbles: true, clientX: cx, clientY: cy, pointerId: 1 }),
67
+ );
68
+ btn.dispatchEvent(new MouseEvent('mousedown', { bubbles: true, clientX: cx, clientY: cy }));
69
+ btn.dispatchEvent(
70
+ new PointerEvent('pointerup', { bubbles: true, clientX: cx, clientY: cy, pointerId: 1 }),
71
+ );
72
+ btn.dispatchEvent(new MouseEvent('mouseup', { bubbles: true, clientX: cx, clientY: cy }));
73
+ btn.dispatchEvent(new MouseEvent('click', { bubbles: true, clientX: cx, clientY: cy }));
74
+ }
75
+
76
+ const { doc, root } = resolveDoc();
77
+ if (!root) return JSON.stringify({ modes: [], current: '', currentMode: '', error: 'no root' });
78
+
79
+ const modeBtn = findModeMenuButton(doc);
80
+ if (!modeBtn) {
81
+ return JSON.stringify({
82
+ modes: [],
83
+ current: '',
84
+ currentMode: '',
85
+ error: 'mode menu button not found',
86
+ });
87
+ }
88
+
89
+ const currentLabel = (modeBtn.textContent || '').trim();
90
+ openMenu(modeBtn);
91
+
92
+ return new Promise((resolve) => {
93
+ setTimeout(() => {
94
+ let menu = doc.querySelector('[role="menu"][data-state="open"]');
95
+ if (!menu) {
96
+ menu = doc.querySelector('[role="menu"]');
97
+ }
98
+
99
+ const collected = [];
100
+ if (menu) {
101
+ const items = menu.querySelectorAll(
102
+ '[role="menuitem"], [role="menuitemradio"], [role="option"], div[class*="cursor-interaction"]',
103
+ );
104
+ for (const item of items) {
105
+ const text = (item.textContent || '').trim();
106
+ if (
107
+ text &&
108
+ text.length > 0 &&
109
+ text.length < 80 &&
110
+ !/^모델|^model\b|^select\b/i.test(text)
111
+ ) {
112
+ collected.push(text);
113
+ }
114
+ }
115
+ }
116
+
117
+ doc.dispatchEvent(
118
+ new KeyboardEvent('keydown', {
119
+ key: 'Escape',
120
+ code: 'Escape',
121
+ keyCode: 27,
122
+ bubbles: true,
123
+ }),
124
+ );
125
+
126
+ const modes = [...new Set(collected)];
127
+ const out = {
128
+ modes: modes.length > 0 ? modes : currentLabel ? [currentLabel] : [],
129
+ current: currentLabel,
130
+ currentMode: currentLabel,
131
+ };
132
+ resolve(JSON.stringify(out));
133
+ }, 550);
134
+ });
135
+ } catch (e) {
136
+ return JSON.stringify({ error: e.message || String(e), modes: [], current: '', currentMode: '' });
137
+ }
138
+ })();
@@ -0,0 +1,165 @@
1
+ /**
2
+ * Codex Extension — set_mode
3
+ *
4
+ * Opens the mode dropdown (same discovery as list_modes), selects an item matching ${MODE}.
5
+ *
6
+ * Placeholder: ${MODE}
7
+ */
8
+ (() => {
9
+ try {
10
+ const targetMode = ${MODE};
11
+
12
+ function resolveDoc() {
13
+ let doc = document;
14
+ let root = doc.getElementById('root');
15
+ if (!root) {
16
+ const iframes = doc.querySelectorAll('iframe');
17
+ for (const iframe of iframes) {
18
+ try {
19
+ const innerDoc = iframe.contentDocument || iframe.contentWindow?.document;
20
+ if (innerDoc?.getElementById('root')) {
21
+ doc = innerDoc;
22
+ root = innerDoc.getElementById('root');
23
+ break;
24
+ }
25
+ } catch (e) { /* cross-origin */ }
26
+ }
27
+ }
28
+ return { doc, root };
29
+ }
30
+
31
+ function isModelMenuButton(b) {
32
+ const text = (b.textContent || '').trim();
33
+ if (b.getAttribute('aria-haspopup') !== 'menu') return false;
34
+ return /^(GPT-|gpt-|o\d|claude-|sonnet|opus)/i.test(text);
35
+ }
36
+
37
+ function findModeMenuButton(doc) {
38
+ const composer =
39
+ doc.querySelector('[class*="thread-composer-max-width"]') ||
40
+ doc.querySelector('[class*="thread-composer"]') ||
41
+ doc.getElementById('root') ||
42
+ doc.body;
43
+
44
+ const buttons = Array.from(composer.querySelectorAll('button')).filter(
45
+ (b) => b.offsetWidth > 0 && b.offsetHeight > 0,
46
+ );
47
+
48
+ const menuTriggers = buttons.filter(
49
+ (b) => b.getAttribute('aria-haspopup') === 'menu' && !isModelMenuButton(b),
50
+ );
51
+
52
+ if (menuTriggers.length === 0) return null;
53
+
54
+ const byAria = menuTriggers.find((b) => {
55
+ const al = (b.getAttribute('aria-label') || '').toLowerCase();
56
+ return /mode|agent|ask|plan|autonomy|codex|모드|에이전트|플랜/i.test(al);
57
+ });
58
+ if (byAria) return byAria;
59
+
60
+ return menuTriggers[0];
61
+ }
62
+
63
+ function openMenu(btn) {
64
+ const rect = btn.getBoundingClientRect();
65
+ const cx = rect.left + rect.width / 2;
66
+ const cy = rect.top + rect.height / 2;
67
+ btn.dispatchEvent(
68
+ new PointerEvent('pointerdown', { bubbles: true, clientX: cx, clientY: cy, pointerId: 1 }),
69
+ );
70
+ btn.dispatchEvent(new MouseEvent('mousedown', { bubbles: true, clientX: cx, clientY: cy }));
71
+ btn.dispatchEvent(
72
+ new PointerEvent('pointerup', { bubbles: true, clientX: cx, clientY: cy, pointerId: 1 }),
73
+ );
74
+ btn.dispatchEvent(new MouseEvent('mouseup', { bubbles: true, clientX: cx, clientY: cy }));
75
+ btn.dispatchEvent(new MouseEvent('click', { bubbles: true, clientX: cx, clientY: cy }));
76
+ }
77
+
78
+ function clickItem(el) {
79
+ const ir = el.getBoundingClientRect();
80
+ const ix = ir.left + ir.width / 2;
81
+ const iy = ir.top + ir.height / 2;
82
+ el.dispatchEvent(
83
+ new PointerEvent('pointerdown', { bubbles: true, clientX: ix, clientY: iy }),
84
+ );
85
+ el.dispatchEvent(new MouseEvent('mousedown', { bubbles: true, clientX: ix, clientY: iy }));
86
+ el.dispatchEvent(new PointerEvent('pointerup', { bubbles: true, clientX: ix, clientY: iy }));
87
+ el.dispatchEvent(new MouseEvent('mouseup', { bubbles: true, clientX: ix, clientY: iy }));
88
+ el.dispatchEvent(new MouseEvent('click', { bubbles: true, clientX: ix, clientY: iy }));
89
+ }
90
+
91
+ const { doc, root } = resolveDoc();
92
+ if (!root) return JSON.stringify({ success: false, error: 'no root' });
93
+
94
+ const want =
95
+ typeof targetMode === 'string'
96
+ ? targetMode.trim()
97
+ : targetMode != null
98
+ ? String(targetMode).trim()
99
+ : '';
100
+ if (!want) return JSON.stringify({ success: false, error: 'empty mode' });
101
+
102
+ const modeBtn = findModeMenuButton(doc);
103
+ if (!modeBtn) return JSON.stringify({ success: false, error: 'mode menu button not found' });
104
+
105
+ const currentLabel = (modeBtn.textContent || '').trim();
106
+ if (currentLabel.toLowerCase() === want.toLowerCase()) {
107
+ return JSON.stringify({ success: true, mode: currentLabel, changed: false });
108
+ }
109
+
110
+ openMenu(modeBtn);
111
+
112
+ return new Promise((resolve) => {
113
+ setTimeout(() => {
114
+ let menu = doc.querySelector('[role="menu"][data-state="open"]');
115
+ if (!menu) menu = doc.querySelector('[role="menu"]');
116
+
117
+ if (!menu) {
118
+ doc.dispatchEvent(
119
+ new KeyboardEvent('keydown', { key: 'Escape', code: 'Escape', keyCode: 27, bubbles: true }),
120
+ );
121
+ return resolve(JSON.stringify({ success: false, error: 'mode menu did not open' }));
122
+ }
123
+
124
+ const items = Array.from(
125
+ menu.querySelectorAll(
126
+ '[role="menuitem"], [role="menuitemradio"], [role="option"], div[class*="cursor-interaction"]',
127
+ ),
128
+ );
129
+
130
+ const norm = (s) => (s || '').trim().toLowerCase();
131
+ const wantN = norm(want);
132
+
133
+ let match = items.find((el) => norm(el.textContent) === wantN);
134
+ if (!match) {
135
+ match = items.find((el) => norm(el.textContent).includes(wantN) || wantN.includes(norm(el.textContent)));
136
+ }
137
+
138
+ if (!match) {
139
+ doc.dispatchEvent(
140
+ new KeyboardEvent('keydown', { key: 'Escape', code: 'Escape', keyCode: 27, bubbles: true }),
141
+ );
142
+ const available = items
143
+ .map((el) => (el.textContent || '').trim())
144
+ .filter((t) => t.length > 0 && t.length < 80);
145
+ return resolve(
146
+ JSON.stringify({
147
+ success: false,
148
+ error: `mode "${want}" not found`,
149
+ available,
150
+ }),
151
+ );
152
+ }
153
+
154
+ const picked = (match.textContent || '').trim();
155
+ clickItem(match);
156
+
157
+ setTimeout(() => {
158
+ resolve(JSON.stringify({ success: true, mode: picked, changed: true }));
159
+ }, 350);
160
+ }, 550);
161
+ });
162
+ } catch (e) {
163
+ return JSON.stringify({ success: false, error: e.message || String(e) });
164
+ }
165
+ })();
@@ -31,5 +31,7 @@
31
31
  "min": 30,
32
32
  "max": 600
33
33
  }
34
- }
35
- }
34
+ },
35
+ "defaultScriptDir": "scripts/1.0",
36
+ "compatibility": []
37
+ }
@@ -30,7 +30,8 @@
30
30
  if (animMarkdown && animMarkdown.offsetWidth > 0) status = 'generating';
31
31
  }
32
32
 
33
- const title = document.title.split(' \u2014 ')[0].trim() || 'Active Session';
33
+ const titleParts = document.title.split(' \u2014 ');
34
+ const title = (titleParts.length >= 2 ? titleParts[titleParts.length - 1] : titleParts[0] || '').trim() || 'Active Session';
34
35
 
35
36
  // ─── HTML → Markdown 변환기 (대시보드가 ReactMarkdown+remarkGfm 사용) ───
36
37
  // extractCodeText: layout-independent code text extraction
@@ -30,7 +30,8 @@
30
30
  if (animMarkdown && animMarkdown.offsetWidth > 0) status = 'generating';
31
31
  }
32
32
 
33
- const title = document.title.split(' \u2014 ')[0].trim() || 'Active Session';
33
+ const titleParts = document.title.split(' \u2014 ');
34
+ const title = (titleParts.length >= 2 ? titleParts[titleParts.length - 1] : titleParts[0] || '').trim() || 'Active Session';
34
35
 
35
36
  // ─── HTML → Markdown 변환기 (대시보드가 ReactMarkdown+remarkGfm 사용) ───
36
37
  // extractCodeText: layout-independent code text extraction
@@ -1,70 +1 @@
1
- {
2
- "type": "cursor",
3
- "name": "Cursor",
4
- "category": "ide",
5
- "displayName": "Cursor",
6
- "icon": "⚡",
7
- "cli": "cursor",
8
- "cdpPorts": [
9
- 9333,
10
- 9334
11
- ],
12
- "targetFilter": {
13
- "urlIncludes": "workbench.html",
14
- "urlExcludes": ["agent"],
15
- "titleExcludes": "extension-output|ADHDev CDP|Debug Console|Output\\s*$|Launchpad"
16
- },
17
- "processNames": {
18
- "darwin": "Cursor",
19
- "win32": [
20
- "Cursor.exe"
21
- ]
22
- },
23
- "paths": {
24
- "darwin": [
25
- "/Applications/Cursor.app"
26
- ],
27
- "win32": [
28
- "C:\\Users\\*\\AppData\\Local\\Programs\\cursor\\Cursor.exe"
29
- ],
30
- "linux": [
31
- "/opt/Cursor",
32
- "/usr/share/cursor"
33
- ]
34
- },
35
- "inputMethod": "cdp-type-and-send",
36
- "inputSelector": ".aislash-editor-input[contenteditable=\"true\"]",
37
- "versionCommand": "cursor --version",
38
- "providerVersion": "1.0.0",
39
- "compatibility": [
40
- { "ideVersion": ">=0.49.0", "scriptDir": "scripts/0.49" }
41
- ],
42
- "defaultScriptDir": "scripts/0.49",
43
- "vscodeCommands": {
44
- "changeModel": "cursor.model"
45
- },
46
- "settings": {
47
- "approvalAlert": {
48
- "type": "boolean",
49
- "default": true,
50
- "public": true,
51
- "label": "Approval Notifications",
52
- "description": "Show notification when approval is needed"
53
- },
54
- "longGeneratingAlert": {
55
- "type": "boolean",
56
- "default": true,
57
- "public": true,
58
- "label": "Long Generation Alert",
59
- "description": "Alert when generation takes too long"
60
- },
61
- "longGeneratingThresholdSec": {
62
- "type": "number",
63
- "default": 180,
64
- "public": true,
65
- "label": "Long Generation Threshold (sec)",
66
- "min": 30,
67
- "max": 600
68
- }
69
- }
70
- }
1
+ JSON.stringify((() => { const frames = document.querySelectorAll('iframe.webview'); const results = []; frames.forEach((f, i) => { try { results.push({ index: i, src: f.src?.substring(0, 200), id: f.id?.substring(0, 100), class: f.className?.substring(0, 100) }); } catch(e) { results.push({ index: i, error: e.message }); } }); return { total: frames.length, frames: results }; })())