@adhdev/daemon-core 0.5.37 → 0.5.38

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.
@@ -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
+ })();
@@ -62,6 +62,7 @@ export class ProviderStreamAdapter implements IAgentStreamAdapter {
62
62
  messages: data.messages || [],
63
63
  inputContent: data.inputContent || '',
64
64
  model: data.model,
65
+ mode: data.mode,
65
66
  activeModal: data.activeModal,
66
67
  };
67
68
  if (state.messages.length > 0) {
@@ -30,6 +30,7 @@ export interface AgentStreamState {
30
30
  messages: AgentChatMessage[];
31
31
  inputContent: string;
32
32
  model?: string;
33
+ mode?: string;
33
34
  activeModal?: { message: string; buttons: string[] };
34
35
  }
35
36
 
@@ -23,6 +23,8 @@ export class ExtensionProviderInstance implements ProviderInstance {
23
23
  private agentStreams: any[] = [];
24
24
  private messages: any[] = [];
25
25
  private activeModal: any = null;
26
+ private currentModel: string = '';
27
+ private currentMode: string = '';
26
28
  private lastAgentStatus: string = 'idle';
27
29
  private generatingStartedAt: number = 0;
28
30
  private monitor: StatusMonitor;
@@ -74,6 +76,8 @@ export class ExtensionProviderInstance implements ProviderInstance {
74
76
  activeModal: this.activeModal,
75
77
  inputContent: '',
76
78
  } : null,
79
+ currentModel: this.currentModel || undefined,
80
+ currentPlan: this.currentMode || undefined,
77
81
  agentStreams: this.agentStreams,
78
82
  instanceId: this.instanceId,
79
83
  lastUpdated: Date.now(),
@@ -88,6 +92,8 @@ export class ExtensionProviderInstance implements ProviderInstance {
88
92
  if (data?.streams) this.agentStreams = data.streams;
89
93
  if (data?.messages) this.messages = data.messages;
90
94
  if (data?.activeModal !== undefined) this.activeModal = data.activeModal;
95
+ if (data?.model) this.currentModel = data.model;
96
+ if (data?.mode) this.currentMode = data.mode;
91
97
  if (data?.status) {
92
98
  const newStatus = data.status;
93
99
  this.detectTransition(newStatus, data);