akm-cli 0.9.19 → 0.9.20

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.md CHANGED
@@ -6,6 +6,22 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.9.20] - 2026-09-30
10
+
11
+ ### Fixed
12
+
13
+ - **A command killed by SIGTERM or SIGINT no longer leaves the `opencode serve` it
14
+ started running (#1005).** The SDK runner closes the servers it caches when a
15
+ command finishes, with a `process.once("exit")` hook as the backstop. A command
16
+ with no signal handler of its own dies on the signal without running `exit` hooks,
17
+ so a plain `kill <pid>` (or a supervisor's or scheduler's timeout) left the server
18
+ running, reparented to init, until someone killed it; `akm agent --prompt`
19
+ reproduced it. The runner now closes its servers on SIGINT and SIGTERM when the
20
+ command has no listener of its own, then re-raises the signal, so the command
21
+ still ends by it with the same status. The handlers go up before the first server
22
+ is spawned, so one that is still starting is covered too. `workflow run`,
23
+ `improve`, `index` and shell/script tasks keep handling the signals themselves.
24
+
9
25
  ## [0.9.19] - 2026-09-30
10
26
 
11
27
  ### Added
@@ -518,16 +518,30 @@ async function startServer(profile, sdkConfig, env, registryKey, startupSignal)
518
518
  options.port = await allocateFreePort(registryKey);
519
519
  if (startupSignal.aborted)
520
520
  throw new Error("OpenCode server startup cancelled because no callers are waiting");
521
- const server = await factory(options);
522
- if (!server)
523
- throw new Error("Failed to initialise OpenCode SDK server.");
521
+ // Installed before the spawn, so a child that is still starting up is covered too.
524
522
  if (!_exitHookInstalled) {
525
523
  _exitHookInstalled = true;
526
524
  process.once("exit", () => {
527
525
  _processExiting = true;
528
526
  void closeServer();
529
527
  });
528
+ // A command with no SIGINT/SIGTERM handler of its own dies on the signal without running `exit` hooks, which
529
+ // orphaned every cached server. Close them and re-raise, so the default termination still happens. A command that
530
+ // handles the signal itself (`workflow run`, `improve`, `index`, task runs) unwinds through its own cleanup and is
531
+ // left alone.
532
+ for (const signal of ["SIGINT", "SIGTERM"]) {
533
+ if (process.listenerCount(signal) > 0)
534
+ continue;
535
+ process.once(signal, () => {
536
+ _processExiting = true;
537
+ void closeServer();
538
+ process.kill(process.pid, signal);
539
+ });
540
+ }
530
541
  }
542
+ const server = await factory(options);
543
+ if (!server)
544
+ throw new Error("Failed to initialise OpenCode SDK server.");
531
545
  return server;
532
546
  }
533
547
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "akm-cli",
3
- "version": "0.9.19",
3
+ "version": "0.9.20",
4
4
  "type": "module",
5
5
  "description": "akm (Agent Knowledge Manager) — a portable, local-first capability library for AI agents. Discover, load, share, and improve reusable skills, scripts, workflows, and knowledge across any shell-capable coding agent, including Claude Code, OpenCode, and Cursor.",
6
6
  "keywords": [