baychat 0.30.0 → 0.31.0

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 (38) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +36 -3
  3. package/dist/approval-wait.js +46 -33
  4. package/dist/approve-hook.js +35 -1
  5. package/dist/auto-update/describe.js +66 -0
  6. package/dist/auto-update/notice.js +40 -0
  7. package/dist/auto-update/policy.js +110 -0
  8. package/dist/auto-update/relay-glue.js +143 -0
  9. package/dist/auto-update/store.js +140 -0
  10. package/dist/auto-update/updater.js +324 -0
  11. package/dist/channel/permission.js +6 -0
  12. package/dist/cli-help.js +6 -1
  13. package/dist/denied/after-hook.js +8 -2
  14. package/dist/denied/confirm.js +131 -0
  15. package/dist/denied/grants.js +60 -2
  16. package/dist/denied/hook-log.js +75 -0
  17. package/dist/denied/live-session.js +154 -0
  18. package/dist/denied/notice.js +29 -0
  19. package/dist/denied/permission-rule.js +9 -6
  20. package/dist/denied/settings-rules.js +61 -0
  21. package/dist/denied/transcript.js +39 -16
  22. package/dist/denied-hook.js +132 -30
  23. package/dist/doctor-command.js +7 -1
  24. package/dist/doctor.js +28 -0
  25. package/dist/main.js +11 -2
  26. package/dist/permissions-command.js +18 -1
  27. package/dist/refresh-clients.js +36 -0
  28. package/dist/relay/acp/runner.js +4 -0
  29. package/dist/relay/commands.js +19 -3
  30. package/dist/relay/daemon.js +37 -1
  31. package/dist/relay/launcher/loop.js +4 -1
  32. package/dist/relay/self-restart.js +149 -0
  33. package/dist/relay/terminal-pane.js +74 -2
  34. package/dist/self-upgrade.js +92 -27
  35. package/dist/start-command.js +15 -1
  36. package/dist/update-command.js +51 -31
  37. package/dist/waiting-cards.js +107 -0
  38. package/package.json +4 -1
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.markWaitingCard = markWaitingCard;
37
+ exports.countWaitingCards = countWaitingCards;
38
+ const fs = __importStar(require("fs"));
39
+ const path = __importStar(require("path"));
40
+ const config_1 = require("./config");
41
+ const parent_watch_1 = require("./relay/parent-watch");
42
+ /**
43
+ * Which processes on this computer are waiting for a tap on a decision card right now.
44
+ *
45
+ * The hooks (`approve-hook`, `denied-hook`) and the Claude Code channel each wait on their own
46
+ * card in their own process, so nothing else on the machine knows a question is open. The relay's
47
+ * automatic update must (docs/features/CLI_AUTO_UPDATE.md): it never restarts BayChat while
48
+ * somebody is about to answer one. So each waiter leaves a marker for as long as it waits —
49
+ * `~/.baychat/waiting-cards/<pid>-<card id>` — and removes it when done. A crashed waiter's marker
50
+ * is ignored (and cleared) because its pid is gone; an absurdly old one because pids are reused.
51
+ */
52
+ /** Longer than any card is waited on (the denied-command card's 3600 s, an approval's day). */
53
+ const MARKER_MAX_AGE_MS = 2 * 24 * 60 * 60 * 1000;
54
+ function markerDir() {
55
+ return path.join((0, config_1.configDir)(), "waiting-cards");
56
+ }
57
+ /** Mark `cardId` as waited on by this process. Returns the function that ends the mark. Never throws. */
58
+ function markWaitingCard(cardId, pid = process.pid) {
59
+ const safeId = cardId.replace(/[^A-Za-z0-9_-]/g, "").slice(0, 64) || "card";
60
+ let file;
61
+ try {
62
+ file = path.join(markerDir(), `${pid}-${safeId}`);
63
+ fs.mkdirSync(markerDir(), { recursive: true, mode: 0o700 });
64
+ fs.writeFileSync(file, "");
65
+ }
66
+ catch {
67
+ // Without the marker an update might restart the relay mid-question; the card itself still
68
+ // works, because its wait never goes through the relay. Not worth failing a hook over.
69
+ return () => undefined;
70
+ }
71
+ return () => {
72
+ try {
73
+ fs.rmSync(file, { force: true });
74
+ }
75
+ catch {
76
+ // A marker left behind is ignored once this process has exited (its pid is gone).
77
+ }
78
+ };
79
+ }
80
+ /** How many cards live processes are waiting on. Stale markers are removed on the way. */
81
+ function countWaitingCards(isAlive = parent_watch_1.processIsAlive, now = Date.now()) {
82
+ let names;
83
+ try {
84
+ names = fs.readdirSync(markerDir());
85
+ }
86
+ catch {
87
+ // No directory: nobody has ever waited on a card here.
88
+ return 0;
89
+ }
90
+ let live = 0;
91
+ for (const name of names) {
92
+ const file = path.join(markerDir(), name);
93
+ const pid = Number(name.split("-")[0]);
94
+ let fresh = false;
95
+ try {
96
+ fresh = now - fs.statSync(file).mtimeMs < MARKER_MAX_AGE_MS;
97
+ }
98
+ catch {
99
+ continue; // Removed between the listing and the look: its waiter finished.
100
+ }
101
+ if (Number.isInteger(pid) && pid > 1 && fresh && isAlive(pid))
102
+ live += 1;
103
+ else
104
+ fs.rmSync(file, { force: true });
105
+ }
106
+ return live;
107
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "baychat",
3
- "version": "0.30.0",
3
+ "version": "0.31.0",
4
4
  "description": "BayChat connector CLI — pair an agent session (Claude Code, Codex, Cursor) with BayChat, or have the relay run DeepSeek or the Cursor CLI for you",
5
5
  "bin": {
6
6
  "baychat": "dist/index.js"
@@ -22,6 +22,9 @@
22
22
  "vitest": "^4.1.10"
23
23
  },
24
24
  "license": "MIT",
25
+ "baychat": {
26
+ "attention": {}
27
+ },
25
28
  "homepage": "https://baychat.io",
26
29
  "keywords": [
27
30
  "baychat",