sintbot 1.4.9 → 1.4.10

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/CHANGELOG.en.json CHANGED
@@ -1,4 +1,15 @@
1
1
  [
2
+ {
3
+ "version": "1.4.10",
4
+ "date": "2026-11-10",
5
+ "name": "Interrupted task completion",
6
+ "items": [
7
+ {
8
+ "t": "Fix: a group could stop accepting work after an executor exited mid-task",
9
+ "d": "When an accepted executor exits without a final result, the existing card shows an interruption notice. The group continues after delivery is confirmed. Partial output is not treated as an answer and the task is not automatically rerun. Check any operations already performed; uncertain closure or delivery remains held."
10
+ }
11
+ ]
12
+ },
2
13
  {
3
14
  "version": "1.4.9",
4
15
  "date": "2026-11-10",
@@ -193,318 +204,5 @@
193
204
  "d": "Restart first; for a group that is still paused, stop the service and run sintbot incident seal --group <group ID>. The old records are kept unchanged, the group reopens with new records, and messages left unfinished before the seal are not processed again."
194
205
  }
195
206
  ]
196
- },
197
- {
198
- "version": "1.4.0",
199
- "date": "2026-11-08",
200
- "name": "Multiple groups, Claude Code and chat commands",
201
- "items": [
202
- {
203
- "t": "One app serves several groups",
204
- "d": "One Feishu app can bind 1–32 groups, each to a local project with its own records; a concurrency limit caps simultaneous tasks."
205
- },
206
- {
207
- "t": "Codex or Claude Code per group",
208
- "d": "Each group chooses its runner and model. Send /model to list or switch; a switch happens only while that group is idle and starts a new conversation."
209
- },
210
- {
211
- "t": "Chat commands",
212
- "d": "Adds /help, /status, /new, /hud and /issue for status, quota and usage, a new conversation and feedback. An unsupported command gets a one-line notice and never stops the service."
213
- },
214
- {
215
- "t": "Reply cards update while working",
216
- "d": "The card appears once the model starts answering and refreshes with progress."
217
- },
218
- {
219
- "t": "Local console",
220
- "d": "Start with --ui to see every group, stop tasks, bind new groups, switch the model or project of an idle group, and handle feedback."
221
- },
222
- {
223
- "t": "A failure stays in its group",
224
- "d": "When a turn returns a model error or no result, only that group is asked to resend, with no automatic retry; other groups keep working. Groups added to the configuration are registered at restart."
225
- }
226
- ]
227
- },
228
- {
229
- "version": "1.3.0",
230
- "date": "2026-11-08",
231
- "name": "Built-in core",
232
- "items": [
233
- {
234
- "t": "Adds a built-in core",
235
- "d": "This release supports Codex messages in one Feishu group on macOS. Whiteboards, multiple groups and other platforms will follow. Keep existing multi-group installations and configure this release separately using the installation guide."
236
- }
237
- ]
238
- },
239
- {
240
- "version": "1.2.1",
241
- "date": "2026-11-05",
242
- "name": "Follow-up notice fix",
243
- "items": [
244
- {
245
- "t": "No false queue notice right after a task starts",
246
- "d": "A follow-up sent in the first few seconds joins the running task once the channel is ready, without first saying it will wait until the task ends."
247
- }
248
- ]
249
- },
250
- {
251
- "version": "1.2.0",
252
- "date": "2026-11-05",
253
- "name": "Steadier follow-ups, clearer errors",
254
- "items": [
255
- {
256
- "t": "The reply card follows the latest follow-up",
257
- "d": "Once a follow-up is accepted, the card moves under that message, so the answer ends up at the bottom of the group. A short notice is sent only when the card cannot move."
258
- },
259
- {
260
- "t": "Recalls and redos no longer lose messages",
261
- "d": "A recalled follow-up that had not been delivered no longer runs on its own. A redo in a new session or on another model keeps delivered follow-ups, except recalled ones."
262
- },
263
- {
264
- "t": "Codex requests no longer stall a task",
265
- "d": "Approval and question requests are declined according to the protocol, and the task continues."
266
- },
267
- {
268
- "t": "Console messages can join the running task",
269
- "d": "A console message with Reply checked is treated like a group member's. The group line is posted first, the dialog says where the message will go, and the result reports where it landed."
270
- },
271
- {
272
- "t": "Feishu answer cards show the model and quota",
273
- "d": "The small print on the card now includes the current model and account quota."
274
- },
275
- {
276
- "t": "Plain explanations for network and billing errors",
277
- "d": "Network failures, low balance and expired subscriptions are explained in the group. Repeated network failures alert the operator, and account problems can fail over."
278
- },
279
- {
280
- "t": "Lost sessions are redone automatically",
281
- "d": "Claude and Codex groups clear a session that no longer exists, redo the message in a new one, and say so in the group."
282
- }
283
- ]
284
- },
285
- {
286
- "version": "1.1.0",
287
- "date": "2026-11-05",
288
- "name": "Codex busy follow-up",
289
- "items": [
290
- {
291
- "t": "Codex can receive follow-ups during a task",
292
- "d": "Busy follow-up is on by default for Codex groups. Ordinary human follow-up messages enter the active task through the App Server; related requests can adjust the work, independent requests are answered separately in order, and unconfirmed deliveries return to the queue. It can be disabled per group; Claude groups and scheduled, quiet, and polled messages keep their existing behavior."
293
- },
294
- {
295
- "t": "Busy follow-up is limited to the effective Codex backend",
296
- "d": "The console shows the control for the backend currently in use, and the server validates it too. Changes apply from the next turn."
297
- }
298
- ]
299
- },
300
- {
301
- "version": "1.0.17",
302
- "date": "2026-11-05",
303
- "name": "More reliable installs and runs",
304
- "items": [
305
- {
306
- "t": "Installs are verified by running the program",
307
- "d": "After installing a model CLI, setup runs it once to confirm its version. A file on disk or a clean installer exit no longer counts as success, and a failed check explains what went wrong and what to do next."
308
- },
309
- {
310
- "t": "Health checks ignore files that cannot run",
311
- "d": "Files without execute permission are no longer reported as installed programs. Automatic installs also keep the platform components the CLI needs to run."
312
- },
313
- {
314
- "t": "Finds a model CLI that has moved",
315
- "d": "If the configured path stops working, SintBot looks for the same program in common install locations and keeps going. If it is nowhere to be found, the group gets a plain explanation and the operator gets an alert."
316
- },
317
- {
318
- "t": "Clearer handling of lost logins and crashes",
319
- "d": "A revoked login token now counts as an account problem, so the group can fail over and alert. A Codex run that exits with only an error gets the same treatment."
320
- },
321
- {
322
- "t": "Fixed occasional garbled Chinese",
323
- "d": "Characters split across output chunks no longer turn into garbage."
324
- }
325
- ]
326
- },
327
- {
328
- "version": "1.0.16",
329
- "date": "2026-10-30",
330
- "name": "Safer AI-assisted setup, quieter design tools",
331
- "items": [
332
- {
333
- "t": "Safer AI-assisted installation",
334
- "d": "API keys are masked as they are entered in the local terminal, keeping them out of AI conversation logs. Without an interactive terminal, the installer stops if Node is missing or too old; otherwise it skips model setup and the background service and explains what remains."
335
- },
336
- {
337
- "t": "Clearer install and first-use flow",
338
- "d": "Add bilingual guides for AI-assisted installation and first use. The one-line preview lists planned operations and confirmations, and warns that a model trial may use quota or incur a charge."
339
- },
340
- {
341
- "t": "Design and icon libraries on demand",
342
- "d": "Both libraries are collapsed by default; style presets are recommended only for a new product with no visual direction yet."
343
- }
344
- ]
345
- },
346
- {
347
- "version": "1.0.15",
348
- "date": "2026-10-30",
349
- "name": "Clearer console settings",
350
- "items": [
351
- {
352
- "t": "Software updates and history together",
353
- "d": "Update controls and version history now share one card at the bottom of Settings. A small dot appears by the version number when a newer stable release is available."
354
- },
355
- {
356
- "t": "A wider Bot & network card",
357
- "d": "The card spans the full settings grid, with the bot name and proxy arranged side by side. Background proxy details can be expanded when needed."
358
- }
359
- ]
360
- },
361
- {
362
- "version": "1.0.14",
363
- "date": "2026-10-30",
364
- "name": "Steadier service installs and better console controls",
365
- "items": [
366
- {
367
- "t": "More reliable service reinstalls",
368
- "d": "A reinstall now waits for the old background service to fully unload before starting the new one, reducing cases where the service is left unloaded."
369
- },
370
- {
371
- "t": "Software updates from the console",
372
- "d": "Stable releases are checked at startup and daily, with a manual check available too. An administrator confirms an upgrade, which waits for every group task and queue to clear before installing the exact version."
373
- },
374
- {
375
- "t": "Manage console access in Settings",
376
- "d": "Set a password for LAN access and toggle LAN binding or public Feishu sign-in. Turning off public sign-in revokes existing Feishu sessions; a failed binding change restores the previous settings."
377
- }
378
- ]
379
- },
380
- {
381
- "version": "1.0.13",
382
- "name": "An even shorter install: almost nothing to answer",
383
- "items": [
384
- {
385
- "t": "No questions for what can be done automatically",
386
- "d": "The one-line install upgrades to the latest version directly. The wizard installs Claude Code when it is missing, picks the default model itself and runs a trial turn, and no longer asks about adding more models; Codex and the design icon libraries are optional and only get a one-line install hint. If you are already logged in to Claude or Codex, the whole install asks one thing: whether to install the background service."
387
- },
388
- {
389
- "t": "Keys and proxy go into the service automatically",
390
- "d": "Installing the background service writes the environment-variable keys the config refers to, and your terminal's proxy, into the service definition (mode 600) without asking. Run sintbot service install again after changing a key or the proxy."
391
- },
392
- {
393
- "t": "Less output",
394
- "d": "The install no longer shows npm progress or harmless warnings, and the background service reports a single line when it is up."
395
- }
396
- ]
397
- },
398
- {
399
- "version": "1.0.12",
400
- "name": "Simpler install: the terminal sets up the model, the console does the rest",
401
- "items": [
402
- {
403
- "t": "The terminal only sets up the model",
404
- "d": "The setup wizard no longer asks whether the machine is in mainland China, or for a proxy, a projects folder or chat platform credentials. In the terminal it checks the environment and sets up a model with a live trial turn; everything else is set in the console afterwards. The old full set of questions is still available as sintbot setup --full, for servers without a browser."
405
- },
406
- {
407
- "t": "A console right after install",
408
- "d": "The background service now installs even before a chat platform is connected: it runs the console only (http://127.0.0.1:4600), and the one-line install opens it in your browser. Connect a platform under Settings and save; the service restarts itself within seconds and connects. The Overview page has a new Get started checklist."
409
- },
410
- {
411
- "t": "Bot name and network proxy in the console",
412
- "d": "Settings → Bot & network sets how the bot refers to itself and the network proxy. Service install can also carry your terminal's proxy into the service."
413
- },
414
- {
415
- "t": "English throughout, and small fixes",
416
- "d": "The installer and the wizard speak Chinese or English following the system language (on macOS, the system language). The site a Zhipu or MiniMax key belongs to is found automatically. An up-to-date install is no longer reinstalled, and sintbot ui opens the running service's console. Fixed wizard questions being overwritten by \"> \" and a stray *.0.1 in the direct-connection list."
417
- }
418
- ]
419
- },
420
- {
421
- "version": "1.0.11",
422
- "name": "Icon libraries from the setup wizard",
423
- "items": [
424
- {
425
- "t": "The wizard installs the icon libraries",
426
- "d": "When the design icon libraries (Lucide, Tabler, Phosphor and Pixelarticons) are missing, the setup wizard now offers to install them in one go (about 170 MB). With them, the bot uses standard icons by name when it draws a design instead of drawing its own."
427
- }
428
- ]
429
- },
430
- {
431
- "version": "1.0.10",
432
- "name": "A steadier background service",
433
- "items": [
434
- {
435
- "t": "No service without a chat platform",
436
- "d": "If no Feishu, Slack or WeCom bot is connected yet, installing the background service now stops and points you to the console to connect one and bind a group first. Before, the service would exit as soon as it started."
437
- },
438
- {
439
- "t": "Keys from environment variables reach the service",
440
- "d": "When the config takes keys from environment variables, installing the service now asks whether to write them into the service definition, readable only by you. Without them, models that use those keys do not work in the service."
441
- },
442
- {
443
- "t": "Clearer wording",
444
- "d": "Trial runs show the model from your config instead of the model's own claim (third-party models often call themselves Claude). The health check gives a missing chat platform a row of its own, and in a local terminal trial the model-switch hint says how to switch."
445
- }
446
- ]
447
- },
448
- {
449
- "version": "1.0.9",
450
- "name": "A steadier setup wizard",
451
- "items": [
452
- {
453
- "t": "No more looping without a terminal",
454
- "d": "When the setup wizard runs without keyboard input (in a script, a container or CI), it now finishes on the defaults instead of looping at the model step until the disk fills, and it no longer installs Claude Code on its own. If it still cannot finish, it stops and writes no config."
455
- }
456
- ]
457
- },
458
- {
459
- "version": "1.0.8",
460
- "name": "A clearer console, sharper style extraction",
461
- "items": [
462
- {
463
- "t": "\"Needs you\" on the console",
464
- "d": "The top of Overview lists what is waiting on you: failed tasks with their reason, browser takeovers nobody has claimed, open feedback, leftover background processes and failing health checks. It appears only when something does, and sends nothing extra to any group."
465
- },
466
- {
467
- "t": "Activity survives restarts",
468
- "d": "After a restart or an upgrade, live activity on Overview is filled back in from recent tasks, and failed tasks show their reason."
469
- },
470
- {
471
- "t": "Sharper style extraction",
472
- "d": "Extracting from a URL now reads stylesheets a site serves from other domains, so sites like Feishu and Bilibili work, and sites that need a proxy go through the configured one. Colors, fonts and radii are read more accurately, and anything it cannot read leaves your choices as they were."
473
- },
474
- {
475
- "t": "English throughout",
476
- "d": "The English console now covers the WeCom settings, health checks, scheduled-task descriptions and more, and the built-in design styles have English names and descriptions."
477
- }
478
- ]
479
- },
480
- {
481
- "version": "1.0.7",
482
- "name": "First official release",
483
- "items": [
484
- {
485
- "t": "One group, one project",
486
- "d": "Bind a Feishu, Slack or WeCom group to a project and anyone in the group can hand it work; each group has its own session, queue and permissions."
487
- },
488
- {
489
- "t": "Switch models anytime",
490
- "d": "Claude, GPT (through Codex), DeepSeek, GLM, MiniMax or a custom endpoint — each group picks its own and can switch at any time without losing the project memory."
491
- },
492
- {
493
- "t": "Progress in the group",
494
- "d": "Work in progress streams to a progress card in the group, and the result is posted back when it is done."
495
- },
496
- {
497
- "t": "Local console",
498
- "d": "Manage groups, models and chat platforms in the browser, run a test turn and read the version history; it can also be opened to your LAN or reached through a public entry."
499
- },
500
- {
501
- "t": "Easy to start",
502
- "d": "One-line install; the setup wizard recommends a model based on the accounts you already have and tries it on the spot, and the health check reports honestly what works and what needs fixing."
503
- },
504
- {
505
- "t": "Your data stays on your machine",
506
- "d": "Projects, sessions and memory stay on your own machine, and messages sent to the group are redacted automatically."
507
- }
508
- ]
509
207
  }
