codeep 1.3.40 → 1.3.42

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.
@@ -402,19 +402,17 @@ export function startAcpServer() {
402
402
  transport.respond(msg.id, result);
403
403
  }
404
404
  // ── helpers ──────────────────────────────────────────────────────────────────
405
- function sendSessionTitle(sessionId, history, fallback) {
406
- const firstUserMsg = history.find(m => m.role === 'user');
407
- const title = firstUserMsg
408
- ? firstUserMsg.content.replace(/\n/g, ' ').trim().slice(0, 60)
409
- : (fallback ?? 'Codeep session');
410
- transport.notify('session/update', {
411
- sessionId,
412
- update: {
413
- sessionUpdate: 'session_info_update',
414
- title,
415
- updatedAt: new Date().toISOString(),
416
- },
417
- });
405
+ // Title hint to the client. The ACP spec does NOT define a
406
+ // `session_info_update` variant sending it caused Zed's internally-tagged
407
+ // SessionUpdate deserializer to reject the notification, which (depending
408
+ // on client recovery logic) could swallow following valid notifications
409
+ // like `available_commands_update`. We now no-op here and rely on
410
+ // session/list (which has a proper `title` field per spec) for any
411
+ // client-side session naming. Kept as a function with no body so callers
412
+ // don't need to be touched — easy to wire back up via `_meta` extension if
413
+ // a future client needs an explicit hint.
414
+ function sendSessionTitle(_sessionId, _history, _fallback) {
415
+ // intentionally empty — see comment above
418
416
  }
419
417
  // ── session/new ─────────────────────────────────────────────────────────────
420
418
  function handleSessionNew(msg) {
@@ -438,14 +436,14 @@ export function startAcpServer() {
438
436
  configOptions: buildConfigOptions(),
439
437
  };
440
438
  transport.respond(msg.id, result);
441
- // Advertise slash commands
442
- transport.notify('session/update', {
443
- sessionId: acpSessionId,
444
- update: {
445
- sessionUpdate: 'available_commands_update',
446
- availableCommands: AVAILABLE_COMMANDS,
447
- },
448
- });
439
+ // Advertise slash commands AFTER a short delay. Zed processes
440
+ // `AvailableCommandsUpdated` events synchronously and silently drops them
441
+ // if `thread_view(&session_id)` returns None — which is the case for ~tens
442
+ // of ms after session/new response is sent (Zed needs to spin up the view
443
+ // in a separate task). Without the delay the notification arrives ~1 ms
444
+ // after the response and gets lost, which manifests as
445
+ // "Available commands: none" in the slash menu.
446
+ sendCommandsDelayed(acpSessionId);
449
447
  // Send title immediately so Zed "Recent" panel shows something useful
450
448
  sendSessionTitle(acpSessionId, history, pathBasename(params.cwd));
451
449
  // Send welcome message
@@ -457,6 +455,21 @@ export function startAcpServer() {
457
455
  },
458
456
  });
459
457
  }
458
+ // Delay configurable via env so we can experimentally tune in production.
459
+ // 200 ms is comfortably above the observed ~1 ms race window without
460
+ // making the slash menu feel laggy on first paint.
461
+ const COMMANDS_DELAY_MS = Number(process.env.CODEEP_ACP_COMMANDS_DELAY_MS ?? 200);
462
+ function sendCommandsDelayed(sessionId) {
463
+ setTimeout(() => {
464
+ transport.notify('session/update', {
465
+ sessionId,
466
+ update: {
467
+ sessionUpdate: 'available_commands_update',
468
+ availableCommands: AVAILABLE_COMMANDS,
469
+ },
470
+ });
471
+ }, COMMANDS_DELAY_MS);
472
+ }
460
473
  // ── session/load ────────────────────────────────────────────────────────────
