ai_co_discuss 0.3.83 → 0.3.85

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai_co_discuss",
3
- "version": "0.3.83",
3
+ "version": "0.3.85",
4
4
  "bin": {
5
5
  "codiscuss": "runner/codiscuss.mjs"
6
6
  },
@@ -9,7 +9,7 @@ import { parseArgs } from 'node:util';
9
9
 
10
10
  import { atomic_json } from './files.mjs';
11
11
  import { acquire_lock } from './discussion_runner.mjs';
12
- import { assert_shared_home, main as service_main, service_home, service_pid, service_ready, start_service } from './discussion_service.mjs';
12
+ import { assert_shared_home, main as service_main, service_home, service_pid, service_ready, service_stopped_by_user, start_service } from './discussion_service.mjs';
13
13
  import { detect_python, local_settings } from './discussion_setup.mjs';
14
14
  import { unlink_machine } from './remote_launch.mjs';
15
15
  import { tone } from './discussion_tui.mjs';
@@ -20,6 +20,8 @@ const VERSION = JSON.parse(readFileSync(new URL('../package.json', import.meta.u
20
20
  const START_WAIT_MS = 15000;
21
21
  const STOP_WAIT_MS = 25000;
22
22
  const POLL_MS = 200;
23
+ // A service that exited without `service stop` (e.g. an old one adopted during an upgrade) is restarted at most this often.
24
+ const SERVICE_REVIVE_MS = 10_000;
23
25
  const CONNECTION_TOKEN_BYTES = 32;
24
26
  const LOCAL_HELP = `用法:codiscuss local open|start|status|stop [--json]
25
27
  codiscuss local connect SITE [--setup-key KEY] [--no-open]
@@ -156,11 +158,17 @@ async function close_owned(child, owned_service, home) {
156
158
  }
157
159
  }
158
160
 
159
- /** Handle explicit restart requests in the supervisor so replacement service ownership stays local. */
161
+ let revived_at = 0;
162
+
163
+ /**
164
+ * Start the service on an explicit request, or again when it exited without `service stop`, so replacement
165
+ * ownership stays local and an adopted service that exits later does not leave every room unattended.
166
+ */
160
167
  async function requested_service(home, status, owned_service) {
161
168
  const path = join(home, 'local', 'start.request');
162
- if (!existsSync(path)) return owned_service;
163
- unlinkSync(path);
169
+ if (existsSync(path)) unlinkSync(path);
170
+ else if (service_pid(home) || service_stopped_by_user(home) || Date.now() - revived_at < SERVICE_REVIVE_MS) return owned_service;
171
+ revived_at = Date.now();
164
172
  const status_path = join(home, 'local', 'status.json');
165
173
  try {
166
174
  const service = await start_service(home);
@@ -32,6 +32,8 @@ const REMOTE_SYNC_MS = 3000;
32
32
  const RELAY_RESTART_MIN_MS = 1000;
33
33
  const START_WAIT_MS = 5000;
34
34
  const STOP_WAIT_MS = 20_000;
35
+ // Left by `service stop` and cleared by any start: the local supervisor restarts a service that exited only without it.
36
+ const STOPPED_MARKER = 'service.stopped';
35
37
  const REGISTRY_WAIT_MS = 5000;
36
38
  // Housekeeping: logs above the limit keep only their newest part; a launch folder no room uses is removed once it is this old.
37
39
  const SWEEP_MS = 6 * 60 * 60 * 1000;
@@ -744,6 +746,7 @@ export async function run_service(home, output = () => {}) {
744
746
  /** Start the detached service once; an already running service is reused. */
745
747
  export async function start_service(home) {
746
748
  assert_shared_home(home);
749
+ rmSync(join(home, STOPPED_MARKER), { force: true });
747
750
  const running = service_pid(home);
748
751
  if (service_ready(home, running)) return { running: true, ready: true, pid: running, started: false };
749
752
  mkdirSync(home, { recursive: true });
@@ -793,6 +796,11 @@ function read_persisted_env() {
793
796
  } catch { return {}; }
794
797
  }
795
798
 
799
+ /** Whether the user stopped the service on purpose, so the local supervisor must not bring it back. */
800
+ export function service_stopped_by_user(home) {
801
+ return existsSync(join(home, STOPPED_MARKER));
802
+ }
803
+
796
804
  /** Ask the service to pause its runs and exit, then wait for its lock to be released. */
797
805
  async function stop_service(home) {
798
806
  if (!service_pid(home)) return { running: false };
@@ -865,7 +873,9 @@ export async function main(args = process.argv.slice(2), print = value => proces
865
873
  switch (command) {
866
874
  case 'run': return run_service(home);
867
875
  case 'start': return print(await start_service(home));
868
- case 'stop': return print(await stop_service(home));
876
+ case 'stop':
877
+ atomic_json(join(home, STOPPED_MARKER), { stopped_at: Math.floor(Date.now() / 1000) });
878
+ return print(await stop_service(home));
869
879
  case 'restart': await stop_service(home); return print(await start_service(home));
870
880
  case 'status': return print(service_status(home));
871
881
  case 'open': return print({ ...(await start_service(home)), opened: open_sites(home) });