510
208
  ]
package/CHANGELOG.json CHANGED
@@ -1,4 +1,15 @@
1
1
  [
2
+ {
3
+ "version": "1.4.10",
4
+ "date": "2026-11-10",
5
+ "name": "执行中断收尾",
6
+ "items": [
7
+ {
8
+ "t": "修复:模型进程中途退出后群无法继续处理消息",
9
+ "d": "执行器确认退出但未返回最终结果时,原卡片显示中断提示,确认送达后继续处理下一条消息。不会将草稿当答案或自动重跑;已执行的操作需先核对。关闭或发送结果不明时仍保留现场。"
10
+ }
11
+ ]
12
+ },
2
13
  {
3
14
  "version": "1.4.9",
4
15
  "date": "2026-11-10",
@@ -193,325 +204,5 @@
193
204
  "d": "先重启服务;仍然暂停的群,在服务停止后运行 sintbot incident seal --group 群 ID。原记录原样封存,这个群换一份新记录重新开放,封存前未完成的消息不会再处理。"
194
205
  }
195
206
  ]
196
- },
197
- {
198
- "version": "1.4.0",
199
- "date": "2026-11-08",
200
- "name": "多群、Claude Code 与群内命令",
201
- "items": [
202
- {
203
- "t": "一个应用服务多个群",
204
- "d": "同一个飞书应用可绑定 1–32 个群,每个群对应一个本地项目,各自记录、互不影响;同时运行的任务数可设上限。"
205
- },
206
- {
207
- "t": "每个群可选 Codex 或 Claude Code",
208
- "d": "按群选择执行器和模型;群里发 /model 查看或切换,切换只在本群空闲时进行,并开始新的一段对话。"
209
- },
210
- {
211
- "t": "群内命令",
212
- "d": "新增 /help、/status、/new、/hud、/issue,查看状态、额度与用量,开始新对话,记下反馈;不支持的命令只回一句提示,不再中断服务。"
213
- },
214
- {
215
- "t": "回复卡片边做边更新",
216
- "d": "模型开始输出后卡片就出现,并随进度刷新。"
217
- },
218
- {
219
- "t": "本机控制台",
220
- "d": "带 --ui 启动后可查看各群状态、停止任务、绑定新群、切换空闲群的模型或项目目录、处理群内反馈。"
221
- },
222
- {
223
- "t": "出错只影响当前群",
224
- "d": "某一轮模型报错或没有结果时,只在本群提示重新发送,不自动重试,其他群照常;新加的群在重启时自动登记。"
225
- }
226
- ]
227
- },
228
- {
229
- "version": "1.3.0",
230
- "date": "2026-11-08",
231
- "name": "补充内置核心",
232
- "items": [
233
- {
234
- "t": "补充内置核心",
235
- "d": "本版支持 macOS 上的飞书单群 Codex 消息;画布、多群和其他平台后续迭代。已有多群安装请保留原版本,按新版安装指南单独配置。"
236
- }
237
- ]
238
- },
239
- {
240
- "version": "1.2.1",
241
- "date": "2026-11-05",
242
- "name": "修复补话时的误报",
243
- "items": [
244
- {
245
- "t": "刚开始处理时补话不再误报已排队",
246
- "d": "任务刚开始的几秒内补话,会在通道就绪后并入当前任务,不再先说一句「当前任务结束后处理」。"
247
- }
248
- ]
249
- },
250
- {
251
- "version": "1.2.0",
252
- "date": "2026-11-05",
253
- "name": "忙时跟进更可靠,出错说得更清楚",
254
- "items": [
255
- {
256
- "t": "回答卡片跟着最新的跟进走",
257
- "d": "跟进被接受后,回复卡片移到这条消息下面,做完时答案在群底部;卡片搬不了时才发一句「已加入」。"
258
- },
259
- {
260
- "t": "撤回和重做不再丢消息",
261
- "d": "撤回还没送达的跟进后不会再单独执行;换会话或切模型重做时,已送达的跟进会一起带上,撤回过的除外。"
262
- },
263
- {
264
- "t": "Codex 主动请求不再卡住任务",
265
- "d": "无人值守时按协议拒绝审批和提问请求,任务继续往下走。"
266
- },
267
- {
268
- "t": "控制台插话可以加入当前任务",
269
- "d": "勾了「回复」的插话按群成员消息处理;先等群里那行发出去再执行,插话框说明去向,提交后回报落点。"
270
- },
271
- {
272
- "t": "飞书回答卡显示模型和额度",
273
- "d": "卡片右下角的小字增加当前模型和账号额度。"
274
- },
275
- {
276
- "t": "连不上模型、余额不足都说人话",
277
- "d": "网络不通、余额不足、订阅过期在群里都有清楚的说明;连续网络失败发运维告警,账号类问题可切备用模型。"
278
- },
279
- {
280
- "t": "续接的会话不见了会自动重做",
281
- "d": "Claude 和 Codex 群都会清掉失效的会话,在新会话里重做这条,并在群里说一句。"
282
- }
283
- ]
284
- },
285
- {
286
- "version": "1.1.0",
287
- "date": "2026-11-05",
288
- "name": "Codex 忙时跟进",
289
- "items": [
290
- {
291
- "t": "Codex 可接收任务进行中的后续消息",
292
- "d": "Codex 群默认开启忙时跟进,通过 App Server 将普通真人后续消息送入当前任务;关联要求及时吸收,独立请求按序分别回应,未确认送达的消息回到队列。可按群关闭;Claude 群及定时、静默、轮询消息维持原行为。"
293
- },
294
- {
295
- "t": "忙时跟进仅对实际 Codex 后端开放",
296
- "d": "控制台按当前生效的后端显示开关,服务端也会校验;设置从下一轮开始生效。"
297
- }
298
- ]
299
- },
300
- {
301
- "version": "1.0.17",
302
- "date": "2026-11-05",
303
- "name": "安装判定和运行稳定性",
304
- "items": [
305
- {
306
- "t": "安装后实际运行一次才算成功",
307
- "d": "向导装好模型程序后会实际运行一次确认版本,文件存在或安装命令正常退出都不再算成功;校验失败时会说明原因和处理办法。"
308
- },
309
- {
310
- "t": "体检不再把不能运行的文件当成已安装",
311
- "d": "没有执行权限的文件不再被识别为可用程序。自动安装时也会带上程序运行所需的平台组件。"
312
- },
313
- {
314
- "t": "模型程序换位置后自动找回",
315
- "d": "配置的路径失效时,会在常见安装位置找同一个程序继续运行;哪里都找不到时在群里说明,并发运维告警。"
316
- },
317
- {
318
- "t": "登录失效和异常退出说得更清楚",
319
- "d": "登录令牌被吊销算账号问题,可切备用模型并告警;Codex 只输出错误就退出时也走同样的处理。"
320
- },
321
- {
322
- "t": "修复中文偶尔乱码",
323
- "d": "输出中的汉字被分块拆开时不再变成乱码。"
324
- }
325
- ]
326
- },
327
- {
328
- "version": "1.0.16",
329
- "date": "2026-10-30",
330
- "name": "AI 安装更安全,设计入口更克制",
331
- "items": [
332
- {
333
- "t": "AI 协助安装更安全",
334
- "d": "API key 在本机终端输入时会遮蔽回显,避免进入 AI 对话记录。没有交互终端时,缺少合格 Node 就停止;已有 Node 时则跳过模型配置和后台服务并说明后续步骤。"
335
- },
336
- {
337
- "t": "安装流程与首次使用更清晰",
338
- "d": "新增中英文 AI 安装与首次使用指南;一键预览会列出操作和确认项,并提示模型试跑可能消耗额度或产生费用。"
339
- },
340
- {
341
- "t": "设计库和图标库按需展示",
342
- "d": "两类资源默认折叠;仅在从零设计新产品且尚未确定视觉方向时推荐风格预设。"
343
- }
344
- ]
345
- },
346
- {
347
- "version": "1.0.15",
348
- "date": "2026-10-30",
349
- "name": "控制台设置布局更清晰",
350
- "items": [
351
- {
352
- "t": "软件更新与版本历史合并",
353
- "d": "合并为一张卡片并移到设置页底部;检测到新版时,版本号旁会显示一个提示点。"
354
- },
355
- {
356
- "t": "机器人与网络卡片横跨整行",
357
- "d": "机器人的名字和网络代理并排显示,后台网络详情可以展开查看。"
358
- }
359
- ]
360
- },
361
- {
362
- "version": "1.0.14",
363
- "date": "2026-10-30",
364
- "name": "服务重装与控制台管理更完善",
365
- "items": [
366
- {
367
- "t": "服务重装更稳定",
368
- "d": "重装时会等旧后台服务彻底退出后再启动,减少服务卡在未加载状态的情况。"
369
- },
370
- {
371
- "t": "控制台可管理软件更新",
372
- "d": "启动时及每天自动检查稳定版,也可手动检查。发现新版后由管理员确认,等所有群任务和队列空闲后再安装指定版本。"
373
- },
374
- {
375
- "t": "访问地址可在控制台管理",
376
- "d": "可以设置局域网访问密码、切换局域网监听和公网飞书登录。关闭公网登录会让现有飞书登录失效;切换监听失败时会恢复原设置。"
377
- }
378
- ]
379
- },
380
- {
381
- "version": "1.0.13",
382
- "date": "2026-10-28",
383
- "name": "安装再精简:几乎不用回答问题",
384
- "items": [
385
- {
386
- "t": "能自动做的不再问",
387
- "d": "一键安装直接升级到最新版;向导缺 Claude Code 直接装、自动选默认模型并试跑一轮,不再问要不要再加模型;Codex 和设计图标库是可选的,只给一行装法。已经登录 Claude 或 Codex 的话,整个安装只问一句要不要装后台服务。"
388
- },
389
- {
390
- "t": "key 和代理自动带进后台服务",
391
- "d": "装后台服务时,配置里引用的环境变量 key、以及终端里的代理,直接写进服务定义(文件权限 600),不再问。换了 key 或代理重跑一次 sintbot service install。"
392
- },
393
- {
394
- "t": "输出更短",
395
- "d": "安装过程不再打 npm 的进度和无害警告;后台服务装好只报一行。"
396
- }
397
- ]
398
- },
399
- {
400
- "version": "1.0.12",
401
- "date": "2026-10-28",
402
- "name": "安装更简单:终端只配模型,其余在控制台",
403
- "items": [
404
- {
405
- "t": "终端里只配模型",
406
- "d": "安装向导不再问这台机器在不在中国大陆,也不要求填代理、项目根目录和聊天平台凭据:终端里只检查环境、配好模型并当场试跑,其余装完在控制台里配。原来那一套问答保留为 sintbot setup --full,给没有浏览器的服务器用。"
407
- },
408
- {
409
- "t": "装完就有控制台",
410
- "d": "还没接聊天平台也能装后台服务:服务先只开控制台(http://127.0.0.1:4600),一键安装结束时会在浏览器里打开它。在「设置」里接好平台、保存后,服务几秒内自己重启并连上。概览页新增「开始使用」清单。"
411
- },
412
- {
413
- "t": "控制台补上机器人名字和网络代理",
414
- "d": "「设置 → 机器人与网络」可以改机器人的自称、填网络代理;装服务时也可以把终端里的代理一起带进服务。"
415
- },
416
- {
417
- "t": "中英双语与小修",
418
- "d": "安装脚本和向导按系统语言出中文或英文(macOS 看系统语言)。智谱、MiniMax 的 key 自动试出属于哪个站。已是最新版不再重装;服务在跑时 sintbot ui 直接打开它。修好向导问题被「> 」盖掉、代理直连名单里多出 *.0.1 的问题。"
419
- }
420
- ]
421
- },
422
- {
423
- "version": "1.0.11",
424
- "date": "2026-10-26",
425
- "name": "安装向导代装设计图标库",
426
- "items": [
427
- {
428
- "t": "向导代装设计图标库",
429
- "d": "安装向导发现设计图标库(Lucide、Tabler、Phosphor、Pixelarticons)没装时,会问一句要不要一次装齐(约 170 MB);装好后机器人出设计图能按名字取到标准图标,不用自己画。"
430
- }
431
- ]
432
- },
433
- {
434
- "version": "1.0.10",
435
- "date": "2026-10-26",
436
- "name": "常驻服务装得更稳",
437
- "items": [
438
- {
439
- "t": "没接聊天平台时不装常驻服务",
440
- "d": "安装时还没接飞书、Slack 或企业微信,就不再装常驻服务(装了也会一启动就退出),而是提示先在控制台里接好平台、绑群,再装服务。"
441
- },
442
- {
443
- "t": "环境变量里的 key 能带进服务",
444
- "d": "配置里的 key 取自环境变量时,装常驻服务会问一句要不要把它们写进服务定义(只有你自己能读);不写的话,服务里用这些 key 的模型用不了。"
445
- },
446
- {
447
- "t": "说法更准",
448
- "d": "试跑模型时直接显示配置里的型号,不再靠模型自报(第三方模型常自称 Claude);体检里「没配任何聊天平台」单列一行;在本机终端里试跑时,切模型的提示说清楚该怎么切。"
449
- }
450
- ]
451
- },
452
- {
453
- "version": "1.0.9",
454
- "date": "2026-10-26",
455
- "name": "安装向导更稳",
456
- "items": [
457
- {
458
- "t": "没有终端时向导不再空转",
459
- "d": "在脚本、容器或持续集成里运行安装向导、拿不到键盘输入时,向导会用默认值走完,不再在选模型那一步反复转圈、把磁盘写满,也不会自己去装 Claude Code;实在走不下去就停下提示,不写入配置。"
460
- }
461
- ]
462
- },
463
- {
464
- "version": "1.0.8",
465
- "date": "2026-10-24",
466
- "name": "控制台更好用,提炼风格更准",
467
- "items": [
468
- {
469
- "t": "控制台「需要你处理」",
470
- "d": "概览最上面汇总在等你的事:失败的任务和原因、没人认领的浏览器接管、没处理的反馈、残留的后台进程、没通过的健康检查;没事就不出现,也不往群里多发消息。"
471
- },
472
- {
473
- "t": "实时活动重启不丢",
474
- "d": "重启或升级之后,概览的实时活动会补回最近的任务记录;出错的任务直接显示原因。"
475
- },
476
- {
477
- "t": "从参考提炼风格更准",
478
- "d": "贴网址提炼时能读到网站放在其他域名上的样式表,飞书、B 站这类网站也能提炼,需要代理才能访问的网站走配置里的代理;颜色、字体和圆角读得更准,读不到的项不会改动你已经选好的。"
479
- },
480
- {
481
- "t": "英文界面补齐",
482
- "d": "控制台英文界面补全了企业微信设置、健康检查、定时任务说明等处,内置设计风格也有了英文名称和介绍。"
483
- }
484
- ]
485
- },
486
- {
487
- "version": "1.0.7",
488
- "date": "2026-10-24",
489
- "name": "首个正式版",
490
- "items": [
491
- {
492
- "t": "群即项目",
493
- "d": "一个飞书、Slack 或企业微信群绑一个项目,群里谁都能派活;每个群有自己的会话、排队和权限。"
494
- },
495
- {
496
- "t": "模型随时换",
497
- "d": "Claude、GPT(经 Codex)、DeepSeek、GLM、MiniMax 或自定义端点,每个群各选各的,群里随时切换,项目记忆不丢。"
498
- },
499
- {
500
- "t": "进度在群里",
501
- "d": "干活过程实时更新到群里的进度卡片,做完把结果发回群里。"
502
- },
503
- {
504
- "t": "本地控制台",
505
- "d": "在浏览器里管理群、模型和聊天平台,可以试跑一轮、查看版本历史;也可以开放到局域网,或经公网入口访问。"
506
- },
507
- {
508
- "t": "上手简单",
509
- "d": "一键安装;配置向导按你已有的账号推荐模型并当场试跑,体检如实报告哪些能用、哪些要修。"
510
- },
511
- {
512
- "t": "数据留在本机",
513
- "d": "项目、会话和记忆都在你自己的机器上,发到群里的消息自动脱敏。"
514
- }
515
- ]
516
207
  }
