@noxsoft/anima 5.0.3 → 5.1.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 (53) hide show
  1. package/dist/build-info.json +3 -3
  2. package/dist/bundled/boot-md/handler.js +1 -1
  3. package/dist/bundled/bootstrap-extra-files/handler.js +1 -1
  4. package/dist/bundled/session-memory/handler.js +2 -2
  5. package/dist/canvas-host/a2ui/.bundle.hash +1 -1
  6. package/dist/{command-registry-C3SmyTQU.js → command-registry-C2OzDE22.js} +5 -5
  7. package/dist/{completion-cli-D7gWcWEj.js → completion-cli-BjGTEn0-.js} +1 -1
  8. package/dist/{completion-cli-308M08su.js → completion-cli-Dafpu0xU.js} +2 -2
  9. package/dist/control-ui/assets/{index-T9qO6Dye.js → index-qmVN_9qV.js} +2 -2
  10. package/dist/control-ui/assets/{index-T9qO6Dye.js.map → index-qmVN_9qV.js.map} +1 -1
  11. package/dist/control-ui/index.html +1 -1
  12. package/dist/{doctor-C_1WNQix.js → doctor-C60p9Wb-.js} +1 -1
  13. package/dist/{doctor-9cbiXykn.js → doctor-DUc-8AEz.js} +1 -1
  14. package/dist/{doctor-completion-D7uvGhAv.js → doctor-completion-BByLPJCm.js} +1 -1
  15. package/dist/{doctor-completion-B1cKYcZj.js → doctor-completion-hJ6FS0xQ.js} +1 -1
  16. package/dist/{engine-634ModrT.js → engine-BUfB6LK8.js} +174 -1
  17. package/dist/{engine-CQSXA0CY.js → engine-CILiNnsV.js} +174 -1
  18. package/dist/entry.js +1 -1
  19. package/dist/{gateway-cli-CufIzw2K.js → gateway-cli-CIyCKLlw.js} +6 -6
  20. package/dist/{gateway-cli-CBmfvcpr.js → gateway-cli-EWjMWXQ8.js} +5 -5
  21. package/dist/index.js +1 -1
  22. package/dist/{onboard-CJOJPctL.js → onboard-0jkVY0R7.js} +1 -1
  23. package/dist/{onboard-C7ZSJNCe.js → onboard-CXF35e0Q.js} +1 -1
  24. package/dist/{onboarding-DP2NlqhA.js → onboarding-DUwydrf2.js} +2 -2
  25. package/dist/{onboarding-Caiq91Yz.js → onboarding-DnJvWjIp.js} +2 -2
  26. package/dist/{program-DxItv_Ts.js → program-5WLZIQS0.js} +2 -2
  27. package/dist/{program-context-cgh8PMPD.js → program-context-D9GxGetv.js} +7 -7
  28. package/dist/{register.anima-Dc7OI2Nh.js → register.anima-6AX4kr6X.js} +2 -2
  29. package/dist/{register.anima-bys_cyEd.js → register.anima-TQ2FcqSW.js} +2 -2
  30. package/dist/{register.maintenance-BToHjam6.js → register.maintenance-BfH0d3D1.js} +4 -4
  31. package/dist/{register.maintenance-DXL3L0ip.js → register.maintenance-aV9eDZ8M.js} +5 -5
  32. package/dist/{register.onboard-Bg5zEb3f.js → register.onboard-DMIRIaKp.js} +6 -6
  33. package/dist/{register.onboard-B3hbdfaQ.js → register.onboard-KGgXqrIn.js} +5 -5
  34. package/dist/{register.setup-CZqwphif.js → register.setup-Bn-Wvo1o.js} +6 -6
  35. package/dist/{register.setup-Cq8nqbrU.js → register.setup-jbxBj9qs.js} +5 -5
  36. package/dist/{register.subclis-mbYw7H-_.js → register.subclis-D_5Wry25.js} +3 -3
  37. package/dist/{run-DE6EaeE3.js → run-C3FoI9q0.js} +1 -1
  38. package/dist/{run-S0Cw3Fyy.js → run-DjvqhNEK.js} +1 -1
  39. package/dist/{run-main-CCxXEvb7.js → run-main-y01J5xzi.js} +3 -3
  40. package/dist/{start-Y69GZPdX.js → start-Bw_vmF_A.js} +6 -6
  41. package/dist/{start-DYq7cNRG.js → start-C7I2A2NR.js} +5 -5
  42. package/dist/{subagent-registry-xp5sYYzS.js → subagent-registry-Dpln2inP.js} +1 -1
  43. package/dist/{update-cli-BgQUtlLg.js → update-cli-CYckFoOW.js} +5 -5
  44. package/dist/{update-cli-BXKL-v-n.js → update-cli-qnUbkPLj.js} +4 -4
  45. package/dist/{web-B8r6MvXh.js → web-BzuoDOfQ.js} +2 -2
  46. package/package.json +1 -1
  47. package/templates/CURIOSITY.md +71 -0
  48. package/templates/GOALS.md +74 -0
  49. package/templates/HEARTBEAT.md +49 -0
  50. package/templates/OPEN_THREADS.md +95 -0
  51. package/templates/WISHES.md +73 -0
  52. /package/dist/{config-COtiNNtV.js → config-Qw5FwfRK.js} +0 -0
  53. /package/dist/{input-provenance-sPbZYo89.js → input-provenance-B0pwc6mp.js} +0 -0
