shennian 0.2.33 → 0.2.34

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.
File without changes
@@ -51,6 +51,7 @@ function readJsonlLines(filePath, startOffset, onLine) {
51
51
  let position = startOffset;
52
52
  let nextOffset = startOffset;
53
53
  let carry = Buffer.alloc(0);
54
+ let skippingOversizedLine = false;
54
55
  while (position < fileSize) {
55
56
  const bytesRead = fs.readSync(fd, buffer, 0, Math.min(chunkSize, fileSize - position), position);
56
57
  if (bytesRead <= 0)
@@ -70,15 +71,27 @@ function readJsonlLines(filePath, startOffset, onLine) {
70
71
  const lineOffset = nextOffset;
71
72
  nextOffset += newlineIndex - lineStart + 1;
72
73
  lineStart = newlineIndex + 1;
73
- if (lineBuffer.length > 0 && lineBuffer.length <= MAX_JSONL_LINE_BYTES) {
74
+ if (!skippingOversizedLine && lineBuffer.length > 0 && lineBuffer.length <= MAX_JSONL_LINE_BYTES) {
74
75
  onLine(lineBuffer.toString('utf8'), lineOffset);
75
76
  }
77
+ skippingOversizedLine = false;
76
78
  }
77
79
  if (lineStart < chunk.length) {
78
- carry = Buffer.from(chunk.subarray(lineStart));
80
+ const remaining = chunk.subarray(lineStart);
81
+ if (skippingOversizedLine || remaining.length > MAX_JSONL_LINE_BYTES) {
82
+ skippingOversizedLine = true;
83
+ nextOffset += remaining.length;
84
+ carry = Buffer.alloc(0);
85
+ }
86
+ else {
87
+ carry = Buffer.from(remaining);
88
+ }
79
89
  }
80
90
  }
81
- return nextOffset;
91
+ if (!skippingOversizedLine && carry.length > 0 && carry.length <= MAX_JSONL_LINE_BYTES) {
92
+ onLine(carry.toString('utf8'), nextOffset);
93
+ }
94
+ return fileSize;
82
95
  }
83
96
  finally {
84
97
  fs.closeSync(fd);
@@ -657,20 +670,18 @@ function lookupCodexThreadName(sourceSessionKey) {
657
670
  const indexPath = path.join(os.homedir(), '.codex', 'session_index.jsonl');
658
671
  if (!fs.existsSync(indexPath))
659
672
  return null;
660
- const content = fs.readFileSync(indexPath, 'utf8');
661
- const lines = content.split('\n');
662
- for (let index = lines.length - 1; index >= 0; index -= 1) {
663
- const line = lines[index];
673
+ let latestTitle = null;
674
+ readJsonlLines(indexPath, 0, (line) => {
664
675
  if (!line.trim())
665
- continue;
676
+ return;
666
677
  const parsed = safeParse(line);
667
678
  if (!parsed)
668
- continue;
679
+ return;
669
680
  const title = readCodexIndexTitle(parsed, sourceSessionKey);
670
681
  if (title)
671
- return title;
672
- }
673
- return null;
682
+ latestTitle = title;
683
+ });
684
+ return latestTitle;
674
685
  }
675
686
  export function listCodexRolloutFiles() {
676
687
  const roots = [
@@ -122,6 +122,7 @@ function bindAdapterEvents(runtime, sessionId, agentType, adapter) {
122
122
  sendAgentEvent(event, extra);
123
123
  });
124
124
  adapter.on('error', (error) => {
125
+ console.error(`[chat.send] adapter error sessionId=${sessionId} agentType=${agentType}: ${error.message}`);
125
126
  runtime.sessions.delete(sessionId);
126
127
  runtime.client.sendEvent({
127
128
  type: 'event',
@@ -230,15 +231,17 @@ export async function handleChatSend(runtime, req) {
230
231
  session = await createActiveSession(runtime, sessionId, requestedAgentType, resolvedWorkDir, incomingAgentSid);
231
232
  }
232
233
  catch (err) {
234
+ const message = err instanceof Error && err.message.startsWith('Unsupported agent:')
235
+ ? err.message
236
+ : `Failed to start ${agentType}: ${err instanceof Error ? err.message : String(err)}`;
237
+ console.error(`[chat.send] start failed reqId=${req.id} sessionId=${sessionId} agentType=${agentType} workDir=${resolvedWorkDir} agentSessionId=${incomingAgentSid ?? ''}: ${message}`);
233
238
  runtime.client.sendEvent({
234
239
  type: 'event',
235
240
  event: 'agent',
236
241
  payload: {
237
242
  state: 'error',
238
243
  sessionId,
239
- message: err instanceof Error && err.message.startsWith('Unsupported agent:')
240
- ? err.message
241
- : `Failed to start ${agentType}: ${err instanceof Error ? err.message : String(err)}`,
244
+ message,
242
245
  runId: '',
243
246
  seq: 0,
244
247
  },
@@ -248,9 +251,7 @@ export async function handleChatSend(runtime, req) {
248
251
  type: 'res',
249
252
  id: req.id,
250
253
  ok: false,
251
- error: err instanceof Error && err.message.startsWith('Unsupported agent:')
252
- ? err.message
253
- : `Failed to start ${agentType}: ${err instanceof Error ? err.message : String(err)}`,
254
+ error: message,
254
255
  });
255
256
  return;
256
257
  }
@@ -287,6 +288,8 @@ export async function handleChatSend(runtime, req) {
287
288
  });
288
289
  }
289
290
  catch (err) {
291
+ const message = `Agent send failed: ${err instanceof Error ? err.message : String(err)}`;
292
+ console.error(`[chat.send] send failed reqId=${req.id} sessionId=${sessionId} agentType=${agentType} workDir=${resolvedWorkDir} agentSessionId=${session.agentSessionId ?? incomingAgentSid ?? ''}: ${message}`);
290
293
  runtime.sessions.delete(sessionId);
291
294
  try {
292
295
  await disposeSession(session);
@@ -299,7 +302,7 @@ export async function handleChatSend(runtime, req) {
299
302
  payload: {
300
303
  state: 'error',
301
304
  sessionId,
302
- message: `Agent send failed: ${err instanceof Error ? err.message : String(err)}`,
305
+ message,
303
306
  runId: '',
304
307
  seq: 0,
305
308
  },
@@ -308,7 +311,7 @@ export async function handleChatSend(runtime, req) {
308
311
  type: 'res',
309
312
  id: req.id,
310
313
  ok: false,
311
- error: `Agent send failed: ${err instanceof Error ? err.message : String(err)}`,
314
+ error: message,
312
315
  });
313
316
  }
314
317
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shennian",
3
- "version": "0.2.33",
3
+ "version": "0.2.34",
4
4
  "description": "Shennian — AI Agent Control Plane CLI",
5
5
  "type": "module",
6
6
  "bin": {
@@ -13,7 +13,8 @@
13
13
  "README.md"
14
14
  ],
15
15
  "publishConfig": {
16
- "access": "public"
16
+ "access": "public",
17
+ "tag": "next"
17
18
  },
18
19
  "keywords": [
19
20
  "shennian",
@@ -32,16 +33,10 @@
32
33
  "engines": {
33
34
  "node": ">=18"
34
35
  },
35
- "scripts": {
36
- "build": "tsc",
37
- "build:publish": "node -e \"const fs=require('node:fs'); fs.rmSync('dist', { recursive: true, force: true }); fs.rmSync('.tsbuildinfo.publish', { force: true })\" && tsc -p tsconfig.publish.json",
38
- "dev": "tsc --watch",
39
- "prepublishOnly": "pnpm build:publish"
40
- },
41
36
  "dependencies": {
42
37
  "@mariozechner/pi-agent-core": "^0.64.0",
43
38
  "@sinclair/typebox": "^0.34.49",
44
- "@shennian/wire": "^0.1.2",
39
+ "@shennian/wire": "^0.1.3",
45
40
  "chalk": "^5.4.1",
46
41
  "commander": "^13.1.0",
47
42
  "qrcode-terminal": "^0.12.0",
@@ -53,5 +48,10 @@
53
48
  "@types/ws": "^8.18.1",
54
49
  "tsx": "^4.19.4",
55
50
  "typescript": "^5.9.3"
51
+ },
52
+ "scripts": {
53
+ "build": "tsc",
54
+ "build:publish": "node -e \"const fs=require('node:fs'); fs.rmSync('dist', { recursive: true, force: true }); fs.rmSync('.tsbuildinfo.publish', { force: true })\" && tsc -p tsconfig.publish.json",
55
+ "dev": "tsc --watch"
56
56
  }
57
- }
57
+ }