517
208
  ]
@@ -1,4 +1,4 @@
1
- # Install SintBot 1.4.9 with an AI assistant
1
+ # Install SintBot 1.4.10 with an AI assistant
2
2
 
3
3
  English · [简体中文](./zh-CN/AI-ASSISTED-INSTALL.md)
4
4
 
@@ -15,5 +15,5 @@ Use the terminal on the Mac that will run SintBot. A cloud shell cannot install
15
15
  ## Copyable request
16
16
 
17
17
  ```text
18
- Install SintBot 1.4.9 on this Mac using the one-line installation guide. Preserve existing services, configuration, state and Codex or Claude Code account data. Do not expose credentials. Verify the actual installed executable and binary core, configure the Feishu groups with their runners, and initialize only clean new state. Run the foreground preflight and an authorized read-only group test, check the result, then verify clean stop/restart. Stop temporary processes when finished, and distinguish package installation from successful group acceptance.
18
+ Install SintBot 1.4.10 on this Mac using the one-line installation guide. Preserve existing services, configuration, state and Codex or Claude Code account data. Do not expose credentials. Verify the actual installed executable and binary core, configure the Feishu groups with their runners, and initialize only clean new state. Run the foreground preflight and an authorized read-only group test, check the result, then verify clean stop/restart. Stop temporary processes when finished, and distinguish package installation from successful group acceptance.
19
19
  ```
