@lampdotdev/lamp 0.0.0-stage → 0.36.2-nightly.16
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/LICENSE +21 -0
- package/README.md +397 -2
- package/Resources/Devices/roku.json +410 -0
- package/Resources/Devices/xbox-one.json +367 -0
- package/Resources/GameKit/NOTICE.md +63 -0
- package/Resources/GameKit/apple/LampPage.swift +1813 -0
- package/Resources/GameKit/apple/LampPlayer.swift +46 -0
- package/Resources/GameKit/apple/LampWebApp.swift +63 -0
- package/Resources/GameKit/apple/LampWebGame.swift +87 -0
- package/Resources/GameKit/apple/Native.swift +12 -0
- package/Resources/GameKit/build.sh +55 -0
- package/Resources/GameKit/lamp_game.h +116 -0
- package/Resources/GameKit/lamp_host.h +19 -0
- package/Resources/GameKit/lamp_kit.cpp +61 -0
- package/Resources/GameKit/lamp_sound.cpp +455 -0
- package/Resources/GameKit/lamp_xbox.cpp +374 -0
- package/Resources/GameKit/libraries/HandmadeMath.h +3940 -0
- package/Resources/GameKit/libraries/cgltf.h +7240 -0
- package/Resources/GameKit/libraries/dr_mp3.h +5430 -0
- package/Resources/GameKit/libraries/dr_wav.h +9209 -0
- package/Resources/GameKit/libraries/sokol_debugtext.h +4754 -0
- package/Resources/GameKit/libraries/sokol_gfx.h +29558 -0
- package/Resources/GameKit/libraries/sokol_gl.h +4538 -0
- package/Resources/GameKit/libraries/sokol_log.h +335 -0
- package/Resources/GameKit/libraries/sokol_shape.h +1531 -0
- package/Resources/GameKit/libraries/stb_image.h +7988 -0
- package/Resources/GameKit/libraries/stb_vorbis.c +5584 -0
- package/Resources/GameKit/page/lamp-live.js +672 -0
- package/Resources/GameKit/scaffold/Game/game.cpp +142 -0
- package/Resources/GameKit/scaffold/Game/scene.glsl +49 -0
- package/Resources/GameKit/scaffold-web/Web/game.js +31 -0
- package/Resources/GameKit/scaffold-web/Web/index.html +13 -0
- package/Resources/GameKit/scaffold-web/Web/making.js +33 -0
- package/Resources/GameKit/scaffold-web/Web/world.js +33 -0
- package/Resources/GameKit/web/lamp-game.js +3042 -0
- package/Resources/GameKit/web/lamp-phaser.js +128 -0
- package/Resources/WebHost/App.exe +0 -0
- package/Resources/WebHost/Microsoft.Web.WebView2.Core.dll +0 -0
- package/Resources/WebHost/WebView2-LICENSE.txt +27 -0
- package/Resources/WebHost/lamp_controllers.h +1506 -0
- package/Resources/WebHost/lamp_web_host.cpp +1173 -0
- package/Resources/WebLibraries/earlier.txt +318 -0
- package/Resources/WebLibraries/phaser/LICENSE.md +20 -0
- package/Resources/WebLibraries/phaser/NOTICE.md +2 -0
- package/Resources/WebLibraries/phaser/phaser.esm.min.js +1 -0
- package/Resources/WebLibraries/qrcode/LICENSE +21 -0
- package/Resources/WebLibraries/qrcode/NOTICE.md +4 -0
- package/Resources/WebLibraries/qrcode/qrcode.js +2297 -0
- package/Resources/WebLibraries/rapier/LICENSE +201 -0
- package/Resources/WebLibraries/rapier/NOTICE.md +3 -0
- package/Resources/WebLibraries/rapier/rapier.js +2 -0
- package/Resources/WebLibraries/three/LICENSE +21 -0
- package/Resources/WebLibraries/three/NOTICE.md +4 -0
- package/Resources/WebLibraries/three/addons/animation/AnimationClipCreator.js +168 -0
- package/Resources/WebLibraries/three/addons/animation/CCDIKSolver.js +607 -0
- package/Resources/WebLibraries/three/addons/controls/ArcballControls.js +3543 -0
- package/Resources/WebLibraries/three/addons/controls/DragControls.js +452 -0
- package/Resources/WebLibraries/three/addons/controls/FirstPersonControls.js +512 -0
- package/Resources/WebLibraries/three/addons/controls/FlyControls.js +384 -0
- package/Resources/WebLibraries/three/addons/controls/MapControls.js +116 -0
- package/Resources/WebLibraries/three/addons/controls/OrbitControls.js +1985 -0
- package/Resources/WebLibraries/three/addons/controls/PointerLockControls.js +264 -0
- package/Resources/WebLibraries/three/addons/controls/TrackballControls.js +1106 -0
- package/Resources/WebLibraries/three/addons/controls/TransformControls.js +2003 -0
- package/Resources/WebLibraries/three/addons/curves/CurveExtras.js +694 -0
- package/Resources/WebLibraries/three/addons/curves/NURBSCurve.js +169 -0
- package/Resources/WebLibraries/three/addons/curves/NURBSSurface.js +98 -0
- package/Resources/WebLibraries/three/addons/curves/NURBSUtils.js +532 -0
- package/Resources/WebLibraries/three/addons/curves/NURBSVolume.js +82 -0
- package/Resources/WebLibraries/three/addons/effects/AnaglyphEffect.js +274 -0
- package/Resources/WebLibraries/three/addons/effects/AsciiEffect.js +323 -0
- package/Resources/WebLibraries/three/addons/effects/OutlineEffect.js +489 -0
- package/Resources/WebLibraries/three/addons/effects/ParallaxBarrierEffect.js +155 -0
- package/Resources/WebLibraries/three/addons/effects/StereoEffect.js +91 -0
- package/Resources/WebLibraries/three/addons/environments/ColorEnvironment.js +59 -0
- package/Resources/WebLibraries/three/addons/environments/DebugEnvironment.js +102 -0
- package/Resources/WebLibraries/three/addons/environments/RoomEnvironment.js +185 -0
- package/Resources/WebLibraries/three/addons/geometries/BoxLineGeometry.js +92 -0
- package/Resources/WebLibraries/three/addons/geometries/ConvexGeometry.js +72 -0
- package/Resources/WebLibraries/three/addons/geometries/DecalGeometry.js +420 -0
- package/Resources/WebLibraries/three/addons/geometries/LoftGeometry.js +355 -0
- package/Resources/WebLibraries/three/addons/geometries/ParametricFunctions.js +100 -0
- package/Resources/WebLibraries/three/addons/geometries/ParametricGeometry.js +172 -0
- package/Resources/WebLibraries/three/addons/geometries/RoundedBoxGeometry.js +216 -0
- package/Resources/WebLibraries/three/addons/geometries/TeapotGeometry.js +689 -0
- package/Resources/WebLibraries/three/addons/geometries/TextGeometry.js +102 -0
- package/Resources/WebLibraries/three/addons/helpers/AnimationPathHelper.js +302 -0
- package/Resources/WebLibraries/three/addons/helpers/LightProbeGridHelper.js +166 -0
- package/Resources/WebLibraries/three/addons/helpers/LightProbeGridHelperWebGL.js +221 -0
- package/Resources/WebLibraries/three/addons/helpers/LightProbeHelper.js +166 -0
- package/Resources/WebLibraries/three/addons/helpers/LightProbeHelperGPU.js +102 -0
- package/Resources/WebLibraries/three/addons/helpers/OctreeHelper.js +109 -0
- package/Resources/WebLibraries/three/addons/helpers/PositionalAudioHelper.js +169 -0
- package/Resources/WebLibraries/three/addons/helpers/RapierHelper.js +59 -0
- package/Resources/WebLibraries/three/addons/helpers/RectAreaLightHelper.js +118 -0
- package/Resources/WebLibraries/three/addons/helpers/TextureHelper.js +265 -0
- package/Resources/WebLibraries/three/addons/helpers/TextureHelperGPU.js +214 -0
- package/Resources/WebLibraries/three/addons/helpers/VertexNormalsHelper.js +155 -0
- package/Resources/WebLibraries/three/addons/helpers/VertexTangentsHelper.js +133 -0
- package/Resources/WebLibraries/three/addons/helpers/ViewHelper.js +529 -0
- package/Resources/WebLibraries/three/addons/interactive/HTMLMesh.js +617 -0
- package/Resources/WebLibraries/three/addons/interactive/InteractiveGroup.js +224 -0
- package/Resources/WebLibraries/three/addons/interactive/SelectionBox.js +324 -0
- package/Resources/WebLibraries/three/addons/interactive/SelectionHelper.js +150 -0
- package/Resources/WebLibraries/three/addons/libs/fflate.module.js +2699 -0
- package/Resources/WebLibraries/three/addons/libs/lil-gui.module.min.js +8 -0
- package/Resources/WebLibraries/three/addons/libs/meshopt_decoder.module.js +196 -0
- package/Resources/WebLibraries/three/addons/libs/potpack.module.js +125 -0
- package/Resources/WebLibraries/three/addons/libs/stats.module.js +167 -0
- package/Resources/WebLibraries/three/addons/libs/tween.module.js +876 -0
- package/Resources/WebLibraries/three/addons/lighting/ClusteredLighting.js +153 -0
- package/Resources/WebLibraries/three/addons/lighting/DynamicLighting.js +82 -0
- package/Resources/WebLibraries/three/addons/lighting/LightMapper.js +295 -0
- package/Resources/WebLibraries/three/addons/lighting/LightProbeGrid.js +923 -0
- package/Resources/WebLibraries/three/addons/lighting/LightProbeGridUtils.js +107 -0
- package/Resources/WebLibraries/three/addons/lighting/LightProbeGridWebGL.js +846 -0
- package/Resources/WebLibraries/three/addons/lighting/vxgi/VXGIConeTracer.js +243 -0
- package/Resources/WebLibraries/three/addons/lighting/vxgi/VXGIIrradiance.js +43 -0
- package/Resources/WebLibraries/three/addons/lighting/vxgi/VXGINode.js +617 -0
- package/Resources/WebLibraries/three/addons/lighting/vxgi/VXGISceneCollector.js +793 -0
- package/Resources/WebLibraries/three/addons/lighting/vxgi/VXGIVolume.js +1440 -0
- package/Resources/WebLibraries/three/addons/lights/LightProbeGenerator.js +337 -0
- package/Resources/WebLibraries/three/addons/lights/RectAreaLightTexturesLib.js +127 -0
- package/Resources/WebLibraries/three/addons/lights/RectAreaLightUniformsLib.js +40 -0
- package/Resources/WebLibraries/three/addons/lights/SunLight.js +100 -0
- package/Resources/WebLibraries/three/addons/lights/SunLightNode.js +56 -0
- package/Resources/WebLibraries/three/addons/lights/SunLightShadow.js +319 -0
- package/Resources/WebLibraries/three/addons/lights/SunShadowNode.js +312 -0
- package/Resources/WebLibraries/three/addons/lines/Line2.js +56 -0
- package/Resources/WebLibraries/three/addons/lines/LineGeometry.js +157 -0
- package/Resources/WebLibraries/three/addons/lines/LineMaterial.js +742 -0
- package/Resources/WebLibraries/three/addons/lines/LineSegments2.js +434 -0
- package/Resources/WebLibraries/three/addons/lines/LineSegmentsGeometry.js +298 -0
- package/Resources/WebLibraries/three/addons/lines/Wireframe.js +108 -0
- package/Resources/WebLibraries/three/addons/lines/WireframeGeometry2.js +49 -0
- package/Resources/WebLibraries/three/addons/lines/webgpu/Line2.js +46 -0
- package/Resources/WebLibraries/three/addons/lines/webgpu/LineSegments2.js +419 -0
- package/Resources/WebLibraries/three/addons/lines/webgpu/Wireframe.js +86 -0
- package/Resources/WebLibraries/three/addons/loaders/EXRLoader.js +3411 -0
- package/Resources/WebLibraries/three/addons/loaders/FBXLoader.js +4660 -0
- package/Resources/WebLibraries/three/addons/loaders/FontLoader.js +262 -0
- package/Resources/WebLibraries/three/addons/loaders/GLTFLoader.js +5006 -0
- package/Resources/WebLibraries/three/addons/loaders/HDRLoader.js +463 -0
- package/Resources/WebLibraries/three/addons/loaders/MTLLoader.js +601 -0
- package/Resources/WebLibraries/three/addons/loaders/OBJLoader.js +961 -0
- package/Resources/WebLibraries/three/addons/loaders/PLYLoader.js +992 -0
- package/Resources/WebLibraries/three/addons/loaders/RGBELoader.js +18 -0
- package/Resources/WebLibraries/three/addons/loaders/STLLoader.js +423 -0
- package/Resources/WebLibraries/three/addons/loaders/SVGLoader.js +3297 -0
- package/Resources/WebLibraries/three/addons/loaders/TGALoader.js +539 -0
- package/Resources/WebLibraries/three/addons/loaders/UltraHDRLoader.js +757 -0
- package/Resources/WebLibraries/three/addons/math/Capsule.js +159 -0
- package/Resources/WebLibraries/three/addons/math/ColorConverter.js +62 -0
- package/Resources/WebLibraries/three/addons/math/ColorSpaces.js +147 -0
- package/Resources/WebLibraries/three/addons/math/ConvexHull.js +1695 -0
- package/Resources/WebLibraries/three/addons/math/ImprovedNoise.js +88 -0
- package/Resources/WebLibraries/three/addons/math/Lut.js +317 -0
- package/Resources/WebLibraries/three/addons/math/MeshSurfaceSampler.js +315 -0
- package/Resources/WebLibraries/three/addons/math/OBB.js +535 -0
- package/Resources/WebLibraries/three/addons/math/Octree.js +825 -0
- package/Resources/WebLibraries/three/addons/math/SimplexNoise.js +470 -0
- package/Resources/WebLibraries/three/addons/misc/ConvexObjectBreaker.js +539 -0
- package/Resources/WebLibraries/three/addons/misc/GPUComputationRenderer.js +508 -0
- package/Resources/WebLibraries/three/addons/misc/Gyroscope.js +78 -0
- package/Resources/WebLibraries/three/addons/misc/MorphAnimMesh.js +119 -0
- package/Resources/WebLibraries/three/addons/misc/MorphBlendMesh.js +425 -0
- package/Resources/WebLibraries/three/addons/misc/ProgressiveLightMap.js +370 -0
- package/Resources/WebLibraries/three/addons/misc/ProgressiveLightMapGPU.js +322 -0
- package/Resources/WebLibraries/three/addons/misc/RollerCoaster.js +661 -0
- package/Resources/WebLibraries/three/addons/misc/Sculptor.js +1679 -0
- package/Resources/WebLibraries/three/addons/misc/SculptorMesh.js +1504 -0
- package/Resources/WebLibraries/three/addons/misc/SculptorTools.js +1180 -0
- package/Resources/WebLibraries/three/addons/misc/SculptorUtils.js +345 -0
- package/Resources/WebLibraries/three/addons/misc/TileCreasedNormalsPlugin.js +270 -0
- package/Resources/WebLibraries/three/addons/misc/TubePainter.js +611 -0
- package/Resources/WebLibraries/three/addons/misc/Volume.js +520 -0
- package/Resources/WebLibraries/three/addons/misc/VolumeSlice.js +275 -0
- package/Resources/WebLibraries/three/addons/modifiers/CurveModifier.js +374 -0
- package/Resources/WebLibraries/three/addons/modifiers/CurveModifierGPU.js +256 -0
- package/Resources/WebLibraries/three/addons/modifiers/EdgeSplitModifier.js +299 -0
- package/Resources/WebLibraries/three/addons/modifiers/TessellateModifier.js +340 -0
- package/Resources/WebLibraries/three/addons/objects/GroundedSkybox.js +69 -0
- package/Resources/WebLibraries/three/addons/objects/Lensflare.js +489 -0
- package/Resources/WebLibraries/three/addons/objects/LensflareMesh.js +376 -0
- package/Resources/WebLibraries/three/addons/objects/MarchingCubes.js +1261 -0
- package/Resources/WebLibraries/three/addons/objects/Reflector.js +390 -0
- package/Resources/WebLibraries/three/addons/objects/ReflectorForSSRPass.js +393 -0
- package/Resources/WebLibraries/three/addons/objects/Refractor.js +389 -0
- package/Resources/WebLibraries/three/addons/objects/ShadowMesh.js +130 -0
- package/Resources/WebLibraries/three/addons/objects/Sky.js +342 -0
- package/Resources/WebLibraries/three/addons/objects/SkyMesh.js +403 -0
- package/Resources/WebLibraries/three/addons/objects/Water.js +374 -0
- package/Resources/WebLibraries/three/addons/objects/Water2.js +403 -0
- package/Resources/WebLibraries/three/addons/objects/Water2Mesh.js +199 -0
- package/Resources/WebLibraries/three/addons/objects/WaterMesh.js +194 -0
- package/Resources/WebLibraries/three/addons/postprocessing/AfterimagePass.js +187 -0
- package/Resources/WebLibraries/three/addons/postprocessing/BloomPass.js +274 -0
- package/Resources/WebLibraries/three/addons/postprocessing/BokehPass.js +218 -0
- package/Resources/WebLibraries/three/addons/postprocessing/ClearPass.js +97 -0
- package/Resources/WebLibraries/three/addons/postprocessing/CubeTexturePass.js +146 -0
- package/Resources/WebLibraries/three/addons/postprocessing/DotScreenPass.js +114 -0
- package/Resources/WebLibraries/three/addons/postprocessing/EffectComposer.js +365 -0
- package/Resources/WebLibraries/three/addons/postprocessing/FXAAPass.js +40 -0
- package/Resources/WebLibraries/three/addons/postprocessing/FilmPass.js +113 -0
- package/Resources/WebLibraries/three/addons/postprocessing/GTAOPass.js +735 -0
- package/Resources/WebLibraries/three/addons/postprocessing/GlitchPass.js +177 -0
- package/Resources/WebLibraries/three/addons/postprocessing/HalftonePass.js +134 -0
- package/Resources/WebLibraries/three/addons/postprocessing/LUTPass.js +138 -0
- package/Resources/WebLibraries/three/addons/postprocessing/MaskPass.js +195 -0
- package/Resources/WebLibraries/three/addons/postprocessing/OutlinePass.js +776 -0
- package/Resources/WebLibraries/three/addons/postprocessing/OutputPass.js +148 -0
- package/Resources/WebLibraries/three/addons/postprocessing/Pass.js +191 -0
- package/Resources/WebLibraries/three/addons/postprocessing/RenderPass.js +193 -0
- package/Resources/WebLibraries/three/addons/postprocessing/RenderPixelatedPass.js +314 -0
- package/Resources/WebLibraries/three/addons/postprocessing/RenderTransitionPass.js +267 -0
- package/Resources/WebLibraries/three/addons/postprocessing/SAOPass.js +407 -0
- package/Resources/WebLibraries/three/addons/postprocessing/SMAAPass.js +230 -0
- package/Resources/WebLibraries/three/addons/postprocessing/SSAARenderPass.js +313 -0
- package/Resources/WebLibraries/three/addons/postprocessing/SSAOPass.js +527 -0
- package/Resources/WebLibraries/three/addons/postprocessing/SSRPass.js +858 -0
- package/Resources/WebLibraries/three/addons/postprocessing/SavePass.js +132 -0
- package/Resources/WebLibraries/three/addons/postprocessing/ShaderPass.js +135 -0
- package/Resources/WebLibraries/three/addons/postprocessing/TAARenderPass.js +243 -0
- package/Resources/WebLibraries/three/addons/postprocessing/TexturePass.js +131 -0
- package/Resources/WebLibraries/three/addons/postprocessing/UnrealBloomPass.js +541 -0
- package/Resources/WebLibraries/three/addons/shaders/ACESFilmicToneMappingShader.js +96 -0
- package/Resources/WebLibraries/three/addons/shaders/AfterimageShader.js +63 -0
- package/Resources/WebLibraries/three/addons/shaders/BasicShader.js +36 -0
- package/Resources/WebLibraries/three/addons/shaders/BleachBypassShader.js +68 -0
- package/Resources/WebLibraries/three/addons/shaders/BlendShader.js +56 -0
- package/Resources/WebLibraries/three/addons/shaders/BokehShader.js +151 -0
- package/Resources/WebLibraries/three/addons/shaders/BokehShader2.js +404 -0
- package/Resources/WebLibraries/three/addons/shaders/BrightnessContrastShader.js +62 -0
- package/Resources/WebLibraries/three/addons/shaders/ColorCorrectionShader.js +59 -0
- package/Resources/WebLibraries/three/addons/shaders/ColorifyShader.js +57 -0
- package/Resources/WebLibraries/three/addons/shaders/ConvolutionShader.js +74 -0
- package/Resources/WebLibraries/three/addons/shaders/CopyShader.js +52 -0
- package/Resources/WebLibraries/three/addons/shaders/DOFMipMapShader.js +63 -0
- package/Resources/WebLibraries/three/addons/shaders/DepthLimitedBlurShader.js +183 -0
- package/Resources/WebLibraries/three/addons/shaders/DigitalGlitch.js +104 -0
- package/Resources/WebLibraries/three/addons/shaders/DotScreenShader.js +75 -0
- package/Resources/WebLibraries/three/addons/shaders/ExposureShader.js +51 -0
- package/Resources/WebLibraries/three/addons/shaders/FXAAShader.js +298 -0
- package/Resources/WebLibraries/three/addons/shaders/FilmShader.js +73 -0
- package/Resources/WebLibraries/three/addons/shaders/FocusShader.js +94 -0
- package/Resources/WebLibraries/three/addons/shaders/FreiChenShader.js +103 -0
- package/Resources/WebLibraries/three/addons/shaders/GTAOShader.js +437 -0
- package/Resources/WebLibraries/three/addons/shaders/GammaCorrectionShader.js +52 -0
- package/Resources/WebLibraries/three/addons/shaders/HalftoneShader.js +332 -0
- package/Resources/WebLibraries/three/addons/shaders/HorizontalBlurShader.js +68 -0
- package/Resources/WebLibraries/three/addons/shaders/HorizontalTiltShiftShader.js +70 -0
- package/Resources/WebLibraries/three/addons/shaders/HueSaturationShader.js +74 -0
- package/Resources/WebLibraries/three/addons/shaders/KaleidoShader.js +65 -0
- package/Resources/WebLibraries/three/addons/shaders/LuminosityHighPassShader.js +68 -0
- package/Resources/WebLibraries/three/addons/shaders/LuminosityShader.js +54 -0
- package/Resources/WebLibraries/three/addons/shaders/MirrorShader.js +62 -0
- package/Resources/WebLibraries/three/addons/shaders/NormalMapShader.js +60 -0
- package/Resources/WebLibraries/three/addons/shaders/OutputShader.js +103 -0
- package/Resources/WebLibraries/three/addons/shaders/PoissonDenoiseShader.js +230 -0
- package/Resources/WebLibraries/three/addons/shaders/RGBShiftShader.js +61 -0
- package/Resources/WebLibraries/three/addons/shaders/SAOShader.js +201 -0
- package/Resources/WebLibraries/three/addons/shaders/SMAAShader.js +489 -0
- package/Resources/WebLibraries/three/addons/shaders/SSAOShader.js +331 -0
- package/Resources/WebLibraries/three/addons/shaders/SSRShader.js +396 -0
- package/Resources/WebLibraries/three/addons/shaders/SepiaShader.js +57 -0
- package/Resources/WebLibraries/three/addons/shaders/SobelOperatorShader.js +98 -0
- package/Resources/WebLibraries/three/addons/shaders/SubsurfaceScatteringShader.js +95 -0
- package/Resources/WebLibraries/three/addons/shaders/TechnicolorShader.js +51 -0
- package/Resources/WebLibraries/three/addons/shaders/ToonShader.js +349 -0
- package/Resources/WebLibraries/three/addons/shaders/TriangleBlurShader.js +79 -0
- package/Resources/WebLibraries/three/addons/shaders/UnpackDepthRGBAShader.js +60 -0
- package/Resources/WebLibraries/three/addons/shaders/VelocityShader.js +137 -0
- package/Resources/WebLibraries/three/addons/shaders/VerticalBlurShader.js +66 -0
- package/Resources/WebLibraries/three/addons/shaders/VerticalTiltShiftShader.js +70 -0
- package/Resources/WebLibraries/three/addons/shaders/VignetteShader.js +56 -0
- package/Resources/WebLibraries/three/addons/shaders/VolumeShader.js +285 -0
- package/Resources/WebLibraries/three/addons/shaders/WaterRefractionShader.js +106 -0
- package/Resources/WebLibraries/three/addons/textures/FlakesTexture.js +54 -0
- package/Resources/WebLibraries/three/addons/tsl/WebGLNodesHandler.js +607 -0
- package/Resources/WebLibraries/three/addons/tsl/display/AfterImageNode.js +256 -0
- package/Resources/WebLibraries/three/addons/tsl/display/AnaglyphPassNode.js +550 -0
- package/Resources/WebLibraries/three/addons/tsl/display/BilateralBlurNode.js +377 -0
- package/Resources/WebLibraries/three/addons/tsl/display/BleachBypass.js +33 -0
- package/Resources/WebLibraries/three/addons/tsl/display/BloomNode.js +599 -0
- package/Resources/WebLibraries/three/addons/tsl/display/CRT.js +150 -0
- package/Resources/WebLibraries/three/addons/tsl/display/ChromaticAberrationNode.js +163 -0
- package/Resources/WebLibraries/three/addons/tsl/display/DenoiseNode.js +354 -0
- package/Resources/WebLibraries/three/addons/tsl/display/DepthOfFieldNode.js +572 -0
- package/Resources/WebLibraries/three/addons/tsl/display/DotScreenNode.js +104 -0
- package/Resources/WebLibraries/three/addons/tsl/display/FSR1Node.js +481 -0
- package/Resources/WebLibraries/three/addons/tsl/display/FXAANode.js +357 -0
- package/Resources/WebLibraries/three/addons/tsl/display/FilmNode.js +101 -0
- package/Resources/WebLibraries/three/addons/tsl/display/GTAONode.js +727 -0
- package/Resources/WebLibraries/three/addons/tsl/display/GaussianBlurNode.js +412 -0
- package/Resources/WebLibraries/three/addons/tsl/display/GodraysNode.js +604 -0
- package/Resources/WebLibraries/three/addons/tsl/display/ImportanceSampledEnvironment.js +564 -0
- package/Resources/WebLibraries/three/addons/tsl/display/LensflareNode.js +282 -0
- package/Resources/WebLibraries/three/addons/tsl/display/Lut3DNode.js +109 -0
- package/Resources/WebLibraries/three/addons/tsl/display/MotionBlur.js +33 -0
- package/Resources/WebLibraries/three/addons/tsl/display/OITPassNode.js +341 -0
- package/Resources/WebLibraries/three/addons/tsl/display/OutlineNode.js +916 -0
- package/Resources/WebLibraries/three/addons/tsl/display/ParallaxBarrierPassNode.js +90 -0
- package/Resources/WebLibraries/three/addons/tsl/display/PixelationPassNode.js +227 -0
- package/Resources/WebLibraries/three/addons/tsl/display/RGBShiftNode.js +96 -0
- package/Resources/WebLibraries/three/addons/tsl/display/RecurrentDenoiseNode.js +812 -0
- package/Resources/WebLibraries/three/addons/tsl/display/RetroPassNode.js +263 -0
- package/Resources/WebLibraries/three/addons/tsl/display/SMAANode.js +729 -0
- package/Resources/WebLibraries/three/addons/tsl/display/SSAAPassNode.js +344 -0
- package/Resources/WebLibraries/three/addons/tsl/display/SSAONode.js +422 -0
- package/Resources/WebLibraries/three/addons/tsl/display/SSGINode.js +698 -0
- package/Resources/WebLibraries/three/addons/tsl/display/SSRNode.js +1430 -0
- package/Resources/WebLibraries/three/addons/tsl/display/SSSNode.js +479 -0
- package/Resources/WebLibraries/three/addons/tsl/display/Sepia.js +24 -0
- package/Resources/WebLibraries/three/addons/tsl/display/Shape.js +29 -0
- package/Resources/WebLibraries/three/addons/tsl/display/SharpenNode.js +284 -0
- package/Resources/WebLibraries/three/addons/tsl/display/SobelOperatorNode.js +168 -0
- package/Resources/WebLibraries/three/addons/tsl/display/StereoCompositePassNode.js +190 -0
- package/Resources/WebLibraries/three/addons/tsl/display/StereoPassNode.js +117 -0
- package/Resources/WebLibraries/three/addons/tsl/display/TAAUNode.js +700 -0
- package/Resources/WebLibraries/three/addons/tsl/display/TRAANode.js +609 -0
- package/Resources/WebLibraries/three/addons/tsl/display/TemporalReprojectNode.js +1024 -0
- package/Resources/WebLibraries/three/addons/tsl/display/TransitionNode.js +141 -0
- package/Resources/WebLibraries/three/addons/tsl/display/boxBlur.js +65 -0
- package/Resources/WebLibraries/three/addons/tsl/display/depthAwareBlend.js +80 -0
- package/Resources/WebLibraries/three/addons/tsl/display/depthAwareBlur.js +63 -0
- package/Resources/WebLibraries/three/addons/tsl/display/hashBlur.js +55 -0
- package/Resources/WebLibraries/three/addons/tsl/display/lensDirt.js +30 -0
- package/Resources/WebLibraries/three/addons/tsl/display/radialBlur.js +68 -0
- package/Resources/WebLibraries/three/addons/tsl/lighting/ClusteredLightsNode.js +994 -0
- package/Resources/WebLibraries/three/addons/tsl/lighting/DynamicLightsNode.js +201 -0
- package/Resources/WebLibraries/three/addons/tsl/lighting/LightProbeGridNode.js +183 -0
- package/Resources/WebLibraries/three/addons/tsl/lighting/data/AmbientLightDataNode.js +67 -0
- package/Resources/WebLibraries/three/addons/tsl/lighting/data/DirectionalLightDataNode.js +117 -0
- package/Resources/WebLibraries/three/addons/tsl/lighting/data/HemisphereLightDataNode.js +105 -0
- package/Resources/WebLibraries/three/addons/tsl/lighting/data/PointLightDataNode.js +140 -0
- package/Resources/WebLibraries/three/addons/tsl/lighting/data/SpotLightDataNode.js +167 -0
- package/Resources/WebLibraries/three/addons/tsl/math/Bayer.js +84 -0
- package/Resources/WebLibraries/three/addons/tsl/math/curlNoise.js +107 -0
- package/Resources/WebLibraries/three/addons/tsl/math/voronoiNoise.js +112 -0
- package/Resources/WebLibraries/three/addons/tsl/shadows/TileShadowNode.js +542 -0
- package/Resources/WebLibraries/three/addons/tsl/shadows/TileShadowNodeHelper.js +212 -0
- package/Resources/WebLibraries/three/addons/tsl/utils/GroundedSkybox.js +62 -0
- package/Resources/WebLibraries/three/addons/tsl/utils/RNoise.js +51 -0
- package/Resources/WebLibraries/three/addons/tsl/utils/Raymarching.js +70 -0
- package/Resources/WebLibraries/three/addons/tsl/utils/SoftParticles.js +53 -0
- package/Resources/WebLibraries/three/addons/tsl/utils/SpecularHelpers.js +302 -0
- package/Resources/WebLibraries/three/addons/tsl/utils/TAAUtils.js +184 -0
- package/Resources/WebLibraries/three/addons/utils/BufferGeometryUtils.js +1523 -0
- package/Resources/WebLibraries/three/addons/utils/CameraUtils.js +82 -0
- package/Resources/WebLibraries/three/addons/utils/ColorUtils.js +76 -0
- package/Resources/WebLibraries/three/addons/utils/GaussianSplatUtils.js +229 -0
- package/Resources/WebLibraries/three/addons/utils/GeometryCompressionUtils.js +547 -0
- package/Resources/WebLibraries/three/addons/utils/GeometryUtils.js +226 -0
- package/Resources/WebLibraries/three/addons/utils/LDrawUtils.js +211 -0
- package/Resources/WebLibraries/three/addons/utils/SceneOptimizer.js +459 -0
- package/Resources/WebLibraries/three/addons/utils/SceneUtils.js +363 -0
- package/Resources/WebLibraries/three/addons/utils/ShadowMapViewer.js +244 -0
- package/Resources/WebLibraries/three/addons/utils/ShadowMapViewerGPU.js +233 -0
- package/Resources/WebLibraries/three/addons/utils/SkeletonUtils.js +496 -0
- package/Resources/WebLibraries/three/addons/utils/SortUtils.js +175 -0
- package/Resources/WebLibraries/three/addons/utils/UVsDebug.js +173 -0
- package/Resources/WebLibraries/three/addons/utils/WebGLTextureUtils.js +115 -0
- package/Resources/WebLibraries/three/addons/utils/WebGPUTextureUtils.js +81 -0
- package/Resources/WebLibraries/three/addons/utils/WorkerPool.js +167 -0
- package/Resources/WebLibraries/three/addons/utils/unwrapUVs.js +865 -0
- package/Resources/WebLibraries/three/three.core.js +61162 -0
- package/Resources/WebLibraries/three/three.module.js +19537 -0
- package/Resources/WebLibraries/three/three.tsl.js +41903 -0
- package/Resources/WebLibraries/three/three.webgpu.js +53714 -0
- package/Resources/share-rules.json +64 -0
- package/Resources/skills/2d-game/SKILL.md +305 -0
- package/Resources/skills/3d-game/SKILL.md +274 -0
- package/Resources/skills/accounts/SKILL.md +41 -0
- package/Resources/skills/android-design/SKILL.md +159 -0
- package/Resources/skills/app-ai/SKILL.md +154 -0
- package/Resources/skills/app-intents/SKILL.md +31 -0
- package/Resources/skills/app-kinds/SKILL.md +122 -0
- package/Resources/skills/apple-watch/SKILL.md +43 -0
- package/Resources/skills/assets/SKILL.md +183 -0
- package/Resources/skills/building-blocks/SKILL.md +97 -0
- package/Resources/skills/device-control/SKILL.md +56 -0
- package/Resources/skills/device-integrations/SKILL.md +278 -0
- package/Resources/skills/finder-files/SKILL.md +19 -0
- package/Resources/skills/game/SKILL.md +416 -0
- package/Resources/skills/game-3d/SKILL.md +12 -0
- package/Resources/skills/game-art/SKILL.md +11 -0
- package/Resources/skills/game-feel/SKILL.md +13 -0
- package/Resources/skills/game-levels/SKILL.md +12 -0
- package/Resources/skills/game-live/SKILL.md +12 -0
- package/Resources/skills/game-physics/SKILL.md +13 -0
- package/Resources/skills/game-playtest/SKILL.md +26 -0
- package/Resources/skills/game-ui/SKILL.md +278 -0
- package/Resources/skills/github-projects/SKILL.md +62 -0
- package/Resources/skills/icloud-sync/SKILL.md +30 -0
- package/Resources/skills/iphone-hardware/SKILL.md +57 -0
- package/Resources/skills/iphone-widgets/SKILL.md +53 -0
- package/Resources/skills/lg-developer-mode/SKILL.md +152 -0
- package/Resources/skills/mac-widgets/SKILL.md +60 -0
- package/Resources/skills/maps/SKILL.md +8 -0
- package/Resources/skills/menu-bar/SKILL.md +36 -0
- package/Resources/skills/more-apps/SKILL.md +53 -0
- package/Resources/skills/phone-controllers/SKILL.md +79 -0
- package/Resources/skills/phone-pages/SKILL.md +173 -0
- package/Resources/skills/roku-developer-mode/SKILL.md +106 -0
- package/Resources/skills/scene-3d/SKILL.md +27 -0
- package/Resources/skills/scripting/SKILL.md +17 -0
- package/Resources/skills/share-extension/SKILL.md +22 -0
- package/Resources/skills/tv-design/SKILL.md +72 -0
- package/Resources/skills/web-app/SKILL.md +170 -0
- package/Resources/skills/web-game/SKILL.md +95 -0
- package/Resources/skills/web-or-native/SKILL.md +108 -0
- package/Resources/skills/wish-links/SKILL.md +156 -0
- package/THIRD_PARTY_NOTICES.md +170 -0
- package/cli/ai.mjs +237 -0
- package/cli/android.mjs +941 -0
- package/cli/app-ai.mjs +473 -0
- package/cli/browser.mjs +284 -0
- package/cli/calls.mjs +594 -0
- package/cli/dev.mjs +820 -0
- package/cli/devices.mjs +984 -0
- package/cli/lamp.mjs +1326 -0
- package/cli/lampapp.mjs +332 -0
- package/cli/lamps/android-host/LampPageGateway.kt +345 -0
- package/cli/lamps/android-host/app/build.gradle.kts +40 -0
- package/cli/lamps/android-host/build.gradle.kts +4 -0
- package/cli/lamps/android-host/game/AndroidManifest.xml +33 -0
- package/cli/lamps/android-host/game/MainActivity.kt +173 -0
- package/cli/lamps/android-host/gradle/libs.versions.toml +39 -0
- package/cli/lamps/android-host/gradle.properties +8 -0
- package/cli/lamps/android-host/page/AndroidManifest.xml +35 -0
- package/cli/lamps/android-host/page/MainActivity.kt +193 -0
- package/cli/lamps/android-host/settings.gradle.kts +30 -0
- package/cli/lamps/android-host/tools.json +43 -0
- package/cli/lamps/lamp-controllers.js +2 -0
- package/cli/lamps/lamp-for-games.js +6922 -0
- package/cli/lamps/lamp.js +7082 -0
- package/cli/lamps/mac-starter/.lamp/meta.json +1 -0
- package/cli/lamps/mac-starter/APP.md +12 -0
- package/cli/lamps/mac-starter/Package.swift +8 -0
- package/cli/lamps/mac-starter/Sources/App.swift +11 -0
- package/cli/lamps/mac-starter/Sources/ContentView.swift +17 -0
- package/cli/lamps/mac-starter/Sources/LampSupport.swift +18215 -0
- package/cli/lamps/mac-starter/build.sh +336 -0
- package/cli/lamps/mac-starter/gitignore +3 -0
- package/cli/lamps/mac-starter/lamp-starter.json +6 -0
- package/cli/lamps/web-starter/APP.md +8 -0
- package/cli/lamps/web-starter/app.js +1 -0
- package/cli/lamps/web-starter/index.html +17 -0
- package/cli/lamps/web-starter/lamp-starter.json +5 -0
- package/cli/lamps/web-starter/lamp.js +7082 -0
- package/cli/lamps/web-starter/style.css +25 -0
- package/cli/link.mjs +202 -0
- package/cli/local-ai.mjs +193 -0
- package/cli/mac.mjs +621 -0
- package/cli/mdns.mjs +205 -0
- package/cli/msix.mjs +413 -0
- package/cli/network.mjs +209 -0
- package/cli/openrouter.mjs +133 -0
- package/cli/outside.mjs +203 -0
- package/cli/page.js +317 -0
- package/cli/place.mjs +298 -0
- package/cli/png.mjs +184 -0
- package/cli/share.mjs +270 -0
- package/cli/skill/SKILL.md +280 -0
- package/cli/skills.mjs +71 -0
- package/cli/state.mjs +176 -0
- package/cli/update.mjs +162 -0
- package/package.json +20 -4
- package/site/lib/quota.js +59 -0
- package/site/lib/shared-wishes.js +1727 -0
package/cli/calls.mjs
ADDED
|
@@ -0,0 +1,594 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// What Lamp's app asks of lamp. The work that's lamp's own (this folder) is done here once, and Lamp's app has it done
|
|
3
|
+
// (`LampCLI`, in Swift) rather than doing it a second time itself. Each call is one run of this file: the call's name
|
|
4
|
+
// is its one argument, what it's given is one JSON object on standard input (never in the arguments, which any
|
|
5
|
+
// process on the computer can list), and its answer is the last line it prints, one JSON object: {"done": …}, or
|
|
6
|
+
// {"problem": "…"} for something the person can put right, said in a sentence. Anything else that goes wrong ends
|
|
7
|
+
// the run with its own words on standard error.
|
|
8
|
+
//
|
|
9
|
+
// A call works on what Lamp's app hands it from Lamp's own folders, by path. It's never pointed at an app's folder:
|
|
10
|
+
// what's there is the agent's to write, and Lamp's app reads it its own way before anything comes here.
|
|
11
|
+
//
|
|
12
|
+
// Run with --serve in the place of a call's name, it stays: each line on standard input is {"id", "call", "given"},
|
|
13
|
+
// and each is answered, in whatever order they finish, by a line {"id", "done"} or {"id", "problem"}, or {"id",
|
|
14
|
+
// "failed"} with lamp's own words for anything else. A line {"stop": id} lets go of a call that hasn't answered, when
|
|
15
|
+
// whoever asked no longer wants it. It ends when its input does, which is when Lamp's app does. The many small things
|
|
16
|
+
// go this way (a request to a device), so each doesn't wait for a program to start.
|
|
17
|
+
//
|
|
18
|
+
// Lamp's app runs this on the JavaScript runtime it carries (the Bun its bundled agent is built on), and a test run on
|
|
19
|
+
// Node: what's imported here, and by what it imports, has to run on both.
|
|
20
|
+
|
|
21
|
+
import { lstatSync, mkdirSync, readdirSync, readFileSync, realpathSync, renameSync, writeFileSync } from "node:fs";
|
|
22
|
+
import { dirname, join } from "node:path";
|
|
23
|
+
import { fileURLToPath } from "node:url";
|
|
24
|
+
import { Away, OffNetwork, Refused, Rejected, Runner, StillWorking, answersOn, bonjour, pinsAt, searchNetwork, send, ssdp } from "./devices.mjs";
|
|
25
|
+
import { adbCommand, connectTo, deviceListing, deviceProperties, displaySizeOf, dumpIn, installApk, installTools, launchApp, makeEmulator, pairWith, processIn, processOf,
|
|
26
|
+
rowsOf, saveState, screenItems, screenshotOf, tellApp, toolsThere, useLamps } from "./android.mjs";
|
|
27
|
+
import { accountFor, keepAccount } from "./share.mjs";
|
|
28
|
+
import { Unreachable, accountName, askAccount, ideasOf, latestOf, pageUp, makerOf, publishLink, removeFile, removeIdea, removeLink, replyIdea, sendFile } from "./link.mjs";
|
|
29
|
+
import { defaultRoute, homeNetwork, neighbours, samsungAt, subnetOn, tvsIn } from "./network.mjs";
|
|
30
|
+
import { PUBLISHER, identityName, keptSigner, namesOf, packageOf, versionAfter } from "./msix.mjs";
|
|
31
|
+
import { tile } from "./png.mjs";
|
|
32
|
+
import { Problem } from "./state.mjs";
|
|
33
|
+
import { allowed as pagesAllowed, forgetPage, serveLocalAI } from "./local-ai.mjs";
|
|
34
|
+
import { EngineTrouble, complete } from "./ai.mjs";
|
|
35
|
+
import { OpenRouterTrouble, chat as openRouterChat, decide as openRouterDecide, image as openRouterImage, text as openRouterText } from "./openrouter.mjs";
|
|
36
|
+
|
|
37
|
+
/** OpenRouter's answer, or what kept it from one, as Lamp's app reads it. */
|
|
38
|
+
async function openRouter(asking) {
|
|
39
|
+
try { return await asking(); } catch (error) {
|
|
40
|
+
if (!(error instanceof OpenRouterTrouble)) throw error;
|
|
41
|
+
return { trouble: { kind: error.kind, message: error.message, status: error.status, reply: error.reply, cost: error.cost } };
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
import { Refused as StepRefused, chatBody, decidePrompt, planPrompt, planSchema, readDecision, readMessage, readPlan, readStep } from "./app-ai.mjs";
|
|
45
|
+
|
|
46
|
+
// Pages shared on lamp.dev asking for their AI, answered by Lamp's app (`sharedPages`): what each is waiting on from it.
|
|
47
|
+
const sharedPagesWaiting = new Map();
|
|
48
|
+
let sharedPagesAsked = 0;
|
|
49
|
+
|
|
50
|
+
/** A number of seconds a call was given, within what it may take. */
|
|
51
|
+
const seconds = (given, standard, most = 10) => Math.min(Math.max(Number(given) > 0 ? Number(given) : standard, 0.5), most);
|
|
52
|
+
|
|
53
|
+
const text = (given, name) => {
|
|
54
|
+
if (typeof given[name] !== "string" || !given[name]) throw new Error(`the call needs "${name}"`);
|
|
55
|
+
return given[name];
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/** Every file in a folder, by its path from the folder's top, in a settled order. A link is never followed: it's refused. */
|
|
59
|
+
function filesIn(folder) {
|
|
60
|
+
const files = [];
|
|
61
|
+
const walk = (at, prefix) => {
|
|
62
|
+
for (const name of readdirSync(at).sort()) {
|
|
63
|
+
const file = join(at, name), kind = lstatSync(file);
|
|
64
|
+
if (kind.isSymbolicLink()) throw new Problem(`${prefix}${name} is a shortcut to another file. Put the file itself in its place`);
|
|
65
|
+
if (kind.isDirectory()) walk(file, `${prefix}${name}/`);
|
|
66
|
+
else if (kind.isFile()) files.push([prefix + name, readFileSync(file)]);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
walk(folder, "");
|
|
70
|
+
return files;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Written whole or not at all: beside its place, then moved in. */
|
|
74
|
+
function write(file, bytes, mode) {
|
|
75
|
+
mkdirSync(dirname(file), { recursive: true });
|
|
76
|
+
const beside = `${file}.writing`;
|
|
77
|
+
writeFileSync(beside, bytes, mode ? { mode } : undefined);
|
|
78
|
+
renameSync(beside, file);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* The runner for an integration's device, as Lamp's app hands it over: the integration (its JSON), the device (its
|
|
83
|
+
* id, name and address), the values to fill in (what the person typed among them, kept by Lamp's app), the file its
|
|
84
|
+
* certificates are kept in, and where a key it gives is kept. `event` tells whoever asked each time the device is
|
|
85
|
+
* waited on; `stopped` ends the run.
|
|
86
|
+
*/
|
|
87
|
+
function runnerOf(given, { stopped, event = () => {} } = {}) {
|
|
88
|
+
if (typeof given.integration?.id !== "string" || typeof given.device?.id !== "string") throw new Error('the call needs "integration" and "device"');
|
|
89
|
+
return new Runner({ integration: given.integration, device: { id: given.device.id, name: String(given.device.name ?? "The device"), address: given.device.address },
|
|
90
|
+
values: given.values ?? {}, pins: pinsAt(text(given, "pins")), keyFile: typeof given.keyFile === "string" ? given.keyFile : undefined,
|
|
91
|
+
stopped, onWaiting: () => event({ waiting: true }) });
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** What a sequence gave back, as Lamp's app reads it: a picture in base64, and the cookies its next part sends back. */
|
|
95
|
+
const outcomeOf = (outcome) => ({ ...outcome, picture: outcome.picture ? Buffer.from(outcome.picture).toString("base64") : null });
|
|
96
|
+
|
|
97
|
+
/** A shared link as Lamp's app keeps it: its id and secret, and the site it's on. */
|
|
98
|
+
const linkOf = (given) => ({ id: text(given, "id"), secret: text(given, "secret") });
|
|
99
|
+
const siteOf = (given) => text(given, "site").replace(/\/+$/, "");
|
|
100
|
+
|
|
101
|
+
/** Lamp's app's Android, handed over with every adb call: its tools list, folders and environment (its own adb server and key). */
|
|
102
|
+
const androidFor = (given) => useLamps(given.lamp ?? {});
|
|
103
|
+
const serialOf = (given) => text(given, "serial");
|
|
104
|
+
|
|
105
|
+
export const CALLS = {
|
|
106
|
+
/** One adb command for Lamp's app (`args` after the serial), with `input` on adb's input when given: what it said. */
|
|
107
|
+
async adb(given) {
|
|
108
|
+
androidFor(given);
|
|
109
|
+
return adbCommand(Array.isArray(given.args) ? given.args.map(String) : [], { serial: typeof given.serial === "string" ? given.serial : undefined,
|
|
110
|
+
timeout: Math.round((Number(given.timeout) > 0 ? Number(given.timeout) : 60) * 1000), input: typeof given.input === "string" ? given.input : undefined });
|
|
111
|
+
},
|
|
112
|
+
/** The devices adb can see, each with what it says of itself when it's ready, and what adb's search sees on the network. */
|
|
113
|
+
async androidDevices(given) { androidFor(given); return deviceListing(); },
|
|
114
|
+
/** adb's listing read into rows, for what Lamp's app was handed some other way. */
|
|
115
|
+
async androidRows(given) { return { rows: rowsOf(text(given, "listing")) }; },
|
|
116
|
+
/** What one device says of itself now. */
|
|
117
|
+
async androidProperties(given) { androidFor(given); return { properties: await deviceProperties(serialOf(given)) }; },
|
|
118
|
+
async androidConnect(given) { androidFor(given); return { connected: await connectTo(text(given, "target")) }; },
|
|
119
|
+
/** Pairs with a device by its code, which comes on the call's input and goes on adb's. */
|
|
120
|
+
async androidPair(given) { androidFor(given); return { pairing: await pairWith(text(given, "host"), Number(given.port), text(given, "code")) }; },
|
|
121
|
+
async androidInstallApp(given) { androidFor(given); await installApk(serialOf(given), text(given, "apk"), text(given, "package")); return {}; },
|
|
122
|
+
async androidTell(given) { androidFor(given); return { problem: await tellApp(serialOf(given), text(given, "package"), given.values ?? {}) }; },
|
|
123
|
+
async androidSaveState(given) { androidFor(given); return { saved: await saveState(serialOf(given), text(given, "package")) }; },
|
|
124
|
+
async androidLaunch(given) { androidFor(given); return { pid: await launchApp(serialOf(given), text(given, "package")) }; },
|
|
125
|
+
/** Whether the app runs on the device: running (with its process), gone, or unreachable. With `said`, what pidof said, read without asking. */
|
|
126
|
+
async androidProcess(given) {
|
|
127
|
+
if (given.said) return processIn(given.said);
|
|
128
|
+
androidFor(given);
|
|
129
|
+
return processOf(serialOf(given), text(given, "package"));
|
|
130
|
+
},
|
|
131
|
+
/** The screen as a PNG in base64, a pixel to a point by the device's density. */
|
|
132
|
+
async androidScreenshot(given) {
|
|
133
|
+
androidFor(given);
|
|
134
|
+
const png = await screenshotOf(serialOf(given), given.density);
|
|
135
|
+
return { png: png ? png.toString("base64") : null };
|
|
136
|
+
},
|
|
137
|
+
async androidDisplaySize(given) { androidFor(given); return { size: await displaySizeOf(serialOf(given)) }; },
|
|
138
|
+
/** The screen's dump, as `uiautomator dump` gave it (`said`), read into what's on it, in points at `scale`; null items when it held no dump. */
|
|
139
|
+
async androidScreenItems(given) {
|
|
140
|
+
const xml = dumpIn(text(given, "said"));
|
|
141
|
+
return { items: xml ? screenItems(xml, Number(given.scale) > 0 ? Number(given.scale) : 1) : null };
|
|
142
|
+
},
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Downloads whichever of Android's tools Lamp's app is missing, into its tools folder, as its tools list says (each
|
|
147
|
+
* archive checked against what its maker publishes, then Google's packages through its own package manager, which
|
|
148
|
+
* accepts Google's terms for them: only when the person asked). With `emulator`, the emulator and its phone's image
|
|
149
|
+
* too; with `tv`, the TV's image. `lamp` is Lamp's app's tools list, folders and environment. Tells how far along it
|
|
150
|
+
* is (`part`, 0 to 1) and what it's doing (`said`) as it goes; answers which tools are there.
|
|
151
|
+
*/
|
|
152
|
+
async androidInstall(given, how = {}) {
|
|
153
|
+
useLamps(given.lamp ?? {});
|
|
154
|
+
return { there: await installTools({ emulator: given.emulator === true, tv: given.tv === true,
|
|
155
|
+
said: (line) => how.event?.({ said: line }), progress: (part) => how.event?.({ part }) }) };
|
|
156
|
+
},
|
|
157
|
+
|
|
158
|
+
/** Makes Lamp's app's emulator of a kind ("phone" or "tv") from its downloaded system image. */
|
|
159
|
+
async androidMakeEmulator(given) {
|
|
160
|
+
useLamps(given.lamp ?? {});
|
|
161
|
+
if (given.kind !== "phone" && given.kind !== "tv") throw new Error('the call needs "kind": "phone" or "tv"');
|
|
162
|
+
await makeEmulator(given.kind);
|
|
163
|
+
return { there: toolsThere() };
|
|
164
|
+
},
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Shares a wish's link, or changes what it shows (`earlier`: its id and secret), on `site`, with `body` as the site
|
|
169
|
+
* takes it. Its id, address and secret.
|
|
170
|
+
*/
|
|
171
|
+
async linkPublish(given) {
|
|
172
|
+
const earlier = given.earlier && typeof given.earlier.id === "string" ? given.earlier : null;
|
|
173
|
+
// Sent with the maker's account key, the one `lamp account` keeps, unless the call names another: the link goes
|
|
174
|
+
// under their username once it's confirmed.
|
|
175
|
+
const site = siteOf(given);
|
|
176
|
+
return publishLink({ site, body: given.body ?? {}, earlier, account: typeof given.account === "string" ? given.account : accountFor(site)?.key });
|
|
177
|
+
},
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* The maker's account on `site`, as lamp keeps it: `account` null with none, else its username, the address that
|
|
181
|
+
* confirms it, and `confirmed` (null when the site can't be asked just now).
|
|
182
|
+
*/
|
|
183
|
+
async account(given) {
|
|
184
|
+
const site = siteOf(given);
|
|
185
|
+
const kept = accountFor(site);
|
|
186
|
+
if (!kept) return { account: null };
|
|
187
|
+
let name;
|
|
188
|
+
try { name = await accountName({ site, key: kept.key }); } catch { return { account: { username: kept.username, email: kept.email ?? null, confirmed: null } }; }
|
|
189
|
+
// An address signing in to its account learns the username only once it's confirmed.
|
|
190
|
+
if (name && name !== kept.username) keepAccount(site, { ...kept, username: name });
|
|
191
|
+
return { account: { username: name ?? kept.username, email: kept.email ?? null, confirmed: !!name } };
|
|
192
|
+
},
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Asks `site` for an account (`username`, `email`), or with an address alone, to sign in to the one it has; the key is
|
|
196
|
+
* kept as `lamp account` keeps it, and works once the email's link is opened. Its username and whether the email went.
|
|
197
|
+
*/
|
|
198
|
+
async accountAsk(given) {
|
|
199
|
+
const site = siteOf(given);
|
|
200
|
+
const email = text(given, "email");
|
|
201
|
+
const asked = await askAccount({ site, username: typeof given.username === "string" && given.username ? given.username : undefined, email });
|
|
202
|
+
keepAccount(site, { username: asked.username, key: asked.key, email });
|
|
203
|
+
return { username: asked.username ?? null, existing: !!asked.existing, sent: asked.sent !== false };
|
|
204
|
+
},
|
|
205
|
+
|
|
206
|
+
/** Forgets the maker's account on `site` here (the one waiting for a mistyped address, say). */
|
|
207
|
+
async accountForget(given) {
|
|
208
|
+
keepAccount(siteOf(given), undefined);
|
|
209
|
+
return {};
|
|
210
|
+
},
|
|
211
|
+
|
|
212
|
+
/** What a followed link has now, asked with nothing of the person's; `latest` null when it can't be asked or is gone. */
|
|
213
|
+
async linkLatest(given) {
|
|
214
|
+
return { latest: await latestOf({ site: siteOf(given), id: text(given, "id") }) };
|
|
215
|
+
},
|
|
216
|
+
|
|
217
|
+
/** The link's file (or with `page`, its playable page), from a file of Lamp's at `file`, sent in parts. */
|
|
218
|
+
async linkUpload(given, how = {}) {
|
|
219
|
+
const said = (line) => how.event?.({ said: line });
|
|
220
|
+
const version = await sendFile({ site: siteOf(given), link: linkOf(given), bytes: readFileSync(text(given, "file")), page: given.page === true, said });
|
|
221
|
+
if (given.page === true) await pageUp({ site: siteOf(given), id: linkOf(given).id, version, said });
|
|
222
|
+
return { version };
|
|
223
|
+
},
|
|
224
|
+
|
|
225
|
+
/** Takes the link's file away (with `page`, only its page). */
|
|
226
|
+
async linkRemoveFile(given) {
|
|
227
|
+
await removeFile({ site: siteOf(given), link: linkOf(given), page: given.page === true });
|
|
228
|
+
return {};
|
|
229
|
+
},
|
|
230
|
+
|
|
231
|
+
/** The ideas sent to the link that are still open or answered since; with `earlier`, those seen to. */
|
|
232
|
+
async linkIdeas(given) {
|
|
233
|
+
return { ideas: await ideasOf({ site: siteOf(given), link: linkOf(given), earlier: given.earlier === true }) };
|
|
234
|
+
},
|
|
235
|
+
|
|
236
|
+
/** Lets an idea go; with `built` it's in, and the site writes to whoever asked to hear, with `note` if there is one. */
|
|
237
|
+
async linkRemoveIdea(given) {
|
|
238
|
+
const note = typeof given.note === "string" && given.note.trim() ? given.note.trim() : undefined;
|
|
239
|
+
return removeIdea({ site: siteOf(given), link: linkOf(given), n: Number(given.n), built: given.built === true, note });
|
|
240
|
+
},
|
|
241
|
+
|
|
242
|
+
/** Says something more about an idea, emailed to its sender if they gave an address; without `note`, it's seen to. */
|
|
243
|
+
async linkReplyIdea(given) {
|
|
244
|
+
const note = typeof given.note === "string" && given.note.trim() ? given.note.trim() : undefined;
|
|
245
|
+
return replyIdea({ site: siteOf(given), link: linkOf(given), n: Number(given.n), note });
|
|
246
|
+
},
|
|
247
|
+
|
|
248
|
+
/** The maker's own address for the link's ideas; with `email` (a string, "" for none), given, to be confirmed. */
|
|
249
|
+
async linkMaker(given) {
|
|
250
|
+
return makerOf({ site: siteOf(given), link: linkOf(given), ...(typeof given.email === "string" ? { email: given.email.trim() } : {}) });
|
|
251
|
+
},
|
|
252
|
+
|
|
253
|
+
/** Takes the link down. */
|
|
254
|
+
async linkRemove(given) {
|
|
255
|
+
await removeLink({ site: siteOf(given), link: linkOf(given) });
|
|
256
|
+
return {};
|
|
257
|
+
},
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* One part of an integration's sequence on a device (`sequence`: its requests, waits and probes; what only Lamp's
|
|
262
|
+
* app does, a command on the device or a sign-in page, is between parts), with `cookies` from the part before. The
|
|
263
|
+
* settings it changes for itself (`restore`) come back in `changed`, which Lamp's app hands to `putBack` once it's
|
|
264
|
+
* done with them, or they're put back as the part ends when it asks for that (`putBack: true`).
|
|
265
|
+
*/
|
|
266
|
+
async run(given, how = {}) {
|
|
267
|
+
const runner = runnerOf(given, how), changed = Array.isArray(given.changed) ? given.changed : [], before = changed.length;
|
|
268
|
+
try {
|
|
269
|
+
const outcome = await runner.run(Array.isArray(given.sequence) ? given.sequence : [], { extra: given.extra ?? {}, files: given.files ?? {}, changed, cookies: given.cookies ?? {} });
|
|
270
|
+
if (given.putBack === true) await runner.putBack(changed);
|
|
271
|
+
return { outcome: outcomeOf(outcome), changed };
|
|
272
|
+
} catch (error) {
|
|
273
|
+
// A part that fails puts back what it changed itself: the answer that says so carries no settings to hand back.
|
|
274
|
+
await runner.putBack(changed.splice(before));
|
|
275
|
+
throw error;
|
|
276
|
+
}
|
|
277
|
+
},
|
|
278
|
+
|
|
279
|
+
/** Puts back what parts of a sequence changed for themselves (`changed`, as `run` gave it), last first: the settings it couldn't. */
|
|
280
|
+
async putBack(given, how = {}) {
|
|
281
|
+
return { missed: await runnerOf(given, how).putBack(Array.isArray(given.changed) ? given.changed : []) };
|
|
282
|
+
},
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Opens an app just put on the device: `launch`, then `running` until it's seen running, launched again while the
|
|
286
|
+
* device refuses or doesn't open it, up to `tries` launches. Whether it opened, whether it was ever launched, and
|
|
287
|
+
* what the device last refused with.
|
|
288
|
+
*/
|
|
289
|
+
async open(given, how = {}) {
|
|
290
|
+
const changed = Array.isArray(given.changed) ? given.changed : [];
|
|
291
|
+
const opened = await runnerOf(given, how).open(given.launch ?? [], given.running ?? null, { extra: given.extra ?? {}, changed, tries: Number.isInteger(given.tries) ? given.tries : 8 });
|
|
292
|
+
return { ...opened, refused: opened.refused ?? null, changed };
|
|
293
|
+
},
|
|
294
|
+
|
|
295
|
+
/** What a check of a setup's `conditions` finds on the device now: holds, waiting, away or rejected, with why and what it read. */
|
|
296
|
+
async check(given, how = {}) {
|
|
297
|
+
return runnerOf(given, how).evaluate(Array.isArray(given.conditions) ? given.conditions : []);
|
|
298
|
+
},
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* A signed Windows package (msix.mjs) of the files in `payload`, a folder Lamp's app laid out, written to `out`, with
|
|
302
|
+
* the certificate a device installs beside it at `certificate`. The package is named for the app (`slug`) and is a
|
|
303
|
+
* newer version than `after`, the last one made; `entry` is what it starts ("webHost", {page} or {program}), `icon`
|
|
304
|
+
* a picture of the app for its tiles, and `signer` the folder lamp's key for packages is kept in, made the first time.
|
|
305
|
+
*/
|
|
306
|
+
msix(given) {
|
|
307
|
+
const entry = given.entry === "webHost" || typeof given.entry?.page === "string" || typeof given.entry?.program === "string" ? given.entry : null;
|
|
308
|
+
if (!entry) throw new Error('the call needs "entry": "webHost", {page} or {program}');
|
|
309
|
+
const identity = { name: identityName(text(given, "slug")), publisher: PUBLISHER, version: versionAfter(typeof given.after === "string" ? given.after : undefined) };
|
|
310
|
+
if (typeof given.architecture === "string") identity.architecture = given.architecture;
|
|
311
|
+
let icon = null;
|
|
312
|
+
if (typeof given.icon === "string") { try { icon = readFileSync(given.icon); } catch { /* the tile's color alone */ } }
|
|
313
|
+
const payload = filesIn(text(given, "payload")), signer = keptSigner(text(given, "signer"));
|
|
314
|
+
const made = packageOf({ payload, displayName: text(given, "displayName"), identity, entry, logo: (width, height) => tile(icon, width, height), signer });
|
|
315
|
+
write(text(given, "out"), made);
|
|
316
|
+
write(text(given, "certificate"), signer.certificate);
|
|
317
|
+
return { identity, ...namesOf(identity), bytes: made.length, files: payload.length };
|
|
318
|
+
},
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* One request of an integration's to a device (devices.mjs's `send`, with every guard it has): `request` as the
|
|
322
|
+
* integration writes one, to the device at `address`, with `values` filled in (what the person typed for the device
|
|
323
|
+
* among them, which is why this comes on standard input), `files` it may send by path, and `pins`, the file the
|
|
324
|
+
* device's certificates are kept in, without which nothing secret goes over HTTPS. The answer's body is in base64.
|
|
325
|
+
*/
|
|
326
|
+
async send(given, { stopped } = {}) {
|
|
327
|
+
const answer = await send(given.request ?? {}, text(given, "address"), given.values ?? {}, {
|
|
328
|
+
files: given.files ?? {}, pins: typeof given.pins === "string" ? pinsAt(given.pins) : undefined,
|
|
329
|
+
timeout: Math.round((Number(given.timeout) > 0 ? Number(given.timeout) : 30) * 1000), stopped,
|
|
330
|
+
});
|
|
331
|
+
return { status: answer.status, body: answer.body.toString("base64"), cookies: answer.cookies, certificate: answer.certificate?.toString("base64") ?? null };
|
|
332
|
+
},
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* One look at the home network for the `integrations` Lamp's app has (each as its JSON): every answer to a search
|
|
336
|
+
* for everything, what each integration found and read of its devices, with `unknown` the devices none of them
|
|
337
|
+
* knows, read from their own descriptions, and with `tvs` what each Samsung or LG TV that answered says of itself.
|
|
338
|
+
* Which of those Lamp keeps, and what it called them, is Lamp's app's.
|
|
339
|
+
*/
|
|
340
|
+
async look(given) {
|
|
341
|
+
const list = (Array.isArray(given.integrations) ? given.integrations : []).filter((integration) => typeof integration?.id === "string");
|
|
342
|
+
const answers = await ssdp("ssdp:all", seconds(given.seconds, 2.5));
|
|
343
|
+
const [seen, tvs] = await Promise.all([searchNetwork({ integrations: list, answers, unknown: given.unknown === true }), given.tvs === true ? tvsIn(answers) : []]);
|
|
344
|
+
return { ...seen, tvs };
|
|
345
|
+
},
|
|
346
|
+
|
|
347
|
+
/** What a Samsung TV at `address` says of itself now, as the look reads it; null when it doesn't answer as one. */
|
|
348
|
+
async tv(given) {
|
|
349
|
+
return { tv: await samsungAt(text(given, "address")) };
|
|
350
|
+
},
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Everything on this computer's subnet besides what the look finds: each host with its hardware address and its
|
|
354
|
+
* Bonjour services, and which subnet was swept.
|
|
355
|
+
*/
|
|
356
|
+
async network(given) {
|
|
357
|
+
return homeNetwork({ seconds: seconds(given.seconds, 3) });
|
|
358
|
+
},
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* The network as it is now, read with nothing sent: this computer's neighbor table (each neighbor's IPv4 address
|
|
362
|
+
* and hardware address), its gateway, and the subnet a sweep would take.
|
|
363
|
+
*/
|
|
364
|
+
async neighbours() {
|
|
365
|
+
const route = await defaultRoute();
|
|
366
|
+
return { table: await neighbours(), gateway: route?.gateway ?? null, subnet: route ? subnetOn(route.interface) : null };
|
|
367
|
+
},
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* A text answer from OpenRouter for an app's AI (`AppAI.viaOpenRouter`), with the person's `key`, given on the input
|
|
371
|
+
* like everything else and kept nowhere: `prompt`, `images`, `system`, `model`, `json`, `schema`. `{text, cost}`, or
|
|
372
|
+
* `{trouble: {kind, message, status, reply, cost}}`.
|
|
373
|
+
*/
|
|
374
|
+
async openRouterText(given, { stopped } = {}) {
|
|
375
|
+
return openRouter(() => openRouterText({ key: text(given, "key"), prompt: text(given, "prompt"), images: given.images, system: given.system ?? "",
|
|
376
|
+
model: text(given, "model"), json: given.json === true, schema: given.schema ?? undefined, seconds: seconds(given.seconds, 120, 600), signal: stopped }));
|
|
377
|
+
},
|
|
378
|
+
|
|
379
|
+
/** One chat completion from OpenRouter, its request as `body` (`actAsk`'s): `{message, cost}`, or `{trouble}`. */
|
|
380
|
+
async openRouterChat(given, { stopped } = {}) {
|
|
381
|
+
return openRouter(() => openRouterChat({ key: text(given, "key"), body: given.body ?? {}, seconds: seconds(given.seconds, 60, 600), signal: stopped }));
|
|
382
|
+
},
|
|
383
|
+
|
|
384
|
+
/** Decisions from OpenRouter's decision model (`AppAI.decide`): `key`, `model`, `state`, `questions`. `{answers, cost}` or `{trouble}`. */
|
|
385
|
+
async openRouterDecide(given, { stopped } = {}) {
|
|
386
|
+
return openRouter(() => openRouterDecide({ key: text(given, "key"), model: text(given, "model"), state: given.state, questions: given.questions ?? {},
|
|
387
|
+
seconds: seconds(given.seconds, 60, 120), signal: stopped }));
|
|
388
|
+
},
|
|
389
|
+
|
|
390
|
+
/** A picture from OpenRouter (`AppAI.image`): `key`, `model`, `prompt`, `references`, `aspectRatio`. `{image, cost}` or `{trouble}`. */
|
|
391
|
+
async openRouterImage(given, { stopped } = {}) {
|
|
392
|
+
return openRouter(() => openRouterImage({ key: text(given, "key"), model: text(given, "model"), prompt: text(given, "prompt"),
|
|
393
|
+
references: given.references, aspectRatio: typeof given.aspectRatio === "string" ? given.aspectRatio : undefined, seconds: seconds(given.seconds, 240, 300), signal: stopped }));
|
|
394
|
+
},
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* One answer from Claude Code or Codex for an app's AI (`AppAI.viaEngine`), sealed as ai.mjs runs every one: `engine`,
|
|
398
|
+
* the program Lamp chose (`tool`) and what it needs set (`env`), `system`, `prompt`, optional `schema`, `model`,
|
|
399
|
+
* `images` and `seconds`. `{text}`, or `{trouble: {kind, message}}`; stopping the call stops the engine.
|
|
400
|
+
*/
|
|
401
|
+
async engineAnswer(given, { stopped } = {}) {
|
|
402
|
+
try {
|
|
403
|
+
return { text: await complete({ which: text(given, "engine"), tool: typeof given.tool === "string" && given.tool ? given.tool : undefined,
|
|
404
|
+
env: given.env && typeof given.env === "object" ? given.env : {}, system: typeof given.system === "string" ? given.system : "",
|
|
405
|
+
prompt: text(given, "prompt"), schema: given.schema ?? undefined, model: typeof given.model === "string" ? given.model : "",
|
|
406
|
+
images: Array.isArray(given.images) ? given.images : [], seconds: seconds(given.seconds, 300, 600), signal: stopped }) };
|
|
407
|
+
} catch (error) {
|
|
408
|
+
if (error instanceof EngineTrouble) return { trouble: { kind: error.kind, message: error.message } };
|
|
409
|
+
throw error;
|
|
410
|
+
}
|
|
411
|
+
},
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* A step of an app's `LampAI.act` as the page sent it (`text`, its JSON), checked: `{step}`, the step as the other
|
|
415
|
+
* act calls take it, or `{refused: {status, error}}` for the page.
|
|
416
|
+
*/
|
|
417
|
+
async actStep(given) {
|
|
418
|
+
try { return { step: readStep(text(given, "text")) }; } catch (error) {
|
|
419
|
+
if (error instanceof StepRefused) return { refused: { status: error.status, error: error.message } };
|
|
420
|
+
throw error;
|
|
421
|
+
}
|
|
422
|
+
},
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* What a step's route is asked: `way` "chat" is a chat with tools (`{body}`, OpenRouter's own when `model` names one),
|
|
426
|
+
* "plan" one prompt held to the step's shape (`{system, prompt, schema}`), and "words" one with the shape said in it.
|
|
427
|
+
*/
|
|
428
|
+
async actAsk(given) {
|
|
429
|
+
const step = given.step, tag = text(given, "tag"), retry = typeof given.retry === "string" ? given.retry : null;
|
|
430
|
+
if (given.way === "chat") return { body: chatBody(step, tag, retry, typeof given.model === "string" ? given.model : undefined) };
|
|
431
|
+
return { ...planPrompt(step, tag, retry, given.way === "words"), schema: planSchema(step) };
|
|
432
|
+
},
|
|
433
|
+
|
|
434
|
+
/** A step's answer read and checked: `message` from a chat with tools, or `plan`'s text. `{answer}` or `{problem}`. */
|
|
435
|
+
async actRead(given) {
|
|
436
|
+
return given.message !== undefined ? readMessage(given.message, given.step) : readPlan(String(given.plan ?? ""), given.step);
|
|
437
|
+
},
|
|
438
|
+
|
|
439
|
+
/** A decision asked of a text model: `{system, prompt, schema}`. */
|
|
440
|
+
async decideAsk(given) {
|
|
441
|
+
return decidePrompt(given.state, given.questions ?? {});
|
|
442
|
+
},
|
|
443
|
+
|
|
444
|
+
/** A text model's decision read: `{answers}` or `{problem}`. */
|
|
445
|
+
async decideRead(given) {
|
|
446
|
+
return readDecision(String(given.text ?? ""), given.questions ?? {});
|
|
447
|
+
},
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* Answers the AI of pages shared on lamp.dev, played in a browser on this computer, as `lamp ai` does
|
|
451
|
+
* (local-ai.mjs), for as long as Lamp's app wants it: which pages are let in, and how, is lamp's alone. The person is
|
|
452
|
+
* asked by Lamp's app, and the AI is Lamp's: each is an event, `{ask: n, id, name}` or `{answer: n, path, body}`,
|
|
453
|
+
* which Lamp's app answers with `sharedPagesReply`. A problem when something else answers on this computer already.
|
|
454
|
+
*/
|
|
455
|
+
async sharedPages(given, { stopped, event } = {}) {
|
|
456
|
+
const fromLamp = (kind, fields) => new Promise((done) => {
|
|
457
|
+
const n = ++sharedPagesAsked;
|
|
458
|
+
sharedPagesWaiting.set(n, done);
|
|
459
|
+
event({ [kind]: n, ...fields });
|
|
460
|
+
});
|
|
461
|
+
let server;
|
|
462
|
+
try {
|
|
463
|
+
server = await serveLocalAI({
|
|
464
|
+
...(Number.isInteger(given.port) ? { port: given.port } : {}),
|
|
465
|
+
said: () => {},
|
|
466
|
+
ask: (_question, page) => fromLamp("ask", { id: page.id, name: page.name }).then((reply) => reply.yes === true),
|
|
467
|
+
answer: (path, body, page) => fromLamp("answer", { path, body, id: page.id }).then((reply) => [Number(reply.status) || 502, reply.reply ?? {}]),
|
|
468
|
+
});
|
|
469
|
+
} catch (error) {
|
|
470
|
+
if (error?.code === "EADDRINUSE") throw new Problem("lamp ai already answers shared pages' AI on this computer");
|
|
471
|
+
throw error;
|
|
472
|
+
}
|
|
473
|
+
await new Promise((done) => (stopped?.aborted ? done() : stopped?.addEventListener("abort", done)));
|
|
474
|
+
server.close();
|
|
475
|
+
return {};
|
|
476
|
+
},
|
|
477
|
+
|
|
478
|
+
/** The pages shared on lamp.dev allowed to use the AI here, for Settings: `{pages: [{origin, id, name, at}]}`, newest first. */
|
|
479
|
+
async sharedPagesAllowed() {
|
|
480
|
+
return { pages: Object.entries(pagesAllowed()).map(([origin, page]) => ({ origin, id: page.id, name: page.name, at: page.at }))
|
|
481
|
+
.sort((a, b) => String(b.at).localeCompare(String(a.at))) };
|
|
482
|
+
},
|
|
483
|
+
|
|
484
|
+
/** Takes back one page's leave to use the AI here (`origin`): it asks again the next time. */
|
|
485
|
+
async sharedPagesForget(given) {
|
|
486
|
+
forgetPage(text(given, "origin"));
|
|
487
|
+
return {};
|
|
488
|
+
},
|
|
489
|
+
|
|
490
|
+
/** Lamp's app's answer to what `sharedPages` asked it: `{n, yes}` or `{n, status, reply}`. */
|
|
491
|
+
async sharedPagesReply(given) {
|
|
492
|
+
const done = sharedPagesWaiting.get(given.n);
|
|
493
|
+
sharedPagesWaiting.delete(given.n);
|
|
494
|
+
done?.(given);
|
|
495
|
+
return {};
|
|
496
|
+
},
|
|
497
|
+
|
|
498
|
+
/** A search of the home network for one search target, for a few seconds: every answer. */
|
|
499
|
+
async search(given) {
|
|
500
|
+
return { answers: await ssdp(typeof given.target === "string" ? given.target : "ssdp:all", seconds(given.seconds, 2)) };
|
|
501
|
+
},
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* Whether the device at `address` is there now, as a step's check asks: it takes a connection on a port (`tcp`), it
|
|
505
|
+
* answers a search for a target (`ssdp`), or it offers a Bonjour service (`bonjour`).
|
|
506
|
+
*/
|
|
507
|
+
async probe(given) {
|
|
508
|
+
const address = text(given, "address");
|
|
509
|
+
if (Number.isInteger(given.tcp)) return { present: await answersOn(address, given.tcp, { timeout: seconds(given.seconds, 3) * 1000 }) };
|
|
510
|
+
if (typeof given.ssdp === "string") return { present: (await ssdp(given.ssdp, seconds(given.seconds, 2))).some((answer) => answer.address === address) };
|
|
511
|
+
if (typeof given.bonjour === "string") return { present: (await bonjour(given.bonjour, seconds(given.seconds, 3))).some((found) => found.address === address) };
|
|
512
|
+
throw new Error('the call needs "tcp", "ssdp" or "bonjour"');
|
|
513
|
+
},
|
|
514
|
+
};
|
|
515
|
+
|
|
516
|
+
/** A problem as Lamp's app shows one: a sentence, in which lamp is Lamp. */
|
|
517
|
+
const sentence = (words) => `${words[0].toUpperCase()}${words.slice(1)}${/[.!?]$/.test(words) ? "" : "."}`.replace(/\blamp\b/g, "Lamp");
|
|
518
|
+
|
|
519
|
+
/**
|
|
520
|
+
* What went wrong, as the answer says it: a problem the person can put right, with its kind where Lamp's app does
|
|
521
|
+
* something about that kind (a certificate that changed, a device that's away); null for anything else, lamp's own fault.
|
|
522
|
+
*/
|
|
523
|
+
function problemOf(error) {
|
|
524
|
+
if (!(error instanceof Problem)) return null;
|
|
525
|
+
const said = { problem: sentence(error.message) };
|
|
526
|
+
if (error instanceof Refused) said.kind = error.kind;
|
|
527
|
+
else if (error instanceof Rejected) said.kind = "rejected";
|
|
528
|
+
else if (error instanceof StillWorking) said.kind = "still-working";
|
|
529
|
+
else if (error instanceof OffNetwork) said.kind = "off-network";
|
|
530
|
+
else if (error instanceof Unreachable) said.kind = "unreachable";
|
|
531
|
+
else if (error instanceof Away) Object.assign(said, { kind: "away", code: error.code ?? null, timedOut: error.timedOut });
|
|
532
|
+
if (Number.isInteger(error.status)) said.status = error.status;
|
|
533
|
+
return said;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
/** One call, run to its end, as a single run of this file. */
|
|
537
|
+
async function once(name) {
|
|
538
|
+
const call = CALLS[name];
|
|
539
|
+
if (!call) throw new Error(`lamp has no call named "${name ?? ""}"`);
|
|
540
|
+
const chunks = [];
|
|
541
|
+
for await (const chunk of process.stdin) chunks.push(chunk);
|
|
542
|
+
const given = JSON.parse(Buffer.concat(chunks).toString("utf8") || "{}");
|
|
543
|
+
try {
|
|
544
|
+
console.log(JSON.stringify({ done: await call(given) }));
|
|
545
|
+
} catch (error) {
|
|
546
|
+
const said = problemOf(error);
|
|
547
|
+
if (!said) throw error;
|
|
548
|
+
console.log(JSON.stringify(said));
|
|
549
|
+
process.exitCode = 1;
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
/** Calls answered as they come, for as long as there's someone to ask. */
|
|
554
|
+
async function serve() {
|
|
555
|
+
const say = (line) => process.stdout.write(JSON.stringify(line) + "\n");
|
|
556
|
+
const under = new Map();
|
|
557
|
+
// A stop can overtake the call it's for (Lamp's app cancelled it as it was sent): it's kept, and the call starts stopped.
|
|
558
|
+
const early = new Set();
|
|
559
|
+
const answer = async (line) => {
|
|
560
|
+
let asked;
|
|
561
|
+
try { asked = JSON.parse(line); } catch { return; }
|
|
562
|
+
if (asked?.stop !== undefined) {
|
|
563
|
+
const stopping = under.get(asked.stop);
|
|
564
|
+
if (stopping) stopping.abort();
|
|
565
|
+
else { early.add(asked.stop); if (early.size > 1000) early.delete(early.values().next().value); }
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
const id = asked?.id, call = CALLS[asked?.call], stopping = new AbortController();
|
|
569
|
+
if (early.delete(id)) stopping.abort();
|
|
570
|
+
under.set(id, stopping);
|
|
571
|
+
try {
|
|
572
|
+
if (!call) throw new Error(`lamp has no call named "${asked?.call ?? ""}"`);
|
|
573
|
+
say({ id, done: await call(asked.given ?? {}, { stopped: stopping.signal, event: (said) => say({ id, event: said }) }) });
|
|
574
|
+
} catch (error) {
|
|
575
|
+
say({ id, ...(problemOf(error) ?? { failed: String(error?.stack ?? error) }) });
|
|
576
|
+
} finally { under.delete(id); }
|
|
577
|
+
};
|
|
578
|
+
let waiting = [];
|
|
579
|
+
for await (const chunk of process.stdin) {
|
|
580
|
+
let from = 0;
|
|
581
|
+
for (let end = chunk.indexOf(10, from); end >= 0; end = chunk.indexOf(10, from)) {
|
|
582
|
+
const line = Buffer.concat([...waiting, chunk.subarray(from, end)]).toString("utf8");
|
|
583
|
+
waiting = [];
|
|
584
|
+
from = end + 1;
|
|
585
|
+
if (line.trim()) answer(line);
|
|
586
|
+
}
|
|
587
|
+
if (from < chunk.length) waiting.push(chunk.subarray(from));
|
|
588
|
+
}
|
|
589
|
+
// Nobody is left to hear an answer.
|
|
590
|
+
process.exit(0);
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
const here = () => { try { return realpathSync(process.argv[1] ?? "") === realpathSync(fileURLToPath(import.meta.url)); } catch { return false; } };
|
|
594
|
+
if (here()) await (process.argv[2] === "--serve" ? serve() : once(process.argv[2]));
|