@agentprojectcontext/apx 1.77.0 → 1.77.1

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": "@agentprojectcontext/apx",
3
- "version": "1.77.0",
3
+ "version": "1.77.1",
4
4
  "description": "APX — unified CLI + daemon for the Agent Project Context (APC) standard.",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -40,7 +40,8 @@
40
40
  "upgrade": "pnpm install && pnpm add -g .",
41
41
  "prepare": "node scripts/install-githooks.js",
42
42
  "prepack": "node scripts/sync-apc-skill.js && node scripts/build-web.js",
43
- "postinstall": "node src/interfaces/cli/postinstall.js"
43
+ "postinstall": "node src/interfaces/cli/postinstall.js",
44
+ "smoke:seam": "node --test --test-reporter=spec tests/smoke/*.smoke.js"
44
45
  },
45
46
  "dependencies": {
46
47
  "@modelcontextprotocol/sdk": "^1.29.0",
@@ -25,6 +25,7 @@ const API_PREFIXES = [
25
25
  "/messages", "/sessions", "/tools", "/mcp", "/voice", "/tts", "/desktop", "/overlay",
26
26
  "/transcribe", "/run", "/files", "/memory", "/env", "/pair", "/deck",
27
27
  "/super-agent", "/identity", "/skills", "/profiles", "/inbox",
28
+ "/tasks", "/agents", "/plugins", "/previews", "/embeddings",
28
29
  ];
29
30
 
30
31
  export function isApiPath(p) {
@@ -126,6 +126,12 @@ export class ProjectManager {
126
126
  name,
127
127
  kind,
128
128
  agents: readAgents(e.path).length,
129
+ // Where this project's runtime state lives. The CLI needs it to reach
130
+ // per-routine memory and anything else stored outside the repo — it has
131
+ // no other way to resolve it, and `apx routine memory` was silently
132
+ // broken for want of these two fields.
133
+ apx_id: e.apxId || null,
134
+ storage_path: e.storagePath || null,
129
135
  };
130
136
  });
131
137
  }
@@ -3,9 +3,13 @@
3
3
  // Must run before any outbound fetch — see the module header for why.
4
4
  import "#core/net/ipv4-first.js";
5
5
  import fs from "node:fs";
6
+ import http from "node:http";
6
7
  import path from "node:path";
7
8
  import { fileURLToPath } from "node:url";
8
9
  import { randomBytes } from "node:crypto";
10
+
11
+ // Loopback is always bound, no matter what `host` is configured to.
12
+ const LOOPBACK_HOST = "127.0.0.1";
9
13
  import {
10
14
  readConfig,
11
15
  writeConfig,
@@ -233,9 +237,29 @@ async function main() {
233
237
  plugins.installRoutes(app);
234
238
 
235
239
  let callbackReconciler = null;
236
- const server = app.listen(port, host, () => {
240
+
241
+ // Loopback is ALWAYS bound, whatever `host` says.
242
+ //
243
+ // Binding a single specific LAN address (what `apx panel share` configures)
244
+ // excludes 127.0.0.1 — and the CLI, the desktop app and /admin/web-token all
245
+ // reach the daemon over loopback. Sharing the panel with the phone must not
246
+ // take the local toolchain down with it, so a non-loopback host means TWO
247
+ // listeners on one app, not a move.
248
+ const extraHosts =
249
+ host && host !== LOOPBACK_HOST && host !== "0.0.0.0" && host !== "::" ? [host] : [];
250
+ const secondary = [];
251
+
252
+ const server = app.listen(port, extraHosts.length ? LOOPBACK_HOST : host, () => {
237
253
  writePid();
238
- log(`apx-daemon ${PKG.version} listening on http://${host}:${port}`);
254
+ for (const h of extraHosts) {
255
+ // A secondary bind failing must never take the daemon down — the local
256
+ // one is already up and is the one everything depends on.
257
+ const s2 = http.createServer(app);
258
+ s2.on("error", (e) => log(`bind ${h}:${port} failed (${e.code || e.message}) — local access unaffected`));
259
+ s2.listen(port, h, () => log(`apx-daemon also listening on http://${h}:${port}`));
260
+ secondary.push(s2);
261
+ }
262
+ log(`apx-daemon ${PKG.version} listening on http://${extraHosts.length ? LOOPBACK_HOST : host}:${port}`);
239
263
  log(`projects: ${projects.list().length} | plugins: ${Object.keys(plugins.status()).join(", ") || "(none)"}`);
240
264
  plugins.startAll();
241
265
  scheduler.start();
@@ -317,6 +341,11 @@ async function main() {
317
341
  import("./whisper-server.js").then(({ shutdownWhisperServer }) => {
318
342
  shutdownWhisperServer().catch(() => {});
319
343
  }).catch(() => {});
344
+ // Close the LAN listener(s) too, or the port stays held after SIGTERM and
345
+ // the next `apx restart` fails with "already running".
346
+ for (const s2 of secondary) {
347
+ try { s2.close(); } catch { /* already down */ }
348
+ }
320
349
  server.close(() => {
321
350
  clearPid();
322
351
  process.exit(0);