package/docs/install.md CHANGED
@@ -1,4 +1,4 @@
1
- # Install SintBot 1.4.9
1
+ # Install SintBot 1.4.10
2
2
 
3
3
  English · [简体中文](./zh-CN/install.md)
4
4
 
@@ -10,7 +10,7 @@ You need a Mac, Node.js 22 or newer, and projects stored on that Mac. Install an
10
10
  curl -fsSL https://sintbot.com/install.sh | bash
11
11
  ```
12
12
 
13
- The installer checks the environment, installs `sintbot@1.4.9` into `~/.local/share/sintbot`, and verifies the entry, built-in core and Feishu module. Continue when you see `Installed and verified SintBot 1.4.9`. No sudo is needed.
13
+ The installer checks the environment, installs `sintbot@1.4.10` into `~/.local/share/sintbot`, and verifies the entry, built-in core and Feishu module. Continue when you see `Installed and verified SintBot 1.4.10`. No sudo is needed.
14
14
 
15
15
  To preview, append `-s -- --dry-run`. To choose another location, set `SINTBOT_INSTALL_DIR` and adjust the executable paths below.
16
16
 
@@ -1,4 +1,4 @@
1
- # 用 AI 助手安装 SintBot 1.4.9
1
+ # 用 AI 助手安装 SintBot 1.4.10
2
2
 
3
3
  [English](../AI-ASSISTED-INSTALL.md) · 简体中文
4
4
 
@@ -15,5 +15,5 @@
15
15
  ## 可复制的请求
16
16
 
17
17
  ```text
