@seqyuan/annodex 0.1.66 → 0.1.67

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.
Files changed (71) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +8 -8
  3. package/.next/build-manifest.json +2 -2
  4. package/.next/prerender-manifest.json +3 -3
  5. package/.next/required-server-files.js +1 -1
  6. package/.next/required-server-files.json +1 -1
  7. package/.next/server/app/_global-error.html +1 -1
  8. package/.next/server/app/_global-error.rsc +1 -1
  9. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  10. package/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  11. package/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  12. package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  13. package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  14. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  15. package/.next/server/app/_not-found.html +1 -1
  16. package/.next/server/app/_not-found.rsc +1 -1
  17. package/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  18. package/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  19. package/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  20. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  21. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  22. package/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  23. package/.next/server/app/api/internal/runtime/route.js +1 -1
  24. package/.next/server/app/api/version/route.js +1 -1
  25. package/.next/server/app/docs/changelog.html +2 -2
  26. package/.next/server/app/docs/changelog.rsc +1 -1
  27. package/.next/server/app/docs/changelog.segments/_full.segment.rsc +1 -1
  28. package/.next/server/app/docs/changelog.segments/_head.segment.rsc +1 -1
  29. package/.next/server/app/docs/changelog.segments/_index.segment.rsc +1 -1
  30. package/.next/server/app/docs/changelog.segments/_tree.segment.rsc +1 -1
  31. package/.next/server/app/docs/changelog.segments/docs/changelog/__PAGE__.segment.rsc +1 -1
  32. package/.next/server/app/docs/changelog.segments/docs/changelog.segment.rsc +1 -1
  33. package/.next/server/app/docs/changelog.segments/docs.segment.rsc +1 -1
  34. package/.next/server/app/index.html +1 -1
  35. package/.next/server/app/index.rsc +1 -1
  36. package/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  37. package/.next/server/app/index.segments/_full.segment.rsc +1 -1
  38. package/.next/server/app/index.segments/_head.segment.rsc +1 -1
  39. package/.next/server/app/index.segments/_index.segment.rsc +1 -1
  40. package/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  41. package/.next/server/app/login.html +1 -1
  42. package/.next/server/app/login.rsc +1 -1
  43. package/.next/server/app/login.segments/_full.segment.rsc +1 -1
  44. package/.next/server/app/login.segments/_head.segment.rsc +1 -1
  45. package/.next/server/app/login.segments/_index.segment.rsc +1 -1
  46. package/.next/server/app/login.segments/_tree.segment.rsc +1 -1
  47. package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +1 -1
  48. package/.next/server/app/login.segments/login.segment.rsc +1 -1
  49. package/.next/server/app/workspace/page.js +2 -2
  50. package/.next/server/app/workspace/page_client-reference-manifest.js +1 -1
  51. package/.next/server/app/workspace.html +1 -1
  52. package/.next/server/app/workspace.rsc +2 -2
  53. package/.next/server/app/workspace.segments/_full.segment.rsc +2 -2
  54. package/.next/server/app/workspace.segments/_head.segment.rsc +1 -1
  55. package/.next/server/app/workspace.segments/_index.segment.rsc +1 -1
  56. package/.next/server/app/workspace.segments/_tree.segment.rsc +1 -1
  57. package/.next/server/app/workspace.segments/workspace/__PAGE__.segment.rsc +2 -2
  58. package/.next/server/app/workspace.segments/workspace.segment.rsc +1 -1
  59. package/.next/server/app-paths-manifest.json +8 -8
  60. package/.next/server/chunks/6983.js +1 -1
  61. package/.next/server/middleware-build-manifest.js +1 -1
  62. package/.next/server/pages/404.html +1 -1
  63. package/.next/server/pages/500.html +1 -1
  64. package/.next/server/server-reference-manifest.json +1 -1
  65. package/.next/static/chunks/app/workspace/{page-58f5134d374168a0.js → page-ff1403a471d556ca.js} +2 -2
  66. package/README.md +1 -1
  67. package/bin/annodex-im-gateway.js +5 -0
  68. package/bin/annodex.js +106 -2
  69. package/package.json +1 -1
  70. /package/.next/static/{Tw37G4SGOapzOhkWj9bG4 → 35GeCDRUeg9OBUsdN7kvk}/_buildManifest.js +0 -0
  71. /package/.next/static/{Tw37G4SGOapzOhkWj9bG4 → 35GeCDRUeg9OBUsdN7kvk}/_ssgManifest.js +0 -0
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  AI-native bioinformatics workspace by Annoroad, backed by Codex app-server. Browser workspace for project-scoped agent chat, file preview, extensions, and multi-provider models.
4
4
 
