wiki-viewer 2.7.5 → 2.7.6

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 (87) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/build-manifest.json +3 -3
  3. package/.next/standalone/.next/prerender-manifest.json +3 -3
  4. package/.next/standalone/.next/required-server-files.json +1 -1
  5. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  6. package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
  7. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  8. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  9. package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  10. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  11. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  12. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  13. package/.next/standalone/.next/server/app/_not-found.rsc +1 -1
  14. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  15. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  16. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  17. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  18. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  19. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  20. package/.next/standalone/.next/server/app/api/agent/activity/route.js.nft.json +1 -1
  21. package/.next/standalone/.next/server/app/api/agent/events/[...path]/route.js.nft.json +1 -1
  22. package/.next/standalone/.next/server/app/api/agent/files/[...path]/route.js.nft.json +1 -1
  23. package/.next/standalone/.next/server/app/api/agent/fs/file/[...path]/route.js.nft.json +1 -1
  24. package/.next/standalone/.next/server/app/api/agent/fs/ls/[[...path]]/route.js.nft.json +1 -1
  25. package/.next/standalone/.next/server/app/api/agent/fs/move/route.js.nft.json +1 -1
  26. package/.next/standalone/.next/server/app/api/agent/fs/search/route.js.nft.json +1 -1
  27. package/.next/standalone/.next/server/app/api/agent/internal/span/route.js.nft.json +1 -1
  28. package/.next/standalone/.next/server/app/api/agent/settings/route.js.nft.json +1 -1
  29. package/.next/standalone/.next/server/app/api/agent/sidecar/[...path]/route.js.nft.json +1 -1
  30. package/.next/standalone/.next/server/app/api/assets/[...path]/route.js.nft.json +1 -1
  31. package/.next/standalone/.next/server/app/api/pdf/save/route.js.nft.json +1 -1
  32. package/.next/standalone/.next/server/app/api/share/[token]/asset/route.js.nft.json +1 -1
  33. package/.next/standalone/.next/server/app/api/share/[token]/route.js.nft.json +1 -1
  34. package/.next/standalone/.next/server/app/api/share/route.js.nft.json +1 -1
  35. package/.next/standalone/.next/server/app/api/system/reveal/route.js.nft.json +1 -1
  36. package/.next/standalone/.next/server/app/api/system/set-root/route.js.nft.json +1 -1
  37. package/.next/standalone/.next/server/app/api/system/workspaces/[id]/branch/route.js.nft.json +1 -1
  38. package/.next/standalone/.next/server/app/api/system/workspaces/[id]/open/route.js.nft.json +1 -1
  39. package/.next/standalone/.next/server/app/api/system/workspaces/[id]/refresh/route.js.nft.json +1 -1
  40. package/.next/standalone/.next/server/app/api/system/workspaces/[id]/route.js.nft.json +1 -1
  41. package/.next/standalone/.next/server/app/api/system/workspaces/route.js.nft.json +1 -1
  42. package/.next/standalone/.next/server/app/api/upload/[...path]/route.js.nft.json +1 -1
  43. package/.next/standalone/.next/server/app/api/wiki/app/route.js.nft.json +1 -1
  44. package/.next/standalone/.next/server/app/api/wiki/backlinks/route.js.nft.json +1 -1
  45. package/.next/standalone/.next/server/app/api/wiki/content/route.js.nft.json +1 -1
  46. package/.next/standalone/.next/server/app/api/wiki/download/route.js.nft.json +1 -1
  47. package/.next/standalone/.next/server/app/api/wiki/file/route.js.nft.json +1 -1
  48. package/.next/standalone/.next/server/app/api/wiki/folder/route.js.nft.json +1 -1
  49. package/.next/standalone/.next/server/app/api/wiki/git-branches/route.js.nft.json +1 -1
  50. package/.next/standalone/.next/server/app/api/wiki/git-checkout/route.js.nft.json +1 -1
  51. package/.next/standalone/.next/server/app/api/wiki/git-diff/route.js.nft.json +1 -1
  52. package/.next/standalone/.next/server/app/api/wiki/git-file-info/route.js.nft.json +1 -1
  53. package/.next/standalone/.next/server/app/api/wiki/git-history/route.js.nft.json +1 -1
  54. package/.next/standalone/.next/server/app/api/wiki/git-pull/route.js.nft.json +1 -1
  55. package/.next/standalone/.next/server/app/api/wiki/move/route.js.nft.json +1 -1
  56. package/.next/standalone/.next/server/app/api/wiki/new-file/route.js.nft.json +1 -1
  57. package/.next/standalone/.next/server/app/api/wiki/outlinks/route.js.nft.json +1 -1
  58. package/.next/standalone/.next/server/app/api/wiki/page/route.js.nft.json +1 -1
  59. package/.next/standalone/.next/server/app/api/wiki/presence/route.js.nft.json +1 -1
  60. package/.next/standalone/.next/server/app/api/wiki/route.js.nft.json +1 -1
  61. package/.next/standalone/.next/server/app/api/wiki/search/route.js.nft.json +1 -1
  62. package/.next/standalone/.next/server/app/api/wiki/slugs/route.js.nft.json +1 -1
  63. package/.next/standalone/.next/server/app/api/wiki/upload/route.js.nft.json +1 -1
  64. package/.next/standalone/.next/server/app/api/wiki/watch/route.js.nft.json +1 -1
  65. package/.next/standalone/.next/server/app/index.html +1 -1
  66. package/.next/standalone/.next/server/app/index.rsc +2 -2
  67. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  68. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +2 -2
  69. package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  70. package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  71. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  72. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  73. package/.next/standalone/.next/server/chunks/ssr/_0v4uz-4._.js +1 -1
  74. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  75. package/.next/standalone/.next/server/middleware-manifest.json +5 -5
  76. package/.next/standalone/.next/server/pages/404.html +1 -1
  77. package/.next/standalone/.next/server/pages/500.html +1 -1
  78. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  79. package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
  80. package/.next/standalone/.next/static/chunks/{0i-0jdw7dtj9c.js → 0hwf-t3aoviy_.js} +1 -1
  81. package/.next/standalone/package.json +1 -1
  82. package/.next/standalone/server.js +1 -1
  83. package/bin/wiki-viewer.js +121 -22
  84. package/package.json +1 -1
  85. /package/.next/standalone/.next/static/{w6zxJ1-lNNl0jldTTzyLC → GrvEfHFNbgW5qJUpfaeje}/_buildManifest.js +0 -0
  86. /package/.next/standalone/.next/static/{w6zxJ1-lNNl0jldTTzyLC → GrvEfHFNbgW5qJUpfaeje}/_clientMiddlewareManifest.js +0 -0
  87. /package/.next/standalone/.next/static/{w6zxJ1-lNNl0jldTTzyLC → GrvEfHFNbgW5qJUpfaeje}/_ssgManifest.js +0 -0