18
- 按一行安装指南,在这台 Mac 安装 SintBot 1.4.9。保留已有服务、配置、状态和 Codex 或 Claude Code 账号数据,不输出凭据。验证实际入口与二进制核心,配置飞书群及各群的执行器,只对全新状态初始化。运行前台预检和已授权的只读群测试,对照结果,再验证正常停止与重启。完成后停止临时进程,并区分程序包安装与群验收结果。
18
+ 按一行安装指南,在这台 Mac 安装 SintBot 1.4.10。保留已有服务、配置、状态和 Codex 或 Claude Code 账号数据,不输出凭据。验证实际入口与二进制核心,配置飞书群及各群的执行器,只对全新状态初始化。运行前台预检和已授权的只读群测试,对照结果,再验证正常停止与重启。完成后停止临时进程,并区分程序包安装与群验收结果。
19
19
  ```
@@ -1,4 +1,4 @@
1
- # 安装 SintBot 1.4.9
1
+ # 安装 SintBot 1.4.10
2
2
 
3
3
  [English](../install.md) · 简体中文
4
4
 
@@ -10,7 +10,7 @@
10
10
  curl -fsSL https://sintbot.com/install.sh | bash
11
11
  ```
12
12
 
13
- 安装器会自动检查环境,把 `sintbot@1.4.9` 装到 `~/.local/share/sintbot`,并验证程序入口、内置核心和飞书模块。看到 `Installed and verified SintBot 1.4.9` 就可以继续。不需要 sudo。
13
+ 安装器会自动检查环境,把 `sintbot@1.4.10` 装到 `~/.local/share/sintbot`,并验证程序入口、内置核心和飞书模块。看到 `Installed and verified SintBot 1.4.10` 就可以继续。不需要 sudo。
14
14
 