5
- Version: `0.1.66`
5
+ Version: `0.1.67`
6
6
  Repository: [seqyuan/annodex](https://github.com/seqyuan/annodex)
7
7
  Docs site: see [`site/`](site/) (Fumadocs)
8
8
 
@@ -454,11 +454,16 @@ class ProjectWeComBridge {
454
454
  chatId: inbound.chatId,
455
455
  });
456
456
 
457
+ if (result.ok === false) {
458
+ console.error(`[im] turn failed for ${this.project.cwd} user ${inbound.userId}: ${result.error || result.reply || "unknown error"}`);
459
+ }
460
+
457
461
  const text = typeof result.reply === "string" && result.reply.trim()
458
462
  ? result.reply.trim()
459
463
  : (result.error ? String(result.error) : "No reply from annodex.");
460
464
  await reply.finish(text);
461
465
  } catch (error) {
466
+ console.error(`[im] turn request failed for ${this.project.cwd} user ${inbound.userId}: ${String(error)}`);
462
467
  await reply.fail(`annodex IM error: ${String(error)}`);
463
468
  } finally {
464
469
  if (refreshTimer) clearInterval(refreshTimer);
package/bin/annodex.js CHANGED
@@ -535,12 +535,28 @@ function waitForPidExit(pid, timeoutMs) {
535
535
 
536
536
  async function terminatePid(pid, termTimeoutMs = STOP_TERM_TIMEOUT_MS, killTimeoutMs = STOP_KILL_TIMEOUT_MS) {
537
537
  if (!isPidAlive(pid)) return true;
538
+ if (process.platform === "linux") {
539
+ try {
540
+ process.kill(-pid, "SIGTERM");
541
+ if (await waitForPidExit(pid, termTimeoutMs)) return true;
542
+ } catch {
543
+ // Process may not be a group leader; fall back to single-pid termination.
544
+ }
545
+ }
538
546
  try {
539
547
  process.kill(pid, "SIGTERM");
540
548
  } catch {
541
549
  return !isPidAlive(pid);
542
550
  }
543
551
  if (await waitForPidExit(pid, termTimeoutMs)) return true;
552
+ if (process.platform === "linux") {
553
+ try {
554
+ process.kill(-pid, "SIGKILL");
555
+ if (await waitForPidExit(pid, killTimeoutMs)) return true;
556
+ } catch {
557
+ // ignore
558
+ }
559
+ }
544
560
  try {
545
561
  process.kill(pid, "SIGKILL");
546
562
  } catch {
@@ -549,6 +565,81 @@ async function terminatePid(pid, termTimeoutMs = STOP_TERM_TIMEOUT_MS, killTimeo
549
565
  return waitForPidExit(pid, killTimeoutMs);
550
566
  }
551
567
 
568
+ function looksLikeAnnodexCodexAppServer(cmdline) {
569
+ if (!cmdline) return false;
570
+ const lower = cmdline.toLowerCase();
571
+ if (!lower.includes("app-server")) return false;
572
+ return (
573
+ lower.includes("annodex-router") ||
574
+ lower.includes("model_providers.annodex-router") ||
575
+ lower.includes("@seqyuan/annodex") ||
576
+ lower.includes("/annodex/") ||
577
+ lower.includes("\\annodex\\")
578
+ );
579
+ }
580
+
581
+ function looksLikeAnnodexImGateway(cmdline) {
582
+ return !!cmdline && cmdline.includes("annodex-im-gateway");
583
+ }
584
+
585
+ function listProcessPids() {
586
+ const pids = [];
587
+ if (process.platform === "linux") {
588
+ try {
589
+ for (const entry of fs.readdirSync("/proc")) {
590
+ if (/^\d+$/.test(entry)) {
591
+ const pid = Number(entry);
592
+ if (Number.isInteger(pid) && pid > 0) pids.push(pid);
593
+ }
594
+ }
595
+ return pids;
596
+ } catch {
597
+ // Fall through to ps.
598
+ }
599
+ }
600
+ try {
601
+ const result = spawnSync("ps", ["-eo", "pid="], { encoding: "utf8" });
602
+ if (result.status === 0) {
603
+ for (const line of result.stdout.split(/\r?\n/)) {
604
+ const pid = Number(line.trim());
605
+ if (Number.isInteger(pid) && pid > 0) pids.push(pid);
606
+ }
607
+ }
608
+ } catch {
609
+ // ignore
610
+ }
611
+ return pids;
612
+ }
613
+
614
+ function findMatchingProcessPids(matcher) {
615
+ const pids = new Set();
616
+ for (const pid of listProcessPids()) {
617
+ if (pid === process.pid) continue;
618
+ const cmdline = readProcessCmdline(pid);
619
+ if (matcher(cmdline)) pids.add(pid);
620
+ }
621
+ return [...pids];
622
+ }
623
+
624
+ async function stopMatchingProcesses(matcher, label, quiet = false) {
625
+ const pids = findMatchingProcessPids(matcher);
626
+ if (pids.length === 0) return { found: 0, stopped: true, pids: [] };
627
+
628
+ let stopped = true;
629
+ for (const pid of pids) {
630
+ stopped = (await terminatePid(pid)) && stopped;
631
+ }
632
+
633
+ if (!quiet) {
634
+ const pidList = pids.join(", ");
635
+ console.log(stopped
636
+ ? `annodex stop: stopped ${pids.length} ${label}${pids.length === 1 ? "" : "es"} (pid${pids.length === 1 ? "" : "s"} ${pidList})`
637
+ : `annodex stop: failed to stop some ${label} processes (pids ${pidList})`);
638
+ }
639
+
640
+ return { found: pids.length, stopped, pids };
641
+ }
642
+
552
643
  function renderState(state, json = false) {
553
644
  const supervisorAlive = !!state && isPidAlive(state.supervisorPid);
554
645
  const nextAlive = !!state && isPidAlive(state.nextPid);
@@ -614,7 +705,9 @@ async function stopManagedServer(quiet = false) {
614
705
  const state = readState();
615
706
  if (!state) {
616
707
  const portStop = await stopVerifiedPortListeners(port, quiet);
617
- if (portStop.found) return portStop.stopped ? 0 : 1;
708
+ const codexStop = await stopMatchingProcesses(looksLikeAnnodexCodexAppServer, "orphaned codex app-server process", quiet);
709
+ if (portStop.found) return portStop.stopped && codexStop.stopped ? 0 : 1;
710
+ if (codexStop.found > 0) return codexStop.stopped ? 0 : 1;
618
711
  if (!quiet) console.log("annodex stop: already stopped");
619
712
  return 0;
620
713
  }
@@ -630,9 +723,12 @@ async function stopManagedServer(quiet = false) {
630
723
  }
631
724
  if (stopped) {
632
725
  removeState();
726
+ const codexStop = await stopMatchingProcesses(looksLikeAnnodexCodexAppServer, "orphaned codex app-server process", quiet);
633
727
  if (!quiet) console.log(`annodex stop: stopped${supervisorPid ? ` pid ${supervisorPid}` : ""}`);
728
+ if (!codexStop.stopped) return 1;
634
729
  return 0;
635
730
  }
731
+ await stopMatchingProcesses(looksLikeAnnodexCodexAppServer, "orphaned codex app-server process", quiet);
636
732
  if (!quiet) console.error(`annodex stop: failed to stop pid ${supervisorPid}`);
637
733
  return 1;
638
734
  }
@@ -967,6 +1063,14 @@ function runDoctor(json = false, repair = false) {
967
1063
  }
968
1064
  if (report.codex.selected.exists === false) report.recommendations.push("ANNODEX_CODEX_PATH is set but does not exist. Fix or unset it.");
969
1065
  if (versionProbe && !versionProbe.ok) report.recommendations.push("codex --version probe failed. Check the selected codex path and macOS security dialogs/logs.");
1066
+ const orphanCodexPids = findMatchingProcessPids(looksLikeAnnodexCodexAppServer);
1067
+ if (orphanCodexPids.length > 0) {
1068
+ report.recommendations.push(`Found ${orphanCodexPids.length} orphaned codex app-server process${orphanCodexPids.length === 1 ? "" : "es"} (pids ${orphanCodexPids.join(", ")}). Run \`annodex stop\` to clean them up.`);
1069
+ }
1070
+ const orphanGatewayPids = findMatchingProcessPids(looksLikeAnnodexImGateway);
1071
+ if (orphanGatewayPids.length > 0 && !isPidAlive(readState()?.supervisorPid)) {
1072
+ report.recommendations.push(`annodex-im-gateway is running (pids ${orphanGatewayPids.join(", ")}) but annodex is stopped — IM replies need annodex running; the gateway can stay up.`);
1073
+ }
970
1074
 
971
1075
  if (json) {
972
1076
  console.log(JSON.stringify(report, null, 2));
@@ -1025,7 +1129,7 @@ Usage:
1025
1129
  annodex [options]
1026
1130
  annodex start Start annodex in background
1027
1131
  annodex restart Stop then start annodex in background
1028
- annodex stop Stop background annodex
1132
+ annodex stop Stop background annodex (and orphaned codex app-server processes)
1029
1133
  annodex status [--json] Show background server status
1030
1134
  annodex logs [-f] Show background server logs
1031
1135
  annodex doctor [--json] [--repair] Diagnose local codex/runtime setup
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seqyuan/annodex",
3
- "version": "0.1.66",
3
+ "version": "0.1.67",
4
4
  "description": "AI-native bioinformatics workspace by Annoroad",
5
5
  "license": "MIT",
6
6
  "bin": {