@@ -15,7 +15,7 @@ const currentPort = parseInt(process.env.PORT, 10) || 3000
15
15
  const hostname = process.env.HOSTNAME || '0.0.0.0'
16
16
 
17
17
  let keepAliveTimeout = parseInt(process.env.KEEP_ALIVE_TIMEOUT, 10)
18
- const nextConfig = {"env":{"NEXT_PUBLIC_APP_VERSION":"2.7.5"},"webpack":null,"typescript":{"ignoreBuildErrors":false},"typedRoutes":false,"distDir":"./.next","cleanDistDir":true,"assetPrefix":"","cacheMaxMemorySize":52428800,"configOrigin":"next.config.ts","useFileSystemPublicRoutes":true,"generateEtags":true,"pageExtensions":["tsx","ts","jsx","js"],"poweredByHeader":true,"compress":true,"images":{"deviceSizes":[640,750,828,1080,1200,1920,2048,3840],"imageSizes":[32,48,64,96,128,256,384],"path":"/_next/image","loader":"default","loaderFile":"","domains":[],"disableStaticImages":false,"minimumCacheTTL":14400,"formats":["image/webp"],"maximumRedirects":3,"maximumResponseBody":50000000,"dangerouslyAllowLocalIP":false,"dangerouslyAllowSVG":false,"contentSecurityPolicy":"script-src 'none'; frame-src 'none'; sandbox;","contentDispositionType":"attachment","localPatterns":[{"pathname":"**","search":""}],"remotePatterns":[],"qualities":[75],"unoptimized":false,"customCacheHandler":false},"devIndicators":{"position":"bottom-left"},"onDemandEntries":{"maxInactiveAge":60000,"pagesBufferLength":5},"basePath":"","sassOptions":{},"trailingSlash":false,"i18n":null,"productionBrowserSourceMaps":false,"excludeDefaultMomentLocales":true,"reactProductionProfiling":false,"reactStrictMode":null,"reactMaxHeadersLength":6000,"httpAgentOptions":{"keepAlive":true},"logging":{"serverFunctions":true,"browserToTerminal":"warn"},"compiler":{},"expireTime":31536000,"staticPageGenerationTimeout":60,"output":"standalone","modularizeImports":{"@mui/icons-material":{"transform":"@mui/icons-material/{{member}}"},"lodash":{"transform":"lodash/{{member}}"}},"outputFileTracingRoot":"/home/runner/work/wiki-viewer/wiki-viewer","allowedDevOrigins":["devvm"],"cacheComponents":false,"cacheLife":{"default":{"stale":300,"revalidate":900,"expire":4294967294},"seconds":{"stale":30,"revalidate":1,"expire":60},"minutes":{"stale":300,"revalidate":60,"expire":3600},"hours":{"stale":300,"revalidate":3600,"expire":86400},"days":{"stale":300,"revalidate":86400,"expire":604800},"weeks":{"stale":300,"revalidate":604800,"expire":2592000},"max":{"stale":300,"revalidate":2592000,"expire":31536000}},"cacheHandlers":{},"experimental":{"appNewScrollHandler":false,"useSkewCookie":false,"cssChunking":true,"multiZoneDraftMode":false,"appNavFailHandling":false,"prerenderEarlyExit":true,"serverMinification":true,"linkNoTouchStart":false,"caseSensitiveRoutes":false,"cachedNavigations":false,"partialFallbacks":false,"dynamicOnHover":false,"varyParams":false,"prefetchInlining":false,"preloadEntriesOnStart":true,"clientRouterFilter":true,"clientRouterFilterRedirects":false,"fetchCacheKeyPrefix":"","proxyPrefetch":"flexible","optimisticClientCache":true,"manualClientBasePath":false,"cpus":3,"memoryBasedWorkersCount":false,"imgOptConcurrency":null,"imgOptTimeoutInSeconds":7,"imgOptMaxInputPixels":268402689,"imgOptSequentialRead":null,"imgOptSkipMetadata":null,"isrFlushToDisk":true,"workerThreads":false,"optimizeCss":false,"nextScriptWorkers":false,"scrollRestoration":false,"externalDir":false,"disableOptimizedLoading":false,"gzipSize":true,"craCompat":false,"esmExternals":true,"fullySpecified":false,"swcTraceProfiling":false,"forceSwcTransforms":false,"largePageDataBytes":128000,"typedEnv":false,"parallelServerCompiles":false,"parallelServerBuildTraces":false,"ppr":false,"authInterrupts":false,"webpackMemoryOptimizations":false,"optimizeServerReact":true,"strictRouteTypes":false,"viewTransition":false,"removeUncaughtErrorAndRejectionListeners":false,"validateRSCRequestHeaders":false,"staleTimes":{"dynamic":0,"static":300},"reactDebugChannel":true,"serverComponentsHmrCache":true,"staticGenerationMaxConcurrency":8,"staticGenerationMinPagesPerWorker":25,"transitionIndicator":false,"gestureTransition":false,"inlineCss":false,"useCache":false,"globalNotFound":false,"browserDebugInfoInTerminal":"warn","lockDistDir":true,"proxyClientMaxBodySize":10485760,"hideLogsAfterAbort":false,"mcpServer":true,"turbopackFileSystemCacheForDev":true,"turbopackFileSystemCacheForBuild":false,"turbopackInferModuleSideEffects":true,"turbopackPluginRuntimeStrategy":"childProcesses","optimizePackageImports":["lucide-react","date-fns","lodash-es","ramda","antd","react-bootstrap","ahooks","@ant-design/icons","@headlessui/react","@headlessui-float/react","@heroicons/react/20/solid","@heroicons/react/24/solid","@heroicons/react/24/outline","@visx/visx","@tremor/react","rxjs","@mui/material","@mui/icons-material","recharts","react-use","effect","@effect/schema","@effect/platform","@effect/platform-node","@effect/platform-browser","@effect/platform-bun","@effect/sql","@effect/sql-mssql","@effect/sql-mysql2","@effect/sql-pg","@effect/sql-sqlite-node","@effect/sql-sqlite-bun","@effect/sql-sqlite-wasm","@effect/sql-sqlite-react-native","@effect/rpc","@effect/rpc-http","@effect/typeclass","@effect/experimental","@effect/opentelemetry","@material-ui/core","@material-ui/icons","@tabler/icons-react","mui-core","react-icons/ai","react-icons/bi","react-icons/bs","react-icons/cg","react-icons/ci","react-icons/di","react-icons/fa","react-icons/fa6","react-icons/fc","react-icons/fi","react-icons/gi","react-icons/go","react-icons/gr","react-icons/hi","react-icons/hi2","react-icons/im","react-icons/io","react-icons/io5","react-icons/lia","react-icons/lib","react-icons/lu","react-icons/md","react-icons/pi","react-icons/ri","react-icons/rx","react-icons/si","react-icons/sl","react-icons/tb","react-icons/tfi","react-icons/ti","react-icons/vsc","react-icons/wi"],"trustHostHeader":false,"isExperimentalCompile":false},"htmlLimitedBots":"[\\w-]+-Google|Google-[\\w-]+|Chrome-Lighthouse|Slurp|DuckDuckBot|baiduspider|yandex|sogou|bitlybot|tumblr|vkShare|quora link preview|redditbot|ia_archiver|Bingbot|BingPreview|applebot|facebookexternalhit|facebookcatalog|Twitterbot|LinkedInBot|Slackbot|Discordbot|WhatsApp|SkypeUriPreview|Yeti|googleweblight","bundlePagesRouterDependencies":false,"configFileName":"next.config.ts","turbopack":{"root":"/home/runner/work/wiki-viewer/wiki-viewer"},"distDirRoot":".next"}
18
+ const nextConfig = {"env":{"NEXT_PUBLIC_APP_VERSION":"2.7.6"},"webpack":null,"typescript":{"ignoreBuildErrors":false},"typedRoutes":false,"distDir":"./.next","cleanDistDir":true,"assetPrefix":"","cacheMaxMemorySize":52428800,"configOrigin":"next.config.ts","useFileSystemPublicRoutes":true,"generateEtags":true,"pageExtensions":["tsx","ts","jsx","js"],"poweredByHeader":true,"compress":true,"images":{"deviceSizes":[640,750,828,1080,1200,1920,2048,3840],"imageSizes":[32,48,64,96,128,256,384],"path":"/_next/image","loader":"default","loaderFile":"","domains":[],"disableStaticImages":false,"minimumCacheTTL":14400,"formats":["image/webp"],"maximumRedirects":3,"maximumResponseBody":50000000,"dangerouslyAllowLocalIP":false,"dangerouslyAllowSVG":false,"contentSecurityPolicy":"script-src 'none'; frame-src 'none'; sandbox;","contentDispositionType":"attachment","localPatterns":[{"pathname":"**","search":""}],"remotePatterns":[],"qualities":[75],"unoptimized":false,"customCacheHandler":false},"devIndicators":{"position":"bottom-left"},"onDemandEntries":{"maxInactiveAge":60000,"pagesBufferLength":5},"basePath":"","sassOptions":{},"trailingSlash":false,"i18n":null,"productionBrowserSourceMaps":false,"excludeDefaultMomentLocales":true,"reactProductionProfiling":false,"reactStrictMode":null,"reactMaxHeadersLength":6000,"httpAgentOptions":{"keepAlive":true},"logging":{"serverFunctions":true,"browserToTerminal":"warn"},"compiler":{},"expireTime":31536000,"staticPageGenerationTimeout":60,"output":"standalone","modularizeImports":{"@mui/icons-material":{"transform":"@mui/icons-material/{{member}}"},"lodash":{"transform":"lodash/{{member}}"}},"outputFileTracingRoot":"/home/runner/work/wiki-viewer/wiki-viewer","allowedDevOrigins":["devvm"],"cacheComponents":false,"cacheLife":{"default":{"stale":300,"revalidate":900,"expire":4294967294},"seconds":{"stale":30,"revalidate":1,"expire":60},"minutes":{"stale":300,"revalidate":60,"expire":3600},"hours":{"stale":300,"revalidate":3600,"expire":86400},"days":{"stale":300,"revalidate":86400,"expire":604800},"weeks":{"stale":300,"revalidate":604800,"expire":2592000},"max":{"stale":300,"revalidate":2592000,"expire":31536000}},"cacheHandlers":{},"experimental":{"appNewScrollHandler":false,"useSkewCookie":false,"cssChunking":true,"multiZoneDraftMode":false,"appNavFailHandling":false,"prerenderEarlyExit":true,"serverMinification":true,"linkNoTouchStart":false,"caseSensitiveRoutes":false,"cachedNavigations":false,"partialFallbacks":false,"dynamicOnHover":false,"varyParams":false,"prefetchInlining":false,"preloadEntriesOnStart":true,"clientRouterFilter":true,"clientRouterFilterRedirects":false,"fetchCacheKeyPrefix":"","proxyPrefetch":"flexible","optimisticClientCache":true,"manualClientBasePath":false,"cpus":3,"memoryBasedWorkersCount":false,"imgOptConcurrency":null,"imgOptTimeoutInSeconds":7,"imgOptMaxInputPixels":268402689,"imgOptSequentialRead":null,"imgOptSkipMetadata":null,"isrFlushToDisk":true,"workerThreads":false,"optimizeCss":false,"nextScriptWorkers":false,"scrollRestoration":false,"externalDir":false,"disableOptimizedLoading":false,"gzipSize":true,"craCompat":false,"esmExternals":true,"fullySpecified":false,"swcTraceProfiling":false,"forceSwcTransforms":false,"largePageDataBytes":128000,"typedEnv":false,"parallelServerCompiles":false,"parallelServerBuildTraces":false,"ppr":false,"authInterrupts":false,"webpackMemoryOptimizations":false,"optimizeServerReact":true,"strictRouteTypes":false,"viewTransition":false,"removeUncaughtErrorAndRejectionListeners":false,"validateRSCRequestHeaders":false,"staleTimes":{"dynamic":0,"static":300},"reactDebugChannel":true,"serverComponentsHmrCache":true,"staticGenerationMaxConcurrency":8,"staticGenerationMinPagesPerWorker":25,"transitionIndicator":false,"gestureTransition":false,"inlineCss":false,"useCache":false,"globalNotFound":false,"browserDebugInfoInTerminal":"warn","lockDistDir":true,"proxyClientMaxBodySize":10485760,"hideLogsAfterAbort":false,"mcpServer":true,"turbopackFileSystemCacheForDev":true,"turbopackFileSystemCacheForBuild":false,"turbopackInferModuleSideEffects":true,"turbopackPluginRuntimeStrategy":"childProcesses","optimizePackageImports":["lucide-react","date-fns","lodash-es","ramda","antd","react-bootstrap","ahooks","@ant-design/icons","@headlessui/react","@headlessui-float/react","@heroicons/react/20/solid","@heroicons/react/24/solid","@heroicons/react/24/outline","@visx/visx","@tremor/react","rxjs","@mui/material","@mui/icons-material","recharts","react-use","effect","@effect/schema","@effect/platform","@effect/platform-node","@effect/platform-browser","@effect/platform-bun","@effect/sql","@effect/sql-mssql","@effect/sql-mysql2","@effect/sql-pg","@effect/sql-sqlite-node","@effect/sql-sqlite-bun","@effect/sql-sqlite-wasm","@effect/sql-sqlite-react-native","@effect/rpc","@effect/rpc-http","@effect/typeclass","@effect/experimental","@effect/opentelemetry","@material-ui/core","@material-ui/icons","@tabler/icons-react","mui-core","react-icons/ai","react-icons/bi","react-icons/bs","react-icons/cg","react-icons/ci","react-icons/di","react-icons/fa","react-icons/fa6","react-icons/fc","react-icons/fi","react-icons/gi","react-icons/go","react-icons/gr","react-icons/hi","react-icons/hi2","react-icons/im","react-icons/io","react-icons/io5","react-icons/lia","react-icons/lib","react-icons/lu","react-icons/md","react-icons/pi","react-icons/ri","react-icons/rx","react-icons/si","react-icons/sl","react-icons/tb","react-icons/tfi","react-icons/ti","react-icons/vsc","react-icons/wi"],"trustHostHeader":false,"isExperimentalCompile":false},"htmlLimitedBots":"[\\w-]+-Google|Google-[\\w-]+|Chrome-Lighthouse|Slurp|DuckDuckBot|baiduspider|yandex|sogou|bitlybot|tumblr|vkShare|quora link preview|redditbot|ia_archiver|Bingbot|BingPreview|applebot|facebookexternalhit|facebookcatalog|Twitterbot|LinkedInBot|Slackbot|Discordbot|WhatsApp|SkypeUriPreview|Yeti|googleweblight","bundlePagesRouterDependencies":false,"configFileName":"next.config.ts","turbopack":{"root":"/home/runner/work/wiki-viewer/wiki-viewer"},"distDirRoot":".next"}
19
19
 
