clideck 1.29.0 → 1.29.1
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.
- package/handlers.js +37 -7
- package/package.json +1 -1
- package/plugin-loader.js +3 -2
- package/sessions.js +29 -12
- package/transcript-builder.js +1 -1
package/handlers.js
CHANGED
|
@@ -101,6 +101,33 @@ checkAvailability();
|
|
|
101
101
|
let cfg = config.load();
|
|
102
102
|
if (detectTelemetryConfig(cfg)) config.save(cfg);
|
|
103
103
|
|
|
104
|
+
function extractQuotedPath(command, needle) {
|
|
105
|
+
if (!command || !needle) return '';
|
|
106
|
+
const parts = String(command).match(/"([^"]+)"/g) || [];
|
|
107
|
+
for (const part of parts) {
|
|
108
|
+
const value = part.slice(1, -1);
|
|
109
|
+
if (value.includes(needle)) return value;
|
|
110
|
+
}
|
|
111
|
+
return '';
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function hasExistingHook(arr, hookFile, route) {
|
|
115
|
+
return !!arr?.some(h => h.hooks?.some(x => {
|
|
116
|
+
if (!x.command?.includes(hookFile) || !x.command?.includes(` ${route}`)) return false;
|
|
117
|
+
const hookPath = extractQuotedPath(x.command, hookFile);
|
|
118
|
+
return !!hookPath && existsSync(hookPath);
|
|
119
|
+
}));
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function codexConfigLooksHealthy(content, port) {
|
|
123
|
+
if (!content.includes('[otel]') || !content.includes(`localhost:${port}`)) return false;
|
|
124
|
+
const notifyLine = content.match(/^\s*notify\s*=\s*\[(.+)\]\s*$/m)?.[1] || '';
|
|
125
|
+
if (!notifyLine.includes('notify-helper')) return false;
|
|
126
|
+
const quoted = [...notifyLine.matchAll(/"([^"]+)"/g)].map(m => m[1]);
|
|
127
|
+
const helperPath = quoted.find(v => v.includes('notify-helper'));
|
|
128
|
+
return !!helperPath && existsSync(helperPath);
|
|
129
|
+
}
|
|
130
|
+
|
|
104
131
|
function detectTelemetryConfig(c) {
|
|
105
132
|
const home = os.homedir();
|
|
106
133
|
const port = '4000';
|
|
@@ -116,24 +143,27 @@ function detectTelemetryConfig(c) {
|
|
|
116
143
|
try {
|
|
117
144
|
const s = JSON.parse(readFileSync(join(home, '.claude', 'settings.json'), 'utf8'));
|
|
118
145
|
const hooks = s.hooks || {};
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
&&
|
|
122
|
-
&& hooks.
|
|
146
|
+
detected = hasExistingHook(hooks.UserPromptSubmit, 'claude-hook.js', 'start')
|
|
147
|
+
&& hasExistingHook(hooks.Stop, 'claude-hook.js', 'stop')
|
|
148
|
+
&& hasExistingHook(hooks.StopFailure, 'claude-hook.js', 'stop')
|
|
149
|
+
&& hasExistingHook(hooks.PreToolUse, 'claude-hook.js', 'menu')
|
|
150
|
+
&& hooks.Notification?.some(h => h.matcher === 'idle_prompt' && hasExistingHook([h], 'claude-hook.js', 'idle'));
|
|
123
151
|
if (!detected) reason = 'Needs re-patch';
|
|
124
152
|
} catch {}
|
|
125
153
|
} else if (preset.presetId === 'codex') {
|
|
126
154
|
try {
|
|
127
155
|
const content = readFileSync(join(home, '.codex', 'config.toml'), 'utf8');
|
|
128
|
-
detected =
|
|
156
|
+
detected = codexConfigLooksHealthy(content, port);
|
|
129
157
|
if (!detected) reason = 'Needs re-patch';
|
|
130
158
|
} catch {}
|
|
131
159
|
} else if (preset.presetId === 'gemini-cli') {
|
|
132
160
|
try {
|
|
133
161
|
const s = JSON.parse(readFileSync(join(home, '.gemini', 'settings.json'), 'utf8'));
|
|
134
162
|
const hooks = s.hooks || {};
|
|
135
|
-
|
|
136
|
-
|
|
163
|
+
detected = hasExistingHook(hooks.BeforeAgent, 'gemini-hook.js', 'start')
|
|
164
|
+
&& hasExistingHook(hooks.AfterAgent, 'gemini-hook.js', 'stop')
|
|
165
|
+
&& hasExistingHook(hooks.SessionEnd, 'gemini-hook.js', 'stop')
|
|
166
|
+
&& hasExistingHook(hooks.BeforeTool, 'gemini-hook.js', 'menu');
|
|
137
167
|
if (!detected) reason = 'Needs re-patch';
|
|
138
168
|
} catch {}
|
|
139
169
|
} else if (preset.presetId === 'opencode') {
|
package/package.json
CHANGED
package/plugin-loader.js
CHANGED
|
@@ -206,13 +206,14 @@ function buildApi(pluginId, pluginDir, state) {
|
|
|
206
206
|
getSession(id) {
|
|
207
207
|
const s = sessionsFn?.()?.get(id);
|
|
208
208
|
if (!s) return null;
|
|
209
|
-
|
|
209
|
+
const state = sessionStatus.get(id) || '';
|
|
210
|
+
return { id, name: s.name, cwd: s.cwd, commandId: s.commandId, presetId: s.presetId || 'shell', themeId: s.themeId, projectId: s.projectId, roleName: s.roleName || null, working: state.startsWith('1:') };
|
|
210
211
|
},
|
|
211
212
|
getSessions() {
|
|
212
213
|
const sessions = sessionsFn?.();
|
|
213
214
|
if (!sessions) return [];
|
|
214
215
|
return [...sessions].map(([id, s]) => ({
|
|
215
|
-
id, name: s.name, cwd: s.cwd, commandId: s.commandId, presetId: s.presetId || 'shell', themeId: s.themeId, projectId: s.projectId, roleName: s.roleName || null, working:
|
|
216
|
+
id, name: s.name, cwd: s.cwd, commandId: s.commandId, presetId: s.presetId || 'shell', themeId: s.themeId, projectId: s.projectId, roleName: s.roleName || null, working: (sessionStatus.get(id) || '').startsWith('1:'),
|
|
216
217
|
}));
|
|
217
218
|
},
|
|
218
219
|
|
package/sessions.js
CHANGED
|
@@ -101,19 +101,28 @@ function spawnSession(id, cmd, parts, cwd, name, themeId, commandId, savedToken,
|
|
|
101
101
|
if (preset?.telemetryEnv) telemetry.watchSession(id, bin);
|
|
102
102
|
if (preset?.bridge === 'opencode') opencodeBridge.watchSession(id, cwd);
|
|
103
103
|
|
|
104
|
+
function injectRolePrompt() {
|
|
105
|
+
if (!session.pendingRolePrompt) return;
|
|
106
|
+
transcript.recordInjectedInput(id, session.pendingRolePrompt);
|
|
107
|
+
term.write(session.pendingRolePrompt);
|
|
108
|
+
setTimeout(() => term.write('\r'), 150);
|
|
109
|
+
console.log(`Session ${id.slice(0, 8)}: injected role prompt`);
|
|
110
|
+
delete session.pendingRolePrompt;
|
|
111
|
+
delete session._rolePromptTimer;
|
|
112
|
+
}
|
|
113
|
+
|
|
104
114
|
term.onData((data) => {
|
|
105
|
-
//
|
|
115
|
+
// Role prompts should be injected only when the agent is likely ready for
|
|
116
|
+
// input. For Codex, use the first OTLP startup event instead of a blind
|
|
117
|
+
// fixed startup delay; other agents keep the existing delayed path.
|
|
106
118
|
if (session.pendingRolePrompt && !session._rolePromptTimer) {
|
|
107
|
-
session.
|
|
108
|
-
if (
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
delete session._rolePromptTimer;
|
|
115
|
-
}
|
|
116
|
-
}, 3000);
|
|
119
|
+
if (session.presetId === 'codex') {
|
|
120
|
+
if (telemetry.hasEvents(id)) injectRolePrompt();
|
|
121
|
+
} else {
|
|
122
|
+
session._rolePromptTimer = setTimeout(() => {
|
|
123
|
+
if (session.pendingRolePrompt) injectRolePrompt();
|
|
124
|
+
}, 3000);
|
|
125
|
+
}
|
|
117
126
|
}
|
|
118
127
|
session.chunks.push(data);
|
|
119
128
|
session.chunksSize += data.length;
|
|
@@ -363,7 +372,7 @@ function restart(msg, ws, cfg) {
|
|
|
363
372
|
}
|
|
364
373
|
|
|
365
374
|
const savedToken = s.sessionToken;
|
|
366
|
-
const { name, cwd, commandId, projectId } = s;
|
|
375
|
+
const { name, cwd, commandId, projectId, roleName, muted, lastPreview, lastActivityAt } = s;
|
|
367
376
|
|
|
368
377
|
activity.clear(id);
|
|
369
378
|
telemetry.clear(id);
|
|
@@ -380,6 +389,14 @@ function restart(msg, ws, cfg) {
|
|
|
380
389
|
return;
|
|
381
390
|
}
|
|
382
391
|
|
|
392
|
+
const next = sessions.get(id);
|
|
393
|
+
if (next) {
|
|
394
|
+
next.roleName = roleName || null;
|
|
395
|
+
next.muted = !!muted;
|
|
396
|
+
next.lastPreview = lastPreview || '';
|
|
397
|
+
next.lastActivityAt = lastActivityAt || null;
|
|
398
|
+
}
|
|
399
|
+
|
|
383
400
|
broadcast({ type: 'session.restarted', id, resumed: !!canResume });
|
|
384
401
|
}
|
|
385
402
|
|
package/transcript-builder.js
CHANGED
|
@@ -14,7 +14,7 @@ function cleanAgentText(presetId, text) {
|
|
|
14
14
|
out = out.replace(/\n\s*.*\(running stop hook\)[\s\S]*$/, '').trim();
|
|
15
15
|
out = out.replace(/\n\s*\?\s*for shortcuts[\s\S]*$/, '').trim();
|
|
16
16
|
out = out.replace(/\n\s*esc to interrupt[\s\S]*$/, '').trim();
|
|
17
|
-
out = out.replace(/\n\s*[✻✢✣✤✥✦✧]\s
|
|
17
|
+
out = out.replace(/\n\n\s*[✻✢✣✤✥✦✧][\s\S]*$/, '').trim();
|
|
18
18
|
}
|
|
19
19
|
return out;
|
|
20
20
|
}
|