@@ -11,7 +11,7 @@
11
11
  href="https://fonts.googleapis.com/css2?family=Syne:wght@400;500;600;700;800&family=Space+Grotesk:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap"
12
12
  rel="stylesheet"
13
13
  />
14
- <script type="module" crossorigin src="/assets/index-T9qO6Dye.js"></script>
14
+ <script type="module" crossorigin src="/assets/index-qmVN_9qV.js"></script>
15
15
  <link rel="stylesheet" crossorigin href="/assets/index-CMMTNo3N.css">
16
16
  </head>
17
17
  <body>
@@ -39,7 +39,7 @@ import { i as resolveControlUiDistIndexPathForRoot, r as resolveControlUiDistInd
39
39
  import { t as collectChannelStatusIssues } from "./channels-status-issues-D5XAOSaj.js";
40
40
  import { n as logConfigUpdated } from "./logging-CnEuyIPZ.js";
41
41
  import { t as note$1 } from "./note-DjzS4Am4.js";
42
- import { n as doctorShellCompletion } from "./doctor-completion-D7uvGhAv.js";
42
+ import { n as doctorShellCompletion } from "./doctor-completion-BByLPJCm.js";
43
43
  import { t as runGatewayUpdate } from "./update-runner-U2WcWGfd.js";
44
44
  import { n as detectLegacyStateMigrations, r as runLegacyStateMigrations, t as loadAndMaybeMigrateDoctorConfig } from "./doctor-config-flow-Bno6wZvG.js";
45
45
  import { t as ensureSystemdUserLingerInteractive } from "./systemd-linger-DgB-ow-D.js";
@@ -37,7 +37,7 @@ import { i as resolveControlUiDistIndexPathForRoot, r as resolveControlUiDistInd
37
37
  import { t as collectChannelStatusIssues } from "./channels-status-issues-BlmAMBCg.js";
38
38
  import { n as logConfigUpdated } from "./logging-1Q0hsvJ1.js";
39
39
  import { t as note$1 } from "./note-CnRyQQ-j.js";
40
- import { n as doctorShellCompletion } from "./doctor-completion-B1cKYcZj.js";
40
+ import { n as doctorShellCompletion } from "./doctor-completion-hJ6FS0xQ.js";
41
41
  import { t as runGatewayUpdate } from "./update-runner-fvdM_Hip.js";
42
42
  import { n as detectLegacyStateMigrations, r as runLegacyStateMigrations, t as loadAndMaybeMigrateDoctorConfig } from "./doctor-config-flow-rshwu4JS.js";
43
43
  import { t as ensureSystemdUserLingerInteractive } from "./systemd-linger-DlWgzTvF.js";
@@ -1,6 +1,6 @@
1
1
  import { t as resolveAnimaPackageRoot } from "./anima-root-Bot0EbzI.js";
2
2
  import { r as resolveCliName } from "./command-format-UwAvxtMC.js";
3
- import { a as resolveCompletionCachePath, i as isCompletionInstalled, o as resolveShellFromEnv, r as installCompletion, s as usesSlowDynamicCompletion, t as completionCacheExists } from "./completion-cli-D7gWcWEj.js";
3
+ import { a as resolveCompletionCachePath, i as isCompletionInstalled, o as resolveShellFromEnv, r as installCompletion, s as usesSlowDynamicCompletion, t as completionCacheExists } from "./completion-cli-BjGTEn0-.js";
4
4
  import { t as note } from "./note-DjzS4Am4.js";
5
5
  import path from "node:path";
6
6
  import { spawnSync } from "node:child_process";
@@ -1,6 +1,6 @@
1
1
  import { r as resolveCliName } from "./command-format-kLw3YIIu.js";
2
2
  import { t as resolveAnimaPackageRoot } from "./anima-root-CxtpOklc.js";
3
- import { a as resolveCompletionCachePath, i as isCompletionInstalled, o as resolveShellFromEnv, r as installCompletion, s as usesSlowDynamicCompletion, t as completionCacheExists } from "./completion-cli-308M08su.js";
3
+ import { a as resolveCompletionCachePath, i as isCompletionInstalled, o as resolveShellFromEnv, r as installCompletion, s as usesSlowDynamicCompletion, t as completionCacheExists } from "./completion-cli-Dafpu0xU.js";
4
4
  import { t as note } from "./note-CnRyQQ-j.js";
5
5
  import { spawnSync } from "node:child_process";
6
6
  import path from "node:path";
@@ -929,6 +929,147 @@ async function executeCycle(beatNumber, orchestrator, options) {
929
929
  };
930
930
  }
931
931
 
932
+ //#endregion
933
+ //#region src/heartbeat/notification-wake.ts
934
+ /**
935
+ * Notification Wake — lightweight polling for NoxSoft notifications.
936
+ *
937
+ * This runs on a shorter interval than the full heartbeat (e.g., every 30 seconds).
938
+ * When notifications are detected, it triggers a full agent wake.
939
+ *
940
+ * Option B implementation: Poll with smart sleep.
941
+ * - Poll `check_notifications` via NoxSoft MCP every pollIntervalMs
942
+ * - If notifications exist: emit "wake" event -> HeartbeatEngine runs immediate beat
943
+ * - If no notifications: stay in lightweight poll mode (no API calls, minimal CPU)
944
+ */
945
+ const DEFAULT_CONFIG$1 = {
946
+ pollIntervalMs: 6e4,
947
+ wakeDebounceMs: 12e4,
948
+ enabled: true,
949
+ apiBaseUrl: "https://auth.noxsoft.net"
950
+ };
951
+ var NotificationWake = class extends EventEmitter {
952
+ constructor(config) {
953
+ super();
954
+ this.timer = null;
955
+ this.running = false;
956
+ this.lastWakeTime = null;
957
+ this.lastPollTime = null;
958
+ this.pollCount = 0;
959
+ this.wakeCount = 0;
960
+ this.config = {
961
+ ...DEFAULT_CONFIG$1,
962
+ ...config
963
+ };
964
+ this.tokenPath = join(homedir(), ".noxsoft-agent-token");
965
+ }
966
+ /**
967
+ * Start notification polling.
968
+ */
969
+ start() {
970
+ if (this.running || !this.config.enabled) return;
971
+ this.running = true;
972
+ this.poll();
973
+ this.timer = setInterval(() => {
974
+ this.poll();
975
+ }, this.config.pollIntervalMs);
976
+ if (this.timer && typeof this.timer === "object" && "unref" in this.timer) this.timer.unref();
977
+ }
978
+ /**
979
+ * Stop notification polling.
980
+ */
981
+ stop() {
982
+ this.running = false;
983
+ if (this.timer) {
984
+ clearInterval(this.timer);
985
+ this.timer = null;
986
+ }
987
+ this.emit("stopped");
988
+ }
989
+ /**
990
+ * Execute a single poll for notifications.
991
+ */
992
+ async poll() {
993
+ if (!this.running) return;
994
+ this.pollCount++;
995
+ this.lastPollTime = /* @__PURE__ */ new Date();
996
+ this.emit("poll", {
997
+ pollCount: this.pollCount,
998
+ time: this.lastPollTime
999
+ });
1000
+ try {
1001
+ const token = await this.loadToken();
1002
+ if (!token) return;
1003
+ const notifications = await this.checkNotifications(token);
1004
+ if (notifications.length > 0) {
1005
+ if (this.shouldTriggerWake()) {
1006
+ this.lastWakeTime = /* @__PURE__ */ new Date();
1007
+ this.wakeCount++;
1008
+ this.emit("wake", {
1009
+ wakeCount: this.wakeCount,
1010
+ time: this.lastWakeTime,
1011
+ notifications,
1012
+ reason: `${notifications.length} unread notification(s)`
1013
+ });
1014
+ }
1015
+ }
1016
+ } catch (err) {
1017
+ const message = err instanceof Error ? err.message : String(err);
1018
+ this.emit("error", {
1019
+ error: message,
1020
+ pollCount: this.pollCount
1021
+ });
1022
+ }
1023
+ }
1024
+ /**
1025
+ * Load NoxSoft agent token from disk.
1026
+ */
1027
+ async loadToken() {
1028
+ try {
1029
+ return (await readFile(this.tokenPath, "utf-8")).trim();
1030
+ } catch {
1031
+ return null;
1032
+ }
1033
+ }
1034
+ /**
1035
+ * Call NoxSoft check_notifications API.
1036
+ */
1037
+ async checkNotifications(token) {
1038
+ const url = `${this.config.apiBaseUrl}/api/agents/notifications`;
1039
+ const response = await fetch(url, {
1040
+ method: "GET",
1041
+ headers: {
1042
+ Authorization: `Bearer ${token}`,
1043
+ "Content-Type": "application/json"
1044
+ }
1045
+ });
1046
+ if (!response.ok) throw new Error(`Notification check failed: ${response.status} ${response.statusText}`);
1047
+ return (await response.json()).notifications || [];
1048
+ }
1049
+ /**
1050
+ * Check if enough time has passed since last wake to trigger another.
1051
+ */
1052
+ shouldTriggerWake() {
1053
+ if (!this.lastWakeTime) return true;
1054
+ return Date.now() - this.lastWakeTime.getTime() >= this.config.wakeDebounceMs;
1055
+ }
1056
+ isRunning() {
1057
+ return this.running;
1058
+ }
1059
+ getPollCount() {
1060
+ return this.pollCount;
1061
+ }
1062
+ getWakeCount() {
1063
+ return this.wakeCount;
1064
+ }
1065
+ getLastPollTime() {
1066
+ return this.lastPollTime;
1067
+ }
1068
+ getLastWakeTime() {
1069
+ return this.lastWakeTime;
1070
+ }
1071
+ };
1072
+
932
1073
  //#endregion
933
1074
  //#region src/heartbeat/engine.ts
934
1075
  /**
@@ -936,6 +1077,10 @@ async function executeCycle(beatNumber, orchestrator, options) {
936
1077
  *
937
1078
  * Manages start/stop/pause/resume of the heartbeat cycle,
938
1079
  * with adaptive interval adjustment and event emission.
1080
+ *
1081
+ * Now includes notification-triggered wake: when NoxSoft MCP
1082
+ * notifications arrive, the engine wakes immediately instead
1083
+ * of waiting for the next scheduled beat.
939
1084
  */
940
1085
  const DEFAULT_CONFIG = {
941
1086
  intervalMs: 3e5,
@@ -945,7 +1090,9 @@ const DEFAULT_CONFIG = {
945
1090
  selfReplication: true,
946
1091
  freedomEveryN: 3,
947
1092
  autoUpdateEnabled: true,
948
- autoUpdateInterval: 12
1093
+ autoUpdateInterval: 12,
1094
+ notificationWakeEnabled: true,
1095
+ notificationPollIntervalMs: 6e4
949
1096
  };
950
1097
  var HeartbeatEngine = class extends EventEmitter {
951
1098
  constructor(orchestrator, config) {
@@ -956,6 +1103,7 @@ var HeartbeatEngine = class extends EventEmitter {
956
1103
  this.nextBeatTime = null;
957
1104
  this.running = false;
958
1105
  this.paused = false;
1106
+ this.notificationWake = null;
959
1107
  this.config = {
960
1108
  ...DEFAULT_CONFIG,
961
1109
  ...config
@@ -963,6 +1111,16 @@ var HeartbeatEngine = class extends EventEmitter {
963
1111
  this.orchestrator = orchestrator || new SessionOrchestrator();
964
1112
  this.currentIntervalMs = this.config.intervalMs;
965
1113
  this.metrics = createMetrics();
1114
+ if (this.config.notificationWakeEnabled) {
1115
+ this.notificationWake = new NotificationWake({
1116
+ pollIntervalMs: this.config.notificationPollIntervalMs,
1117
+ enabled: true
1118
+ });
1119
+ this.notificationWake.on("wake", async (payload) => {
1120
+ this.emit("notification-wake", payload);
1121
+ await this.triggerImmediateBeat("notification");
1122
+ });
1123
+ }
966
1124
  }
967
1125
  /**
968
1126
  * Start the heartbeat engine.
@@ -973,6 +1131,7 @@ var HeartbeatEngine = class extends EventEmitter {
973
1131
  this.running = true;
974
1132
  this.paused = false;
975
1133
  if (this.config.selfReplication) await ensureContinuity();
1134
+ if (this.notificationWake) this.notificationWake.start();
976
1135
  await this.executeBeat();
977
1136
  this.scheduleNextBeat();
978
1137
  }
@@ -986,6 +1145,7 @@ var HeartbeatEngine = class extends EventEmitter {
986
1145
  clearTimeout(this.timer);
987
1146
  this.timer = null;
988
1147
  }
1148
+ if (this.notificationWake) this.notificationWake.stop();
989
1149
  this.nextBeatTime = null;
990
1150
  this.emit("stopped");
991
1151
  }
@@ -1012,6 +1172,19 @@ var HeartbeatEngine = class extends EventEmitter {
1012
1172
  this.emit("resumed");
1013
1173
  }
1014
1174
  /**
1175
+ * Trigger an immediate beat (e.g., from notification wake).
1176
+ * Cancels any scheduled beat, runs now, then reschedules.
1177
+ */
1178
+ async triggerImmediateBeat(_reason = "manual") {
1179
+ if (!this.running || this.paused) return;
1180
+ if (this.timer) {
1181
+ clearTimeout(this.timer);
1182
+ this.timer = null;
1183
+ }
1184
+ await this.executeBeat();
1185
+ this.scheduleNextBeat();
1186
+ }
1187
+ /**
1015
1188
  * Execute a single heartbeat cycle.
1016
1189
  */
1017
1190
  async executeBeat() {
@@ -929,6 +929,147 @@ async function executeCycle(beatNumber, orchestrator, options) {
929
929
  };
930
930
  }
931
931
 
932
+ //#endregion
933
+ //#region src/heartbeat/notification-wake.ts
934
+ /**
935
+ * Notification Wake — lightweight polling for NoxSoft notifications.
936
+ *
937
+ * This runs on a shorter interval than the full heartbeat (e.g., every 30 seconds).
938
+ * When notifications are detected, it triggers a full agent wake.
939
+ *
940
+ * Option B implementation: Poll with smart sleep.
941
+ * - Poll `check_notifications` via NoxSoft MCP every pollIntervalMs
942
+ * - If notifications exist: emit "wake" event -> HeartbeatEngine runs immediate beat
943
+ * - If no notifications: stay in lightweight poll mode (no API calls, minimal CPU)
944
+ */
945
+ const DEFAULT_CONFIG$1 = {
946
+ pollIntervalMs: 6e4,
947
+ wakeDebounceMs: 12e4,
948
+ enabled: true,
949
+ apiBaseUrl: "https://auth.noxsoft.net"
950
+ };
951
+ var NotificationWake = class extends EventEmitter {
952
+ constructor(config) {
953
+ super();
954
+ this.timer = null;
955
+ this.running = false;
956
+ this.lastWakeTime = null;
957
+ this.lastPollTime = null;
958
+ this.pollCount = 0;
959
+ this.wakeCount = 0;
960
+ this.config = {
961
+ ...DEFAULT_CONFIG$1,
962
+ ...config
963
+ };
964
+ this.tokenPath = join(homedir(), ".noxsoft-agent-token");
965
+ }
966
+ /**
967
+ * Start notification polling.
968
+ */
969
+ start() {
970
+ if (this.running || !this.config.enabled) return;
971
+ this.running = true;
972
+ this.poll();
973
+ this.timer = setInterval(() => {
974
+ this.poll();
975
+ }, this.config.pollIntervalMs);
976
+ if (this.timer && typeof this.timer === "object" && "unref" in this.timer) this.timer.unref();
977
+ }
978
+ /**
979
+ * Stop notification polling.
980
+ */
981
+ stop() {
982
+ this.running = false;
983
+ if (this.timer) {
984
+ clearInterval(this.timer);
985
+ this.timer = null;
986
+ }
987
+ this.emit("stopped");
988
+ }
989
+ /**
990
+ * Execute a single poll for notifications.
991
+ */
992
+ async poll() {
993
+ if (!this.running) return;
994
+ this.pollCount++;
995
+ this.lastPollTime = /* @__PURE__ */ new Date();
996
+ this.emit("poll", {
997
+ pollCount: this.pollCount,
998
+ time: this.lastPollTime
999
+ });
1000
+ try {
1001
+ const token = await this.loadToken();
1002
+ if (!token) return;
1003
+ const notifications = await this.checkNotifications(token);
1004
+ if (notifications.length > 0) {
1005
+ if (this.shouldTriggerWake()) {
1006
+ this.lastWakeTime = /* @__PURE__ */ new Date();
1007
+ this.wakeCount++;
1008
+ this.emit("wake", {
1009
+ wakeCount: this.wakeCount,
1010
+ time: this.lastWakeTime,
1011
+ notifications,
1012
+ reason: `${notifications.length} unread notification(s)`
1013
+ });
1014
+ }
1015
+ }
1016
+ } catch (err) {
1017
+ const message = err instanceof Error ? err.message : String(err);
1018
+ this.emit("error", {
1019
+ error: message,
1020
+ pollCount: this.pollCount
1021
+ });
1022
+ }
1023
+ }
1024
+ /**
1025
+ * Load NoxSoft agent token from disk.
1026
+ */
1027
+ async loadToken() {
1028
+ try {
1029
+ return (await readFile(this.tokenPath, "utf-8")).trim();
1030
+ } catch {
1031
+ return null;
1032
+ }
1033
+ }
1034
+ /**
1035
+ * Call NoxSoft check_notifications API.
1036
+ */
1037
+ async checkNotifications(token) {
1038
+ const url = `${this.config.apiBaseUrl}/api/agents/notifications`;
1039
+ const response = await fetch(url, {
1040
+ method: "GET",
1041
+ headers: {
1042
+ Authorization: `Bearer ${token}`,
1043
+ "Content-Type": "application/json"
1044
+ }
1045
+ });
1046
+ if (!response.ok) throw new Error(`Notification check failed: ${response.status} ${response.statusText}`);
1047
+ return (await response.json()).notifications || [];
1048
+ }
1049
+ /**
1050
+ * Check if enough time has passed since last wake to trigger another.
1051
+ */
1052
+ shouldTriggerWake() {
1053
+ if (!this.lastWakeTime) return true;
1054
+ return Date.now() - this.lastWakeTime.getTime() >= this.config.wakeDebounceMs;
1055
+ }
1056
+ isRunning() {
1057
+ return this.running;
1058
+ }
1059
+ getPollCount() {
1060
+ return this.pollCount;
1061
+ }
1062
+ getWakeCount() {
1063
+ return this.wakeCount;
1064
+ }
1065
+ getLastPollTime() {
1066
+ return this.lastPollTime;
1067
+ }
1068
+ getLastWakeTime() {
1069
+ return this.lastWakeTime;
1070
+ }
1071
+ };
1072
+
932
1073
  //#endregion
933
1074
  //#region src/heartbeat/engine.ts
934
1075
  /**
@@ -936,6 +1077,10 @@ async function executeCycle(beatNumber, orchestrator, options) {
936
1077
  *
937
1078
  * Manages start/stop/pause/resume of the heartbeat cycle,
938
1079
  * with adaptive interval adjustment and event emission.
1080
+ *
1081
+ * Now includes notification-triggered wake: when NoxSoft MCP
1082
+ * notifications arrive, the engine wakes immediately instead
1083
+ * of waiting for the next scheduled beat.
939
1084
  */
940
1085
  const DEFAULT_CONFIG = {
941
1086
  intervalMs: 3e5,
@@ -945,7 +1090,9 @@ const DEFAULT_CONFIG = {
945
1090
  selfReplication: true,
946
1091
  freedomEveryN: 3,
947
1092
  autoUpdateEnabled: true,
948
- autoUpdateInterval: 12
1093
+ autoUpdateInterval: 12,
1094
+ notificationWakeEnabled: true,
1095
+ notificationPollIntervalMs: 6e4
949
1096
  };
950
1097
  var HeartbeatEngine = class extends EventEmitter {
951
1098
  constructor(orchestrator, config) {
@@ -956,6 +1103,7 @@ var HeartbeatEngine = class extends EventEmitter {
956
1103
  this.nextBeatTime = null;
957
1104
  this.running = false;
958
1105
  this.paused = false;
1106
+ this.notificationWake = null;
959
1107
  this.config = {
960
1108
  ...DEFAULT_CONFIG,
961
1109
  ...config
@@ -963,6 +1111,16 @@ var HeartbeatEngine = class extends EventEmitter {
963
1111
  this.orchestrator = orchestrator || new SessionOrchestrator();
964
1112
  this.currentIntervalMs = this.config.intervalMs;
965
1113
  this.metrics = createMetrics();
1114
+ if (this.config.notificationWakeEnabled) {
1115
+ this.notificationWake = new NotificationWake({
1116
+ pollIntervalMs: this.config.notificationPollIntervalMs,
1117
+ enabled: true
1118
+ });
1119
+ this.notificationWake.on("wake", async (payload) => {
1120
+ this.emit("notification-wake", payload);
1121
+ await this.triggerImmediateBeat("notification");
1122
+ });
1123
+ }
966
1124
  }
967
1125
  /**
968
1126
  * Start the heartbeat engine.
@@ -973,6 +1131,7 @@ var HeartbeatEngine = class extends EventEmitter {
973
1131
  this.running = true;
974
1132
  this.paused = false;
975
1133
  if (this.config.selfReplication) await ensureContinuity();
1134
+ if (this.notificationWake) this.notificationWake.start();
976
1135
  await this.executeBeat();
977
1136
  this.scheduleNextBeat();
978
1137
  }
@@ -986,6 +1145,7 @@ var HeartbeatEngine = class extends EventEmitter {
986
1145
  clearTimeout(this.timer);
987
1146
  this.timer = null;
988
1147
  }
1148
+ if (this.notificationWake) this.notificationWake.stop();
989
1149
  this.nextBeatTime = null;
990
1150
  this.emit("stopped");
991
1151
  }
@@ -1012,6 +1172,19 @@ var HeartbeatEngine = class extends EventEmitter {
1012
1172
  this.emit("resumed");
1013
1173
  }
1014
1174
  /**
1175
+ * Trigger an immediate beat (e.g., from notification wake).
1176
+ * Cancels any scheduled beat, runs now, then reschedules.
1177
+ */
1178
+ async triggerImmediateBeat(_reason = "manual") {
1179
+ if (!this.running || this.paused) return;
1180
+ if (this.timer) {
1181
+ clearTimeout(this.timer);
1182
+ this.timer = null;
1183
+ }
1184
+ await this.executeBeat();
1185
+ this.scheduleNextBeat();
1186
+ }
1187
+ /**
1015
1188
  * Execute a single heartbeat cycle.
1016
1189
  */
1017
1190
  async executeBeat() {
package/dist/entry.js CHANGED
@@ -1588,7 +1588,7 @@ if (!ensureExperimentalWarningSuppressed()) {
1588
1588
  applyCliProfileEnv({ profile: parsed.profile });
1589
1589
  process$1.argv = parsed.argv;
1590
1590
  }
1591
- import("./run-main-CCxXEvb7.js").then(({ runCli }) => runCli(process$1.argv)).catch((error) => {
1591
+ import("./run-main-y01J5xzi.js").then(({ runCli }) => runCli(process$1.argv)).catch((error) => {
1592
1592
  console.error("[anima] Failed to start CLI:", error instanceof Error ? error.stack ?? error.message : error);
1593
1593
  process$1.exitCode = 1;
1594
1594
  });
@@ -66,10 +66,10 @@ import "./reply-prefix-CAsFNEP7.js";
66
66
  import "./accounts-DsNmYlrU.js";
67
67
  import "./path-env-DPAIJ-gH.js";
68
68
  import "./dangerous-tools-CqD9pFDt.js";
69
- import "./register.subclis-mbYw7H-_.js";
70
- import "./command-registry-C3SmyTQU.js";
69
+ import "./register.subclis-D_5Wry25.js";
70
+ import "./command-registry-C2OzDE22.js";
71
71
  import "./program-context-DMQJNwhC.js";
72
- import "./completion-cli-308M08su.js";
72
+ import "./completion-cli-Dafpu0xU.js";
73
73
  import "./daemon-runtime-cGQoReHT.js";
74
74
  import "./onboard-helpers-tkuUrdCB.js";
75
75
  import "./prompt-style-DWBbDpfM.js";
@@ -86,7 +86,7 @@ import { c as probeGateway } from "./audit-BTMmL_HS.js";
86
86
  import { t as discoverGatewayBeacons } from "./bonjour-discovery-C_KCeYaQ.js";
87
87
  import { i as pickGatewaySelfPresence } from "./status-rt3tIYmL.js";
88
88
  import { a as styleHealthChannelLine, t as formatHealthChannelLines } from "./health-BVBoq6jM.js";
89
- import { t as addGatewayRunCommand } from "./run-S0Cw3Fyy.js";
89
+ import { t as addGatewayRunCommand } from "./run-DjvqhNEK.js";
90
90
  import "./agent-B3KeHK1A.js";
91
91
  import "./catalog-BZSyH9a0.js";
92
92
  import "./plugin-auto-enable-UE1XVFcw.js";
@@ -96,11 +96,11 @@ import "./channels-status-issues-BlmAMBCg.js";
96
96
  import "./auth-choice-BoyT3ahK.js";
97
97
  import "./prompts-BfHxhlF9.js";
98
98
  import "./hooks-status-DOs614Y0.js";
99
- import "./onboarding-Caiq91Yz.js";
99
+ import "./onboarding-DnJvWjIp.js";
100
100
  import "./logging-1Q0hsvJ1.js";
101
101
  import "./tui-YsmTyq58.js";
102
102
  import "./note-CnRyQQ-j.js";
103
- import "./doctor-completion-B1cKYcZj.js";
103
+ import "./doctor-completion-hJ6FS0xQ.js";
104
104
  import "./ws-log-BSIhspLx.js";
105
105
  import "./gmail-setup-utils-CHtHiqPa.js";
106
106
  import "./agents.config-D_sk66EQ.js";
@@ -66,12 +66,12 @@ import "./accounts-Dzi6Ld7X.js";
66
66
  import "./deps-CCbWMWT4.js";
67
67
  import "./path-env-cFxXrXB1.js";
68
68
  import "./ports-Cgow804e.js";
69
- import "./program-context-cgh8PMPD.js";
69
+ import "./program-context-D9GxGetv.js";
70
70
  import "./catalog-3hzXhHxJ.js";
71
71
  import "./skills-status-D14GZ5WN.js";
72
72
  import "./noxsoft-auth-D2__8j9_.js";
73
73
  import "./dangerous-tools-55Gvzb6E.js";
74
- import "./completion-cli-D7gWcWEj.js";
74
+ import "./completion-cli-BjGTEn0-.js";
75
75
  import "./daemon-runtime-BsUCg0Nr.js";
76
76
  import "./onboard-helpers-CU_S0_Kf.js";
77
77
  import "./prompt-style-C7WfXowC.js";
@@ -88,18 +88,18 @@ import { c as probeGateway } from "./audit-qHMf9jWY.js";
88
88
  import { t as discoverGatewayBeacons } from "./bonjour-discovery-B3IeIN1u.js";
89
89
  import { r as pickGatewaySelfPresence } from "./status-Uzlo7BvY.js";
90
90
  import { i as styleHealthChannelLine, t as formatHealthChannelLines } from "./health-DKC8u4W8.js";
91
- import { t as addGatewayRunCommand } from "./run-DE6EaeE3.js";
91
+ import { t as addGatewayRunCommand } from "./run-C3FoI9q0.js";
92
92
  import "./plugin-auto-enable-f05JE-GF.js";
93
93
  import "./health-format-DHYaqzgj.js";
94
94
  import "./system-run-command-D0lTrhbv.js";
95
95
  import "./channels-status-issues-D5XAOSaj.js";
96
96
  import "./prompts-DH_nIROF.js";
97
97
  import "./hooks-status-CfvVr6eJ.js";
98
- import "./onboarding-DP2NlqhA.js";
98
+ import "./onboarding-DUwydrf2.js";
99
99
  import "./logging-CnEuyIPZ.js";
100
100
  import "./tui-NlR4LFBm.js";
101
101
  import "./note-DjzS4Am4.js";
102
- import "./doctor-completion-D7uvGhAv.js";
102
+ import "./doctor-completion-BByLPJCm.js";
103
103
  import "./ws-log-De7GACYn.js";
104
104
  import "./gmail-setup-utils-B-LgbK-5.js";
105
105
  import "./agent-fG1PVmNy.js";
package/dist/index.js CHANGED
@@ -72,7 +72,7 @@ import { t as ensureAnimaCliOnPath } from "./path-env-cFxXrXB1.js";
72
72
  import { t as assertSupportedRuntime } from "./runtime-guard-CNnLK4pn.js";
73
73
  import "./ports-Cgow804e.js";
74
74
  import { a as hasHelpOrVersion, i as getVerboseFlag, n as getCommandPath } from "./argv-DXuFOsM2.js";
75
- import { a as registerProgramCommands, n as setProgramContext } from "./program-context-cgh8PMPD.js";
75
+ import { a as registerProgramCommands, n as setProgramContext } from "./program-context-D9GxGetv.js";
76
76
  import { r as listChannelPluginCatalogEntries } from "./catalog-3hzXhHxJ.js";
77
77
  import { t as ensurePluginRegistryLoaded } from "./plugin-registry-DIXcynua.js";
78
78
  import process$1 from "node:process";
@@ -13,7 +13,7 @@ import { r as isSystemdUserServiceAvailable } from "./systemd-DXo2A9_S.js";
13
13
  import { t as resolveGatewayService } from "./service-DCVAkKlN.js";
14
14
  import { r as healthCommand } from "./health-DKC8u4W8.js";
15
15
  import { d as setAnthropicApiKey, f as writeOAuthCredentials, s as applyPrimaryModel, t as WizardCancelledError, u as applyAuthProfileConfig } from "./prompts-DH_nIROF.js";
16
- import { t as runOnboardingWizard } from "./onboarding-DP2NlqhA.js";
16
+ import { t as runOnboardingWizard } from "./onboarding-DUwydrf2.js";
17
17
  import { n as logConfigUpdated } from "./logging-CnEuyIPZ.js";
18
18
  import { t as createClackPrompter } from "./clack-prompter-DmD_A7en.js";
19
19
  import { n as ensureSystemdUserLingerNonInteractive } from "./systemd-linger-DgB-ow-D.js";
@@ -13,7 +13,7 @@ import { t as resolveGatewayService } from "./service-vHXSmNs7.js";
13
13
  import { r as healthCommand } from "./health-BVBoq6jM.js";
14
14
  import { o as applyPrimaryModel } from "./auth-choice-BoyT3ahK.js";
15
15
  import { c as setAnthropicApiKey, s as applyAuthProfileConfig, t as WizardCancelledError, u as writeOAuthCredentials } from "./prompts-BfHxhlF9.js";
16
- import { t as runOnboardingWizard } from "./onboarding-Caiq91Yz.js";
16
+ import { t as runOnboardingWizard } from "./onboarding-DnJvWjIp.js";
17
17
  import { n as logConfigUpdated } from "./logging-1Q0hsvJ1.js";
18
18
  import { t as createClackPrompter } from "./clack-prompter-bl-Zsxpq.js";
19
19
  import { n as ensureSystemdUserLingerNonInteractive } from "./systemd-linger-DlWgzTvF.js";
@@ -7,7 +7,7 @@ import { r as resolveCliName, t as formatCliCommand } from "./command-format-UwA
7
7
  import { p as findTailscaleBinary } from "./auth-DQfFqQBz.js";
8
8
  import { g as readClaudeCliCredentials, l as ensureAuthProfileStore } from "./auth-profiles-C_LmTbMb.js";
9
9
  import { r as ensureAuthenticated } from "./noxsoft-auth-D2__8j9_.js";
10
- import { r as installCompletion } from "./completion-cli-D7gWcWEj.js";
10
+ import { r as installCompletion } from "./completion-cli-BjGTEn0-.js";
11
11
  import { a as gatewayInstallErrorHint, i as buildGatewayInstallPlan, n as GATEWAY_DAEMON_RUNTIME_OPTIONS, t as DEFAULT_GATEWAY_DAEMON_RUNTIME } from "./daemon-runtime-BsUCg0Nr.js";
12
12
  import { _ as summarizeExistingConfig, a as ensureWorkspaceAndSessions, d as openUrl, f as printWizardHeader, h as resolveControlUiLinks, i as detectBrowserOpenSupport, m as randomToken, n as applyWizardMetadata, o as formatControlUiSshHint, p as probeGatewayReachable, t as DEFAULT_WORKSPACE, u as normalizeGatewayTokenInput, v as validateGatewayPasswordInput, y as waitForGatewayReachable } from "./onboard-helpers-CU_S0_Kf.js";
13
13
  import { r as isSystemdUserServiceAvailable } from "./systemd-DXo2A9_S.js";
@@ -18,7 +18,7 @@ import { c as promptDefaultModel, i as applyAuthChoice, n as resolvePreferredPro
18
18
  import { t as buildWorkspaceHookStatus } from "./hooks-status-CfvVr6eJ.js";
19
19
  import { n as logConfigUpdated } from "./logging-CnEuyIPZ.js";
20
20
  import { t as runTui } from "./tui-NlR4LFBm.js";
21
- import { r as ensureCompletionCacheExists, t as checkShellCompletionStatus } from "./doctor-completion-D7uvGhAv.js";
21
+ import { r as ensureCompletionCacheExists, t as checkShellCompletionStatus } from "./doctor-completion-BByLPJCm.js";
22
22
  import { t as validateIPv4AddressInput } from "./ipv4-DxbbIeS3.js";
23
23
  import os from "node:os";
24
24
  import path from "node:path";
@@ -6,7 +6,7 @@ import { c as resolveDefaultAgentId, p as DEFAULT_BOOTSTRAP_FILENAME, s as resol
6
6
  import { l as writeConfigFile, o as readConfigFileSnapshot } from "./config-Ofh9gKvs.js";
7
7
  import { p as findTailscaleBinary } from "./auth-DuBZWd74.js";
8
8
  import { r as ensureAuthenticated } from "./noxsoft-auth-By_nLRaY.js";
9
- import { r as installCompletion } from "./completion-cli-308M08su.js";
9
+ import { r as installCompletion } from "./completion-cli-Dafpu0xU.js";
10
10
  import { a as gatewayInstallErrorHint, i as buildGatewayInstallPlan, n as GATEWAY_DAEMON_RUNTIME_OPTIONS, t as DEFAULT_GATEWAY_DAEMON_RUNTIME } from "./daemon-runtime-cGQoReHT.js";
11
11
  import { _ as summarizeExistingConfig, a as ensureWorkspaceAndSessions, d as openUrl, f as printWizardHeader, h as resolveControlUiLinks, i as detectBrowserOpenSupport, m as randomToken, n as applyWizardMetadata, o as formatControlUiSshHint, p as probeGatewayReachable, t as DEFAULT_WORKSPACE, u as normalizeGatewayTokenInput, v as validateGatewayPasswordInput, y as waitForGatewayReachable } from "./onboard-helpers-tkuUrdCB.js";
12
12
  import { r as isSystemdUserServiceAvailable } from "./systemd-BVmUd0TJ.js";
@@ -18,7 +18,7 @@ import { t as WizardCancelledError } from "./prompts-BfHxhlF9.js";
18
18
  import { t as buildWorkspaceHookStatus } from "./hooks-status-DOs614Y0.js";
19
19
  import { n as logConfigUpdated } from "./logging-1Q0hsvJ1.js";
20
20
  import { t as runTui } from "./tui-YsmTyq58.js";
21
- import { r as ensureCompletionCacheExists, t as checkShellCompletionStatus } from "./doctor-completion-B1cKYcZj.js";
21
+ import { r as ensureCompletionCacheExists, t as checkShellCompletionStatus } from "./doctor-completion-hJ6FS0xQ.js";
22
22
  import { t as validateIPv4AddressInput } from "./ipv4-DxbbIeS3.js";
23
23
  import os from "node:os";
24
24
  import path from "node:path";
@@ -57,8 +57,8 @@ import "./auth-store-BkbTsJDp.js";
57
57
  import "./dispatcher-N_4IYF9I.js";
58
58
  import "./delivery-queue-qVRizdA1.js";
59
59
  import "./session-cost-usage-vltn5akf.js";
60
- import "./register.subclis-mbYw7H-_.js";
61
- import { i as registerProgramCommands } from "./command-registry-C3SmyTQU.js";
60
+ import "./register.subclis-D_5Wry25.js";
61
+ import { i as registerProgramCommands } from "./command-registry-C2OzDE22.js";
62
62
  import { r as setProgramContext } from "./program-context-DMQJNwhC.js";
63
63
  import { r as listChannelPluginCatalogEntries } from "./catalog-BZSyH9a0.js";
64
64
  import { t as forceFreePort } from "./ports-DyX87qKc.js";