461
474
  function handleSessionLoad(msg) {
462
475
  const params = msg.params;
@@ -493,16 +506,9 @@ export function startAcpServer() {
493
506
  configOptions: buildConfigOptions(),
494
507
  };
495
508
  transport.respond(msg.id, result);
496
- // Re-advertise slash commands so `/` autocomplete works after a reload.
497
- // Zed only registers commands when AvailableCommandsUpdated fires; without
498
- // this the slash menu stays empty after session/load.
499
- transport.notify('session/update', {
500
- sessionId: acpSessionId,
501
- update: {
502
- sessionUpdate: 'available_commands_update',
503
- availableCommands: AVAILABLE_COMMANDS,
504
- },
505
- });
509
+ // Re-advertise commands (delayed for the same race-condition reason as
510
+ // session/new see sendCommandsDelayed comment).
511
+ sendCommandsDelayed(acpSessionId);
506
512
  // Send title immediately so Zed "Recent" panel shows something useful
507
513
  sendSessionTitle(params.sessionId, history, pathBasename(params.cwd));
508
514
  // Send restored session welcome
@@ -521,18 +527,6 @@ export function startAcpServer() {
521
527
  // Falls back to `session/load` semantics if the session isn't in memory yet.
522
528
  function handleSessionResume(msg) {
523
529
  const params = msg.params;
524
- // Helper — re-advertise commands so `/` autocomplete works after a panel
525
- // reload. Without this the slash menu stays empty until a new session is
526
- // created. Same notification shape as session/new.
527
- const advertiseCommands = (sessionId) => {
528
- transport.notify('session/update', {
529
- sessionId,
530
- update: {
531
- sessionUpdate: 'available_commands_update',
532
- availableCommands: AVAILABLE_COMMANDS,
533
- },
534
- });
535
- };
536
530
  const existing = sessions.get(params.sessionId);
537
531
  if (existing) {
538
532
  existing.workspaceRoot = params.cwd;
@@ -542,7 +536,8 @@ export function startAcpServer() {
542
536
  configOptions: buildConfigOptions(),
543
537
  };
544
538
  transport.respond(msg.id, result);
545
- advertiseCommands(params.sessionId);
539
+ // Delayed — see sendCommandsDelayed comment for the race-condition rationale.
540
+ sendCommandsDelayed(params.sessionId);
546
541
  return;
547
542
  }
548
543
  // Session not in memory — load from disk but skip the welcome banner and
@@ -566,7 +561,7 @@ export function startAcpServer() {
566
561
  configOptions: buildConfigOptions(),
567
562
  };
568
563
  transport.respond(msg.id, result);
569
- advertiseCommands(acpSessionId);
564
+ sendCommandsDelayed(acpSessionId);
570
565
  }
571
566
  // ── session/set_mode ────────────────────────────────────────────────────────
572
567
  function handleSetMode(msg) {
@@ -1,5 +1,29 @@
1
1
  // acp/transport.ts
2
2
  // Newline-delimited JSON-RPC over stdio
3
+ import { appendFileSync, mkdirSync } from 'node:fs';
4
+ import { homedir } from 'node:os';
5
+ import { join, dirname } from 'node:path';
6
+ // Debug log destination — when CODEEP_ACP_DEBUG is set we mirror every
7
+ // inbound and outbound JSON-RPC frame here. Using a file (not stderr) because
8
+ // most ACP clients (Zed included) do not pipe agent stderr to anywhere the
9
+ // user can easily read; a known on-disk path is reliable everywhere.
10
+ const ACP_DEBUG_PATH = process.env.CODEEP_ACP_DEBUG_FILE
11
+ || join(homedir(), '.cache', 'codeep', 'acp-debug.log');
12
+ const ACP_DEBUG = !!process.env.CODEEP_ACP_DEBUG;
13
+ if (ACP_DEBUG) {
14
+ try {
15
+ mkdirSync(dirname(ACP_DEBUG_PATH), { recursive: true });
16
+ }
17
+ catch { /* ignore */ }
18
+ }
19
+ function debugLog(direction, payload) {
20
+ if (!ACP_DEBUG)
21
+ return;
22
+ try {
23
+ appendFileSync(ACP_DEBUG_PATH, `${new Date().toISOString()} [ACP${direction}client] ${payload}\n`);
24
+ }
25
+ catch { /* swallow — never break the protocol over a logging failure */ }
26
+ }
3
27
  const MAX_BUFFER_SIZE = 10 * 1024 * 1024; // 10MB
4
28
  const REQUEST_TIMEOUT_MS = 30_000; // 30s
5
29
  export class StdioTransport {
@@ -26,9 +50,7 @@ export class StdioTransport {
26
50
  if (!trimmed)
27
51
  continue;
28
52
  try {
29
- if (process.env.CODEEP_ACP_DEBUG) {
30
- process.stderr.write(`[ACP←client] ${trimmed}\n`);
31
- }
53
+ debugLog('←', trimmed);
32
54
  const msg = JSON.parse(trimmed);
33
55
  // Check if this is a response to one of our outbound requests
34
56
  if ('result' in msg || 'error' in msg) {
@@ -49,9 +71,7 @@ export class StdioTransport {
49
71
  }
50
72
  send(msg) {
51
73
  const line = JSON.stringify(msg);
52
- if (process.env.CODEEP_ACP_DEBUG) {
53
- process.stderr.write(`[ACP→client] ${line}\n`);
54
- }
74
+ debugLog('→', line);
55
75
  process.stdout.write(line + '\n');
56
76
  }
57
77
  respond(id, result) {
@@ -141,7 +141,7 @@ function createConfig() {
141
141
  const defaults = {
142
142
  apiKey: '',
143
143
  provider: 'z.ai',
144
- model: 'glm-4.7',
144
+ model: 'glm-5.1',
145
145
  agentMode: 'on',
146
146
  ollamaUrl: 'http://localhost:11434',
147
147
  agentConfirmation: 'dangerous',
@@ -7,8 +7,6 @@ const MODEL_CONTEXT_WINDOWS = {
7
7
  'glm-5.1': 131_072,
8
8
  'glm-5': 80_000,
9
9
  'glm-5-turbo': 202_752,
10
- 'glm-4.5-air': 131_072,
11
- 'glm-4.7-flash': 202_752,
12
10
  // OpenAI
13
11
  'gpt-5.5': 1_200_000,
14
12
  'gpt-5.4': 1_050_000,
@@ -58,8 +56,6 @@ const MODEL_PRICING = {
58
56
  'glm-5.1': { inputPer1M: 1.00, outputPer1M: 3.20 },
59
57
  'glm-5': { inputPer1M: 0.72, outputPer1M: 2.30 },
60
58
  'glm-5-turbo': { inputPer1M: 1.20, outputPer1M: 4.00 },
61
- 'glm-4.5-air': { inputPer1M: 0.20, outputPer1M: 1.10 },
62
- 'glm-4.7-flash': { inputPer1M: 0.06, outputPer1M: 0.40 },
63
59
  // OpenAI
64
60
  'gpt-5.5': { inputPer1M: 5.00, outputPer1M: 30.00 },
65
61
  'gpt-5.4': { inputPer1M: 2.50, outputPer1M: 15.00 },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeep",
3
- "version": "1.3.40",
3
+ "version": "1.3.42",
4
4
  "description": "AI-powered coding assistant built for the terminal. Multiple LLM providers, project-aware context, and a seamless development workflow.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",