20
20
  process.env.__NEXT_PRIVATE_STANDALONE_CONFIG = JSON.stringify(nextConfig)
21
21
 
@@ -76,6 +76,7 @@ function parseServeArgs(args) {
76
76
  let host = process.env.HOSTNAME;
77
77
  let useHttps;
78
78
  let userSpecifiedPort = false;
79
+ let userSpecifiedHost = false;
79
80
  let rootDir;
80
81
  let noAuth;
81
82
  let sshKey;
@@ -86,7 +87,7 @@ function parseServeArgs(args) {
86
87
  for (let i = 0; i < args.length; i++) {
87
88
  const a = args[i];
88
89
  if (a === "-p" || a === "--port") { port = args[++i] ?? port; userSpecifiedPort = true; }
89
- else if (a === "-H" || a === "--host") host = args[++i] ?? host;
90
+ else if (a === "-H" || a === "--host") { host = args[++i] ?? host; userSpecifiedHost = true; }
90
91
  else if (a === "-e" || a === "--env") { i++; } // consumed by parseEnvFlags
91
92
  else if (a === "--https") useHttps = true;
92
93
  else if (a === "--no-auth") noAuth = true;
@@ -97,7 +98,7 @@ function parseServeArgs(args) {
97
98
  else if (!a.startsWith("-") && rootDir === undefined) rootDir = a;
98
99
  }
99
100
 
100
- return { rootDir, port, host, useHttps, userSpecifiedPort, noAuth: Boolean(noAuth), sshKey, sshPort, sshPassword: Boolean(sshPassword), sshReadOnly: Boolean(sshReadOnly) };
101
+ return { rootDir, port, host, useHttps, userSpecifiedPort, userSpecifiedHost, noAuth: Boolean(noAuth), sshKey, sshPort, sshPassword: Boolean(sshPassword), sshReadOnly: Boolean(sshReadOnly) };
101
102
  }
102
103
 
103
104
  // ── ssh (sshfs) targets ──────────────────────────────────────────────────────
@@ -587,6 +588,85 @@ function runQuiet(cmd, args) {
587
588
 
588
589
  // ── service: install ──────────────────────────────────────────────────────────
589
590
 
591
+ // A persistent service bakes an absolute path to this script into the unit /
592
+ // plist (ExecStart). If we're running from a package-manager scratch cache
593
+ // (`npx wiki-viewer …`, `pnpm dlx …`, or an OS temp dir), that path is deleted
594
+ // the moment the cache is pruned, leaving a service that silently fails on the
595
+ // next reboot. Detect it and refuse, pointing the user at a global install.
596
+ function ephemeralInstallReason() {
597
+ const p = selfScript;
598
+ const sep = path.sep;
599
+ if (p.includes(`${sep}_npx${sep}`)) return "an npx cache";
600
+ if (p.includes(`${sep}dlx-`)) return "a pnpm/yarn dlx cache";
601
+ const tmp = os.tmpdir();
602
+ if (p === tmp || p.startsWith(tmp + sep)) return "a temporary directory";
603
+ return null;
604
+ }
605
+
606
+ function requirePersistentInstall() {
607
+ const reason = ephemeralInstallReason();
608
+ if (!reason) return;
609
+ console.error(`Error: cannot install a service from ${reason}.`);
610
+ console.error(` wiki-viewer is running from ${selfScript},`);
611
+ console.error(` which your package manager will delete. A service pointed there would`);
612
+ console.error(` break after the next cache cleanup or reboot.`);
613
+ console.error(``);
614
+ console.error(` Install it globally first, then install the service:`);
615
+ console.error(` npm install -g ${SERVICE_NAME}`);
616
+ console.error(` ${SERVICE_NAME} service install ...`);
617
+ process.exit(1);
618
+ }
619
+
620
+ // The unit/plist runs node by absolute path. process.execPath is often a
621
+ // version-manager runtime pinned to one Node version (fnm/nvm) — a version bump
622
+ // deletes that path and silently breaks the service. fnm keeps a stable
623
+ // `aliases/default/bin/node` symlink that follows the user's default across
624
+ // upgrades; prefer it. Never use `which node`: under fnm that's an ephemeral
625
+ // per-shell path in /run that vanishes on reboot.
626
+ function fnmRoot() {
627
+ return process.env.FNM_DIR || path.join(os.homedir(), ".local", "share", "fnm");
628
+ }
629
+
630
+ function resolveServiceNode() {
631
+ const exec = process.execPath;
632
+ const looksFnm = exec.includes("/fnm/") || exec.includes("/.fnm/") || exec.includes("fnm_multishells") || exec.includes("/fnm/node-versions/") || exec.includes("/.local/share/fnm/");
633
+ if (looksFnm) {
634
+ const fnmDefault = path.join(fnmRoot(), "aliases", "default", "bin", "node");
635
+ if (existsSync(fnmDefault)) return fnmDefault;
636
+ }
637
+ return exec;
638
+ }
639
+
640
+ // Symmetric to resolveServiceNode: when this script lives inside an fnm
641
+ // version-pinned global tree (`.../node-versions/<ver>/installation/...`, where
642
+ // `npm install -g` lands under fnm), a Node upgrade or prune deletes that whole
643
+ // tree — including this file. Redirect ExecStart through the stable
644
+ // `aliases/default` symlink, which follows the user's default version.
645
+ function resolveServiceScript() {
646
+ const script = selfScript;
647
+ const pinned = path.join(fnmRoot(), "node-versions") + path.sep;
648
+ if (!script.startsWith(pinned)) return script; // dev checkout / system install: already stable
649
+ const parts = path.relative(path.join(fnmRoot(), "node-versions"), script).split(path.sep);
650
+ // parts = [<ver>, "installation", ...rest]; aliases/default -> the installation dir.
651
+ if (parts[1] !== "installation") return script;
652
+ const durable = path.join(fnmRoot(), "aliases", "default", ...parts.slice(2));
653
+ return existsSync(durable) ? durable : script;
654
+ }
655
+
656
+ // After resolving the most durable node we can, warn if it's *still* pinned to a
657
+ // version-manager runtime version we couldn't redirect to a stable alias.
658
+ function versionManagedNodeWarning(nodePath) {
659
+ const markers = ["/.nvm/", "/.asdf/", "/.volta/", "/n/versions/", "/fnm_multishells/", "/node-versions/"];
660
+ if (!markers.some((m) => nodePath.includes(m))) return null;
661
+ return (
662
+ `The service will run Node from a version-manager path:\n` +
663
+ ` ${nodePath}\n` +
664
+ ` If you upgrade or remove that Node version, the service will stop working.\n` +
665
+ ` Set a stable default (e.g. \`fnm default <version>\`) or install wiki-viewer\n` +
666
+ ` under a system Node, then re-run the install.`
667
+ );
668
+ }
669
+
590
670
  // Pull repeatable `--env KEY=VALUE` (or `-e KEY=VALUE`) pairs out of an argv
591
671
  // list. Returns the collected map; the caller has already parsed the rest.
592
672
  function parseEnvFlags(args) {
@@ -607,6 +687,8 @@ function parseEnvFlags(args) {
607
687
 
608
688
  function serviceInstall(args) {
609
689
  const p = requireSupportedPlatform();
690
+ // Refuse before writing anything if we can't produce a durable ExecStart path.
691
+ requirePersistentInstall();
610
692
 
611
693
  // Capture the run config from flags (falling back to existing config), persist it.
612
694
  const cli = parseServeArgs(args);
@@ -614,21 +696,31 @@ function serviceInstall(args) {
614
696
  const existing = loadConfig();
615
697
  const mergedEnv = { ...(existing.env ?? {}), ...envFlags };
616
698
  const cliIsSsh = cli.rootDir != null && looksLikeSshTarget(cli.rootDir);
699
+ // Spread the existing config first so keys we don't manage here (and
700
+ // existing.ssh when this run isn't an SSH target) survive instead of being
701
+ // clobbered back to defaults.
617
702
  const cfg = {
703
+ ...existing,
618
704
  rootDir: cli.rootDir != null
619
705
  ? (cliIsSsh ? cli.rootDir : path.resolve(cli.rootDir))
620
706
  : existing.rootDir ?? null,
621
- host: cli.host ?? existing.host ?? "localhost",
622
- port: cli.port ?? existing.port ?? "3000",
707
+ // Only let the CLI override the persisted host/port when the flag was
708
+ // explicitly passed. cli.host/cli.port are seeded from HOSTNAME/PORT env, so
709
+ // gating on `??` would let ambient env silently clobber the saved config on
710
+ // every reinstall.
711
+ host: cli.userSpecifiedHost ? cli.host : existing.host ?? "localhost",
712
+ port: cli.userSpecifiedPort ? cli.port : existing.port ?? "3000",
623
713
  https: cli.useHttps ?? existing.https ?? false,
624
- // Persist ssh options so `service run` can remount on boot. Password auth is
625
- // intentionally NOT persisted — services run non-interactively, so use
626
- // ssh-agent or --ssh-key for a reboot-persistent SSH workspace.
627
- ...(cliIsSsh
628
- ? { ssh: { ...(cli.sshKey ? { key: cli.sshKey } : {}), ...(cli.sshPort ? { port: cli.sshPort } : {}), ...(cli.sshReadOnly ? { readOnly: true } : {}) } }
629
- : existing.ssh ? { ssh: existing.ssh } : {}),
630
- ...(Object.keys(mergedEnv).length ? { env: mergedEnv } : {}),
631
714
  };
715
+ // Persist ssh options so `service run` can remount on boot. Password auth is
716
+ // intentionally NOT persisted — services run non-interactively, so use
717
+ // ssh-agent or --ssh-key for a reboot-persistent SSH workspace. Only overwrite
718
+ // ssh when this run explicitly targets one; otherwise existing.ssh is kept.
719
+ if (cliIsSsh) {
720
+ cfg.ssh = { ...(cli.sshKey ? { key: cli.sshKey } : {}), ...(cli.sshPort ? { port: cli.sshPort } : {}), ...(cli.sshReadOnly ? { readOnly: true } : {}) };
721
+ }
722
+ if (Object.keys(mergedEnv).length) cfg.env = mergedEnv;
723
+ else delete cfg.env;
632
724
  if (cliIsSsh && cli.sshPassword) {
633
725
  console.log("⚠️ --ssh-password is ignored for services (non-interactive). Use ssh-agent or --ssh-key.\n");
634
726
  }
@@ -649,6 +741,9 @@ function serviceInstall(args) {
649
741
  });
650
742
  for (const w of warnings) console.log(`⚠️ ${w}\n`);
651
743
 
744
+ const nodeWarning = versionManagedNodeWarning(resolveServiceNode());
745
+ if (nodeWarning) console.log(`⚠️ ${nodeWarning}\n`);
746
+
652
747
  if (p === "linux") installSystemd();
653
748
  else installLaunchd();
654
749
  }
@@ -709,13 +804,15 @@ function installSystemd() {
709
804
  mkdirSync(unitDir, { recursive: true });
710
805
  const unitPath = path.join(unitDir, `${SERVICE_NAME}.service`);
711
806
 
807
+ const nodeBin = resolveServiceNode();
808
+ const scriptPath = resolveServiceScript();
712
809
  const unit = `[Unit]
713
810
  Description=wiki-viewer local file viewer
714
811
  After=network.target
715
812
 
716
813
  [Service]
717
814
  Type=simple
718
- ExecStart=${process.execPath} ${selfScript} service run
815
+ ExecStart=${nodeBin} ${scriptPath} service run
719
816
  Restart=on-failure
720
817
  RestartSec=3
721
818
  Environment=NODE_ENV=production
@@ -751,6 +848,8 @@ function installLaunchd() {
751
848
  const outLog = path.join(logDir, "out.log");
752
849
  const errLog = path.join(logDir, "err.log");
753
850
 
851
+ const nodeBin = resolveServiceNode();
852
+ const scriptPath = resolveServiceScript();
754
853
  const plist = `<?xml version="1.0" encoding="UTF-8"?>
755
854
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
756
855
  <plist version="1.0">
@@ -759,8 +858,8 @@ function installLaunchd() {
759
858
  <string>${LAUNCHD_LABEL}</string>
760
859
  <key>ProgramArguments</key>
761
860
  <array>
762
- <string>${process.execPath}</string>
763
- <string>${selfScript}</string>
861
+ <string>${nodeBin}</string>
862
+ <string>${scriptPath}</string>
764
863
  <string>service</string>
765
864
  <string>run</string>
766
865
  </array>
@@ -1013,14 +1112,11 @@ async function runWizard() {
1013
1112
  }
1014
1113
  }
1015
1114
 
1016
- // Build and preview the config.
1017
- const cfg = {
1018
- rootDir,
1019
- host,
1020
- port,
1021
- https: useHttps,
1022
- ...(Object.keys(env).length ? { env } : {}),
1023
- };
1115
+ // Build and preview the config. Spread the existing config first so keys the
1116
+ // wizard doesn't touch (e.g. ssh) survive; then explicitly set/clear env.
1117
+ const cfg = { ...existing, rootDir, host, port, https: useHttps };
1118
+ if (Object.keys(env).length) cfg.env = env;
1119
+ else delete cfg.env;
1024
1120
 
1025
1121
  console.log("\nConfiguration:");
1026
1122
  console.log(` directory : ${rootDir ?? "(choose in browser)"}`);
@@ -1053,6 +1149,9 @@ async function runWizard() {
1053
1149
  console.log("Run it yourself with: wiki-viewer service run");
1054
1150
  return;
1055
1151
  }
1152
+ requirePersistentInstall();
1153
+ const nodeWarning = versionManagedNodeWarning(resolveServiceNode());
1154
+ if (nodeWarning) console.log(`\n⚠️ ${nodeWarning}\n`);
1056
1155
  if (p === "linux") installSystemd();
1057
1156
  else installLaunchd();
1058
1157
  } else if (choice === "2") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wiki-viewer",
3
- "version": "2.7.5",
3
+ "version": "2.7.6",
4
4
  "description": "Local file viewer and wiki — view markdown, HTML, PDFs, notebooks, office docs, and more from any directory",
5
5
  "license": "MIT",
6
6
  "type": "module",