svamp-cli 0.2.45 → 0.2.46

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.
@@ -1,8 +1,8 @@
1
1
  import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(import.meta.url);import { randomUUID } from 'node:crypto';
2
2
  import os from 'node:os';
3
- import { join, resolve } from 'node:path';
4
- import { mkdirSync, writeFileSync, existsSync, unlinkSync, readFileSync, watch } from 'node:fs';
5
- import { c as connectToHypha, a as registerSessionService } from './run-D59qJKn_.mjs';
3
+ import { resolve, join } from 'node:path';
4
+ import { existsSync, readFileSync, watch } from 'node:fs';
5
+ import { c as connectToHypha, a as registerSessionService, h as generateHookSettings } from './run-wfhhtkl1.mjs';
6
6
  import { createServer } from 'node:http';
7
7
  import { spawn } from 'node:child_process';
8
8
  import { createInterface } from 'node:readline';
@@ -66,56 +66,6 @@ async function startHookServer(onSessionHook, log) {
66
66
  });
67
67
  }
68
68
 
69
- const SVAMP_HOME$1 = process.env.SVAMP_HOME || join(os.homedir(), ".svamp");
70
- function generateHookSettings(port) {
71
- const hooksDir = join(SVAMP_HOME$1, "tmp", "hooks");
72
- mkdirSync(hooksDir, { recursive: true });
73
- const forwarderPath = join(hooksDir, `forwarder-${process.pid}.cjs`);
74
- const forwarderCode = `#!/usr/bin/env node
75
- const http = require('http');
76
- const port = parseInt(process.argv[2], 10);
77
- if (!port || isNaN(port)) process.exit(1);
78
- const chunks = [];
79
- process.stdin.on('data', c => chunks.push(c));
80
- process.stdin.on('end', () => {
81
- const body = Buffer.concat(chunks);
82
- const req = http.request({
83
- host: '127.0.0.1', port, method: 'POST',
84
- path: '/hook/session-start',
85
- headers: { 'Content-Type': 'application/json', 'Content-Length': body.length }
86
- }, res => res.resume());
87
- req.on('error', () => {});
88
- req.end(body);
89
- });
90
- process.stdin.resume();
91
- `;
92
- writeFileSync(forwarderPath, forwarderCode, { mode: 493 });
93
- const settingsPath = join(hooksDir, `session-hook-${process.pid}.json`);
94
- const hookCommand = `node "${forwarderPath}" ${port}`;
95
- const settings = {
96
- hooks: {
97
- SessionStart: [
98
- {
99
- matcher: "*",
100
- hooks: [{ type: "command", command: hookCommand }]
101
- }
102
- ]
103
- }
104
- };
105
- writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
106
- const cleanup = () => {
107
- try {
108
- if (existsSync(settingsPath)) unlinkSync(settingsPath);
109
- } catch {
110
- }
111
- try {
112
- if (existsSync(forwarderPath)) unlinkSync(forwarderPath);
113
- } catch {
114
- }
115
- };
116
- return { settingsPath, cleanup };
117
- }
118
-
119
69
  const INTERNAL_EVENT_TYPES = /* @__PURE__ */ new Set([
120
70
  "file-history-snapshot",
121
71
  "change",
@@ -52,7 +52,7 @@ async function handleServeCommand() {
52
52
  }
53
53
  }
54
54
  async function serveAdd(args, machineId) {
55
- const { connectAndGetMachine } = await import('./commands-Cd_I1MXo.mjs');
55
+ const { connectAndGetMachine } = await import('./commands-B6zZtCuh.mjs');
56
56
  const pos = positionalArgs(args);
57
57
  const name = pos[0];
58
58
  if (!name) {
@@ -84,7 +84,7 @@ async function serveAdd(args, machineId) {
84
84
  }
85
85
  }
86
86
  async function serveRemove(args, machineId) {
87
- const { connectAndGetMachine } = await import('./commands-Cd_I1MXo.mjs');
87
+ const { connectAndGetMachine } = await import('./commands-B6zZtCuh.mjs');
88
88
  const pos = positionalArgs(args);
89
89
  const name = pos[0];
90
90
  if (!name) {
@@ -104,7 +104,7 @@ async function serveRemove(args, machineId) {
104
104
  }
105
105
  }
106
106
  async function serveList(args, machineId) {
107
- const { connectAndGetMachine } = await import('./commands-Cd_I1MXo.mjs');
107
+ const { connectAndGetMachine } = await import('./commands-B6zZtCuh.mjs');
108
108
  const all = hasFlag(args, "--all", "-a");
109
109
  const json = hasFlag(args, "--json");
110
110
  const sessionId = getFlag(args, "--session");
@@ -137,7 +137,7 @@ async function serveList(args, machineId) {
137
137
  }
138
138
  }
139
139
  async function serveInfo(machineId) {
140
- const { connectAndGetMachine } = await import('./commands-Cd_I1MXo.mjs');
140
+ const { connectAndGetMachine } = await import('./commands-B6zZtCuh.mjs');
141
141
  const { machine, server } = await connectAndGetMachine(machineId);
142
142
  try {
143
143
  const info = await machine.serveInfo();
@@ -375,6 +375,7 @@ class ServeManager {
375
375
  return {
376
376
  url: firstUrl,
377
377
  port: running ? this.caddy?.port ?? this.port : 0,
378
+ authProxyPort: running ? this.port : 0,
378
379
  running,
379
380
  mountCount: this.mounts.size,
380
381
  mounts: Array.from(this.mounts.values()).map((m) => ({
@@ -510,6 +511,18 @@ class ServeManager {
510
511
  basePath = mountName ? url.pathname.slice(`/${mountName}`.length) || "/" : url.pathname;
511
512
  }
512
513
  const mount = mountName ? this.mounts.get(mountName) : void 0;
514
+ if (basePath === "/__svamp_health" || url.pathname === "/__svamp_health") {
515
+ res.writeHead(200, {
516
+ "Content-Type": "application/json",
517
+ "Cache-Control": "no-store"
518
+ });
519
+ res.end(JSON.stringify({
520
+ ok: true,
521
+ mount: mountName || null,
522
+ ts: Date.now()
523
+ }));
524
+ return;
525
+ }
513
526
  if (basePath === "/__login__" || url.pathname === "/__login__") {
514
527
  const returnUrl = url.searchParams.get("return") || "/";
515
528
  const safeReturn = returnUrl.startsWith("/__login__") ? "/" : returnUrl;
@@ -634,10 +647,17 @@ class ServeManager {
634
647
  const subdomainSafe = mountName.toLowerCase().replace(/[^a-z0-9-]/g, "-");
635
648
  const tunnelName = `static-${subdomainSafe}`;
636
649
  try {
637
- const { FrpcTunnel } = await import('./frpc-DzRFx60H.mjs');
638
- const tunnel = new FrpcTunnel({
650
+ const { FrpcTunnel } = await import('./frpc-j60b46eU.mjs');
651
+ let tunnel;
652
+ tunnel = new FrpcTunnel({
639
653
  name: tunnelName,
640
654
  ports: [this.port],
655
+ // End-to-end probe: the daemon's health loop watches probe.ok
656
+ // to detect ghosted tunnel registrations (frpc says "connected"
657
+ // but no traffic actually flows). The sentinel route is served
658
+ // by the auth proxy without auth.
659
+ probePath: "/__svamp_health",
660
+ probeIntervalMs: 3e4,
641
661
  onError: (err) => this.log(`frpc error [${mountName}]: ${err.message}`),
642
662
  onConnect: () => {
643
663
  const url2 = tunnel.getUrls().get(this.port);
@@ -650,7 +670,8 @@ class ServeManager {
650
670
  this.log(`frpc tunnel connected for '${mountName}'. URL: ${url2}/`);
651
671
  }
652
672
  },
653
- onDisconnect: () => this.log(`frpc tunnel for '${mountName}' disconnected, will auto-reconnect...`)
673
+ onDisconnect: () => this.log(`frpc tunnel for '${mountName}' disconnected, will auto-reconnect...`),
674
+ onProbeFail: (err) => this.log(`probe fail [${mountName}]: ${err.message}`)
654
675
  });
655
676
  await tunnel.connect();
656
677
  this.mountTunnels.set(mountName, tunnel);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svamp-cli",
3
- "version": "0.2.45",
3
+ "version": "0.2.46",
4
4
  "description": "Svamp CLI — AI workspace daemon on Hypha Cloud",
5
5
  "author": "Amun AI AB",
6
6
  "license": "SEE LICENSE IN LICENSE",