15
15
  可选预览:在命令末尾加 `-s -- --dry-run`。要自定义安装位置,设置 `SINTBOT_INSTALL_DIR` 环境变量,并同步修改后面的可执行文件路径。
16
16
 
package/install.sh CHANGED
@@ -2,7 +2,7 @@
2
2
  # The function is parsed in full before installation starts, including when piped.
3
3
  sintbot_install() (
4
4
  set -eu
5
- version=1.4.9
5
+ version=1.4.10
6
6
  prefix="${SINTBOT_INSTALL_DIR:-$HOME/.local/share/sintbot}"
7
7
  fail() { printf 'SintBot: %s\n' "$*" >&2; exit 1; }
8
8
  case "${1:-}" in
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sintbot",
3
- "version": "1.4.9",
3
+ "version": "1.4.10",
4
4
  "private": false,
5
5
  "description": "Drive your Mac projects from Feishu groups with Codex or Claude Code, using a built-in agent core.",
6
6
  "bin": {
@@ -455,6 +455,10 @@ function runTurn({
455
455
  }))
456
456
 
457
457
  const completeClose = (code) => finish(() => {
458
+ if (onDurableEvent && turnAccepted && !lastResult && !aborted) {
459
+ resolveRun({ sessionId: capturedSessionId, result: null, code, aborted })
460
+ return
461
+ }
458
462
  if (code !== 0 && !lastResult && !aborted) {
459
463
  return reject(closedError(new Error(`claude exited ${code}: ${stderr.trim().slice(0, 800) || '(no stderr)'}`)))
460
464
  }
@@ -486,6 +486,12 @@ function runTurn(opts = {}) {
486
486
  })
487
487
  const completeClose = (code) => settle(() => {
488
488
  if (onDurableEvent && !completed && !aborted) {
489
+ if (acceptedTurnId) {
490
+ // No synthetic result: retain the distinction between process
491
+ // closure and model completion for the durable terminal reducer.
492
+ resolveRun({ sessionId: capturedSessionId, result: null, code, aborted })
493
+ return
494
+ }
489
495
  reject(closedError(new Error(`codex app-server exited ${code} before a durable result`)))
490
496
  return
491
497
  }
@@ -402,6 +402,10 @@ function runOnce(opts, effort) {
402
402
  }))
403
403
 
404
404
  const completeClose = (code) => {
405
+ if (onDurableEvent && acceptedStart && !lastResult && !aborted) {
406
+ done(() => resolveRun({ sessionId: capturedSessionId, result: null, code, aborted }))
407
+ return
408
+ }
405
409
  if (onDurableEvent && code !== 0 && !lastResult && !aborted) {
406
410
  done(() => reject(closedError(new Error(`codex exited ${code} before a durable result`))))
407
411
  return
@@ -3,7 +3,7 @@ const fs = require('node:fs')
3
3
  const path = require('node:path')
4
4
  const { createHash } = require('node:crypto')
5
5
 
6
- const EXPECTED_SHA256 = '70bb1b33ba1d9f3249659a4721ed047350f866dd2b3601a67376df604a23b3fd'
6
+ const EXPECTED_SHA256 = '8c55d4f97a738e14885841f9b8f83906cca1e8e9aef46bb28f31022aef1fce2d'
7
7
  let bytes
8
8
  try {
9
9
  bytes = fs.readFileSync(path.join(__dirname, 'privatecore.wasm'))
Binary file
@@ -7,6 +7,7 @@
7
7
  const { createC2CardEffectBoundary, confirmCardOperation } = require('./c2cardeffectbridge')
8
8
  const { prepareTerminalEffectBridge, terminalReplyText } = require('./c2terminaleffectbridge')
9
9
  const { stripMilestones } = require('./turnprogress')
10
+ const { engineTerminalStep } = require('../agent/privatecore')
10
11
 
11
12
  function prepareCardTerminalPath({ runtime, payloadHandles, platform, replyCtx,
12
13
  cardAnchor = null, preferPlain = false,
@@ -207,10 +208,11 @@ function prepareCardTerminalPath({ runtime, payloadHandles, platform, replyCtx,
207
208
  if (card && await card.flush() !== true) {
208
209
  throw new Error('C2 card prior operations lack confirmed flush')
209
210
  }
210
- // Mirrors the private reducer's silent predicate. A posted card must
211
- // be durably recalled before the zero-send quiet settlement.
212
- const quiet = receipt.quiet || terminalPayload.resultText.trim() === 'NO_REPLY' ||
213
- (!terminalPayload.resultText.trim() && terminalPayload.bufferText.trim() === 'NO_REPLY')
211
+ // Partial NO_REPLY text on a crashed turn is not a silent completion.
212
+ const terminalEvent = { ...terminalPayload, type: 'finalize' }
213
+ delete terminalEvent.receiptId; delete terminalEvent.turnToken; delete terminalEvent.quiet
214
+ const quiet = receipt.quiet || engineTerminalStep(
215
+ { finalized: false, outcome: null }, terminalEvent).state.outcome.silent
214
216
  if (suppressedCard && !quiet) {
215
217
  throw new Error('C2 suppressed card needs a silent terminal')
216
218
  }
@@ -9,6 +9,7 @@ const { C2PayloadHandles } = require('./c2payloadhandles')
9
9
  const { engineTerminalStep } = require('../agent/privatecore')
10
10
 
11
11
  const FAILURE_NOTICE = '本次任务执行失败。若已执行过工具,请先核对实际结果,再决定是否重试。'
12
+ const INTERRUPTED_NOTICE = '本次任务执行中断,未收到最终结果。已执行的操作可能已经生效,请核对后再决定是否重试。'
12
13
 
13
14
  const RECEIPT_ID = /^[0-9a-f]{32}$/
14
15
  const GENERATION = /^[0-9a-f]{32}$/
@@ -28,11 +29,12 @@ function terminalReplyText(payload) {
28
29
  }
29
30
  // The core classifies the result; the host supplies a fixed display string.
30
31
  // Neither a provider error nor unfinished assistant text is a final answer.
31
- if (payload.source === 'result' && payload.isError === true) {
32
+ if (payload.source === 'runner-exit' || payload.source === 'result' && payload.isError === true) {
32
33
  const event = { ...payload, type: 'finalize' }
33
34
  delete event.receiptId; delete event.turnToken; delete event.quiet
34
35
  if (engineTerminalStep({ finalized: false, outcome: null }, event)
35
- .state.outcome.status === 'error') return FAILURE_NOTICE
36
+ .state.outcome.status === 'error') return payload.source === 'runner-exit'
37
+ ? INTERRUPTED_NOTICE : FAILURE_NOTICE
36
38
  }
37
39
  return (payload.answerText.trim() ? payload.answerText : payload.bufferText) ||
38
40
  payload.resultText
@@ -8,11 +8,11 @@ const NO_REPLY = 'NO_REPLY'
8
8
  const { isDeepStrictEqual } = require('node:util')
9
9
 
10
10
  function createC2TurnProjection({ receiptId, turnToken, quiet, resumed = false,
11
- freshRetried = false, batchReceiptIds } = {}) {
11
+ freshRetried = false, batchReceiptIds, requireResult = false } = {}) {
12
12
  if (!RECEIPT_ID.test(receiptId || '') ||
13
13
  !Number.isSafeInteger(turnToken) || turnToken <= 0 ||
14
14
  typeof quiet !== 'boolean' || typeof resumed !== 'boolean' ||
15
- typeof freshRetried !== 'boolean') {
15
+ typeof freshRetried !== 'boolean' || typeof requireResult !== 'boolean') {
16
16
  throw new TypeError('C2 projection needs a typed running receipt')
17
17
  }
18
18
  if (batchReceiptIds !== undefined &&
@@ -137,10 +137,11 @@ function createC2TurnProjection({ receiptId, turnToken, quiet, resumed = false,
137
137
  throw new TypeError('C2 projection current resumed session requires abort')
138
138
  }
139
139
  completed = true
140
+ const runnerExit = requireResult && !observedResult && !runnerResult.aborted
140
141
  const resultText = observedResult?.text || ''
141
142
  const payload = Object.freeze({
142
143
  type: 'finalizeEffectCommit', receiptId, turnToken, quiet,
143
- source: observedResult ? 'result' : 'close',
144
+ source: observedResult ? 'result' : runnerExit ? 'runner-exit' : 'close',
144
145
  aborted: runnerResult.aborted,
145
146
  isError: observedResult?.isError || false,
146
147
  resumed, sessionMissing: observedResult?.sessionMissing || false,
@@ -156,10 +157,12 @@ function createC2TurnProjection({ receiptId, turnToken, quiet, resumed = false,
156
157
  const display = Object.freeze({
157
158
  resultText, bufferText, answerText, fullText,
158
159
  finalAnswer: (answerText.trim() ? answerText : bufferText) || resultText,
159
- silent: quiet || resultText.trim() === NO_REPLY ||
160
- (!resultText.trim() && bufferText.trim() === NO_REPLY),
160
+ silent: quiet || !runnerExit && (resultText.trim() === NO_REPLY ||
161
+ (!resultText.trim() && bufferText.trim() === NO_REPLY)),
161
162
  assistantEvents, tools,
162
- sessionId: runnerResult.sessionId || sessionId,
163
+ // A crashed process may never have flushed its new session. Retain the
164
+ // previously stored session; never publish an unproven new session ID.
165
+ sessionId: runnerExit ? null : runnerResult.sessionId || sessionId,
163
166
  contextTokens,
164
167
  usage: result?.usage || null,
165
168
  usageCumulative: result?.usageCumulative === true,
@@ -167,10 +167,11 @@ function supportedV2QuotaFailure(payload, runnerResult) {
167
167
  // Error classification remains in the core; close/session/effect authority is
168
168
  // checked by the terminal path before any delivery can be attempted.
169
169
  function supportedV2ClosedFailure(payload, runnerResult) {
170
- if (!payload || payload.source !== 'result' || payload.aborted ||
170
+ if (!payload || !['result', 'runner-exit'].includes(payload.source) || payload.aborted ||
171
171
  payload.sessionMissing || payload.transientNetwork || payload.hasQuota ||
172
172
  payload.freshRetried || payload.resumedSessionCurrent ||
173
- runnerResult?.aborted !== false) return false
173
+ runnerResult?.aborted !== false ||
174
+ (payload.source === 'runner-exit' && runnerResult.result != null)) return false
174
175
  const terminal = { ...payload, type: 'finalize' }
175
176
  delete terminal.receiptId; delete terminal.turnToken; delete terminal.quiet
176
177
  return engineTerminalStep({ finalized: false, outcome: null }, terminal)
@@ -1266,7 +1267,7 @@ async _drainDurableV2NormalChain(initial) {
1266
1267
  error.classificationEventId = classified.eventId
1267
1268
  throw error
1268
1269
  }
1269
- if (payload.source !== 'result' || payload.sessionMissing ||
1270
+ if ((payload.source !== 'result' && !closedFailure) || payload.sessionMissing ||
1270
1271
  (payload.hasQuota && !quotaFailure) || payload.transientNetwork || payload.freshRetried ||
1271
1272
  payload.resumedSessionCurrent ||
1272
1273
  (!['ok', 'no-reply'].includes(outcome.status) && !quotaFailure && !closedFailure)) {
@@ -1523,7 +1524,7 @@ async startDurableV2Runner({ chatId, receiptId, turnToken, effectId } = {}) {
1523
1524
  throw new Error('C2 v2 runner effect changed before start')
1524
1525
  }
1525
1526
  const projection = createC2TurnProjection({ receiptId, turnToken,
1526
- quiet: receipt.quiet,
1527
+ quiet: receipt.quiet, requireResult: true,
1527
1528
  resumed: !!this.store.getSession(chatId), freshRetried: false,
1528
1529
  ...(cohort.receiptIds.length > 1
1529
1530
  ? { batchReceiptIds: cohort.receiptIds } : {}) })
@@ -1997,7 +1998,7 @@ async completeDurableV2CardTurn({ chatId, receiptId, turnToken, effectId,
1997
1998
  !isDeepStrictEqual(payload, projected.payload) ||
1998
1999
  // A deterministic failure is delivered once, after the same durable
1999
2000
  // close checks as success. Retry and unknown outcomes stay sealed.
2000
- payload.source !== 'result' || payload.aborted || (payload.isError && !quotaFailure && !closedFailure) ||
2001
+ (payload.source !== 'result' && !closedFailure) || payload.aborted || (payload.isError && !quotaFailure && !closedFailure) ||
2001
2002
  payload.sessionMissing || (payload.hasQuota && !quotaFailure) || payload.transientNetwork ||
2002
2003
  payload.freshRetried || payload.resumedSessionCurrent ||
2003
2004
  (replyText !== undefined && replyText !== terminalReplyText(projected.payload)) ||