@aigne/aos 0.2.0-beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +49 -0
- package/LICENSE.md +26 -0
- package/dist/agent-dsl.cjs +116 -0
- package/dist/agent-dsl.d.cts +31 -0
- package/dist/agent-dsl.d.cts.map +1 -0
- package/dist/agent-dsl.d.mts +31 -0
- package/dist/agent-dsl.d.mts.map +1 -0
- package/dist/agent-dsl.mjs +115 -0
- package/dist/agent-dsl.mjs.map +1 -0
- package/dist/arc-compat.cjs +125 -0
- package/dist/arc-compat.d.cts +17 -0
- package/dist/arc-compat.d.cts.map +1 -0
- package/dist/arc-compat.d.mts +17 -0
- package/dist/arc-compat.d.mts.map +1 -0
- package/dist/arc-compat.mjs +123 -0
- package/dist/arc-compat.mjs.map +1 -0
- package/dist/auto-surface/compiler.cjs +36 -0
- package/dist/auto-surface/compiler.d.cts +7 -0
- package/dist/auto-surface/compiler.d.cts.map +1 -0
- package/dist/auto-surface/compiler.d.mts +7 -0
- package/dist/auto-surface/compiler.d.mts.map +1 -0
- package/dist/auto-surface/compiler.mjs +37 -0
- package/dist/auto-surface/compiler.mjs.map +1 -0
- package/dist/auto-surface/definition-dsl.cjs +333 -0
- package/dist/auto-surface/definition-dsl.d.cts +41 -0
- package/dist/auto-surface/definition-dsl.d.cts.map +1 -0
- package/dist/auto-surface/definition-dsl.d.mts +41 -0
- package/dist/auto-surface/definition-dsl.d.mts.map +1 -0
- package/dist/auto-surface/definition-dsl.mjs +332 -0
- package/dist/auto-surface/definition-dsl.mjs.map +1 -0
- package/dist/auto-surface/fragments.cjs +177 -0
- package/dist/auto-surface/fragments.d.cts +23 -0
- package/dist/auto-surface/fragments.d.cts.map +1 -0
- package/dist/auto-surface/fragments.d.mts +23 -0
- package/dist/auto-surface/fragments.d.mts.map +1 -0
- package/dist/auto-surface/fragments.mjs +175 -0
- package/dist/auto-surface/fragments.mjs.map +1 -0
- package/dist/auto-surface/index.d.mts +9 -0
- package/dist/auto-surface/layering.cjs +43 -0
- package/dist/auto-surface/layering.d.cts +7 -0
- package/dist/auto-surface/layering.d.cts.map +1 -0
- package/dist/auto-surface/layering.d.mts +7 -0
- package/dist/auto-surface/layering.d.mts.map +1 -0
- package/dist/auto-surface/layering.mjs +43 -0
- package/dist/auto-surface/layering.mjs.map +1 -0
- package/dist/auto-surface/projection.cjs +11 -0
- package/dist/auto-surface/projection.d.cts +11 -0
- package/dist/auto-surface/projection.d.cts.map +1 -0
- package/dist/auto-surface/projection.d.mts +11 -0
- package/dist/auto-surface/projection.d.mts.map +1 -0
- package/dist/auto-surface/projection.mjs +12 -0
- package/dist/auto-surface/projection.mjs.map +1 -0
- package/dist/auto-surface/projectors/settings-shell.cjs +114 -0
- package/dist/auto-surface/projectors/settings-shell.d.cts +10 -0
- package/dist/auto-surface/projectors/settings-shell.d.cts.map +1 -0
- package/dist/auto-surface/projectors/settings-shell.d.mts +10 -0
- package/dist/auto-surface/projectors/settings-shell.d.mts.map +1 -0
- package/dist/auto-surface/projectors/settings-shell.mjs +114 -0
- package/dist/auto-surface/projectors/settings-shell.mjs.map +1 -0
- package/dist/auto-surface/scenario.cjs +38 -0
- package/dist/auto-surface/scenario.d.cts +31 -0
- package/dist/auto-surface/scenario.d.cts.map +1 -0
- package/dist/auto-surface/scenario.d.mts +31 -0
- package/dist/auto-surface/scenario.d.mts.map +1 -0
- package/dist/auto-surface/scenario.mjs +37 -0
- package/dist/auto-surface/scenario.mjs.map +1 -0
- package/dist/auto-surface/types.cjs +9 -0
- package/dist/auto-surface/types.d.cts +153 -0
- package/dist/auto-surface/types.d.cts.map +1 -0
- package/dist/auto-surface/types.d.mts +153 -0
- package/dist/auto-surface/types.d.mts.map +1 -0
- package/dist/auto-surface/types.mjs +9 -0
- package/dist/auto-surface/types.mjs.map +1 -0
- package/dist/auto-surface/value-dsl.cjs +80 -0
- package/dist/auto-surface/value-dsl.d.cts +24 -0
- package/dist/auto-surface/value-dsl.d.cts.map +1 -0
- package/dist/auto-surface/value-dsl.d.mts +24 -0
- package/dist/auto-surface/value-dsl.d.mts.map +1 -0
- package/dist/auto-surface/value-dsl.mjs +79 -0
- package/dist/auto-surface/value-dsl.mjs.map +1 -0
- package/dist/blocklet/activation.cjs +94 -0
- package/dist/blocklet/activation.d.cts +30 -0
- package/dist/blocklet/activation.d.cts.map +1 -0
- package/dist/blocklet/activation.d.mts +30 -0
- package/dist/blocklet/activation.d.mts.map +1 -0
- package/dist/blocklet/activation.mjs +94 -0
- package/dist/blocklet/activation.mjs.map +1 -0
- package/dist/blocklet/did-space-registry.cjs +282 -0
- package/dist/blocklet/did-space-registry.d.cts +82 -0
- package/dist/blocklet/did-space-registry.d.cts.map +1 -0
- package/dist/blocklet/did-space-registry.d.mts +82 -0
- package/dist/blocklet/did-space-registry.d.mts.map +1 -0
- package/dist/blocklet/did-space-registry.mjs +281 -0
- package/dist/blocklet/did-space-registry.mjs.map +1 -0
- package/dist/blocklet/handlers.cjs +66 -0
- package/dist/blocklet/handlers.d.cts +16 -0
- package/dist/blocklet/handlers.d.cts.map +1 -0
- package/dist/blocklet/handlers.d.mts +16 -0
- package/dist/blocklet/handlers.d.mts.map +1 -0
- package/dist/blocklet/handlers.mjs +65 -0
- package/dist/blocklet/handlers.mjs.map +1 -0
- package/dist/blocklet/index.d.mts +7 -0
- package/dist/blocklet/manifest.d.cts +2 -0
- package/dist/blocklet/manifest.d.mts +2 -0
- package/dist/blocklet/manifest.mjs +3 -0
- package/dist/blocklet/registry.cjs +447 -0
- package/dist/blocklet/registry.d.cts +197 -0
- package/dist/blocklet/registry.d.cts.map +1 -0
- package/dist/blocklet/registry.d.mts +197 -0
- package/dist/blocklet/registry.d.mts.map +1 -0
- package/dist/blocklet/registry.mjs +441 -0
- package/dist/blocklet/registry.mjs.map +1 -0
- package/dist/blocklet/static-render.cjs +183 -0
- package/dist/blocklet/static-render.d.cts +55 -0
- package/dist/blocklet/static-render.d.cts.map +1 -0
- package/dist/blocklet/static-render.d.mts +55 -0
- package/dist/blocklet/static-render.d.mts.map +1 -0
- package/dist/blocklet/static-render.mjs +181 -0
- package/dist/blocklet/static-render.mjs.map +1 -0
- package/dist/blocklet/types.d.cts +70 -0
- package/dist/blocklet/types.d.cts.map +1 -0
- package/dist/blocklet/types.d.mts +70 -0
- package/dist/blocklet/types.d.mts.map +1 -0
- package/dist/devices/chain.cjs +127 -0
- package/dist/devices/chain.d.cts +48 -0
- package/dist/devices/chain.d.cts.map +1 -0
- package/dist/devices/chain.d.mts +48 -0
- package/dist/devices/chain.d.mts.map +1 -0
- package/dist/devices/chain.mjs +125 -0
- package/dist/devices/chain.mjs.map +1 -0
- package/dist/dsl-shared.cjs +290 -0
- package/dist/dsl-shared.d.cts +54 -0
- package/dist/dsl-shared.d.cts.map +1 -0
- package/dist/dsl-shared.d.mts +54 -0
- package/dist/dsl-shared.d.mts.map +1 -0
- package/dist/dsl-shared.mjs +287 -0
- package/dist/dsl-shared.mjs.map +1 -0
- package/dist/http/afs-mcp.cjs +85 -0
- package/dist/http/afs-mcp.d.cts +14 -0
- package/dist/http/afs-mcp.d.cts.map +1 -0
- package/dist/http/afs-mcp.d.mts +14 -0
- package/dist/http/afs-mcp.d.mts.map +1 -0
- package/dist/http/afs-mcp.mjs +86 -0
- package/dist/http/afs-mcp.mjs.map +1 -0
- package/dist/http/afs-raw.cjs +264 -0
- package/dist/http/afs-raw.d.cts +31 -0
- package/dist/http/afs-raw.d.cts.map +1 -0
- package/dist/http/afs-raw.d.mts +31 -0
- package/dist/http/afs-raw.d.mts.map +1 -0
- package/dist/http/afs-raw.mjs +264 -0
- package/dist/http/afs-raw.mjs.map +1 -0
- package/dist/http/afs-rest.cjs +30 -0
- package/dist/http/afs-rest.d.cts +21 -0
- package/dist/http/afs-rest.d.cts.map +1 -0
- package/dist/http/afs-rest.d.mts +21 -0
- package/dist/http/afs-rest.d.mts.map +1 -0
- package/dist/http/afs-rest.mjs +31 -0
- package/dist/http/afs-rest.mjs.map +1 -0
- package/dist/http/afs-rpc-wire.cjs +271 -0
- package/dist/http/afs-rpc-wire.d.cts +195 -0
- package/dist/http/afs-rpc-wire.d.cts.map +1 -0
- package/dist/http/afs-rpc-wire.d.mts +195 -0
- package/dist/http/afs-rpc-wire.d.mts.map +1 -0
- package/dist/http/afs-rpc-wire.mjs +262 -0
- package/dist/http/afs-rpc-wire.mjs.map +1 -0
- package/dist/http/afs-rpc.cjs +729 -0
- package/dist/http/afs-rpc.d.cts +103 -0
- package/dist/http/afs-rpc.d.cts.map +1 -0
- package/dist/http/afs-rpc.d.mts +103 -0
- package/dist/http/afs-rpc.d.mts.map +1 -0
- package/dist/http/afs-rpc.mjs +729 -0
- package/dist/http/afs-rpc.mjs.map +1 -0
- package/dist/http/afs-upload.cjs +116 -0
- package/dist/http/afs-upload.d.cts +40 -0
- package/dist/http/afs-upload.d.cts.map +1 -0
- package/dist/http/afs-upload.d.mts +40 -0
- package/dist/http/afs-upload.d.mts.map +1 -0
- package/dist/http/afs-upload.mjs +116 -0
- package/dist/http/afs-upload.mjs.map +1 -0
- package/dist/http/aup-client.cjs +60 -0
- package/dist/http/aup-client.d.cts +22 -0
- package/dist/http/aup-client.d.cts.map +1 -0
- package/dist/http/aup-client.d.mts +22 -0
- package/dist/http/aup-client.d.mts.map +1 -0
- package/dist/http/aup-client.mjs +59 -0
- package/dist/http/aup-client.mjs.map +1 -0
- package/dist/http/aup-event.cjs +100 -0
- package/dist/http/aup-event.d.cts +38 -0
- package/dist/http/aup-event.d.cts.map +1 -0
- package/dist/http/aup-event.d.mts +38 -0
- package/dist/http/aup-event.d.mts.map +1 -0
- package/dist/http/aup-event.mjs +101 -0
- package/dist/http/aup-event.mjs.map +1 -0
- package/dist/http/auth-context.cjs +66 -0
- package/dist/http/auth-context.d.cts +64 -0
- package/dist/http/auth-context.d.cts.map +1 -0
- package/dist/http/auth-context.d.mts +64 -0
- package/dist/http/auth-context.d.mts.map +1 -0
- package/dist/http/auth-context.mjs +66 -0
- package/dist/http/auth-context.mjs.map +1 -0
- package/dist/http/csrf.cjs +50 -0
- package/dist/http/csrf.d.cts +8 -0
- package/dist/http/csrf.d.cts.map +1 -0
- package/dist/http/csrf.d.mts +8 -0
- package/dist/http/csrf.d.mts.map +1 -0
- package/dist/http/csrf.mjs +49 -0
- package/dist/http/csrf.mjs.map +1 -0
- package/dist/http/handlers.cjs +106 -0
- package/dist/http/handlers.d.cts +39 -0
- package/dist/http/handlers.d.cts.map +1 -0
- package/dist/http/handlers.d.mts +39 -0
- package/dist/http/handlers.d.mts.map +1 -0
- package/dist/http/handlers.mjs +104 -0
- package/dist/http/handlers.mjs.map +1 -0
- package/dist/http/index.d.mts +1 -0
- package/dist/http/ingest-facade.cjs +315 -0
- package/dist/http/ingest-facade.mjs +314 -0
- package/dist/http/ingest-facade.mjs.map +1 -0
- package/dist/http/raw-url.cjs +136 -0
- package/dist/http/raw-url.d.cts +54 -0
- package/dist/http/raw-url.d.cts.map +1 -0
- package/dist/http/raw-url.d.mts +54 -0
- package/dist/http/raw-url.d.mts.map +1 -0
- package/dist/http/raw-url.mjs +136 -0
- package/dist/http/raw-url.mjs.map +1 -0
- package/dist/http/request-context.cjs +178 -0
- package/dist/http/request-context.d.cts +76 -0
- package/dist/http/request-context.d.cts.map +1 -0
- package/dist/http/request-context.d.mts +76 -0
- package/dist/http/request-context.d.mts.map +1 -0
- package/dist/http/request-context.mjs +179 -0
- package/dist/http/request-context.mjs.map +1 -0
- package/dist/index.cjs +197 -0
- package/dist/index.d.cts +63 -0
- package/dist/index.d.mts +68 -0
- package/dist/index.mjs +61 -0
- package/dist/mcp/index.cjs +9 -0
- package/dist/mcp/index.d.cts +5 -0
- package/dist/mcp/index.d.mts +5 -0
- package/dist/mcp/index.mjs +6 -0
- package/dist/mcp/prompts.cjs +17 -0
- package/dist/mcp/prompts.d.cts +8 -0
- package/dist/mcp/prompts.d.cts.map +1 -0
- package/dist/mcp/prompts.d.mts +8 -0
- package/dist/mcp/prompts.d.mts.map +1 -0
- package/dist/mcp/prompts.mjs +17 -0
- package/dist/mcp/prompts.mjs.map +1 -0
- package/dist/mcp/resources.cjs +22 -0
- package/dist/mcp/resources.d.cts +8 -0
- package/dist/mcp/resources.d.cts.map +1 -0
- package/dist/mcp/resources.d.mts +8 -0
- package/dist/mcp/resources.d.mts.map +1 -0
- package/dist/mcp/resources.mjs +22 -0
- package/dist/mcp/resources.mjs.map +1 -0
- package/dist/mcp/server.cjs +51 -0
- package/dist/mcp/server.d.cts +20 -0
- package/dist/mcp/server.d.cts.map +1 -0
- package/dist/mcp/server.d.mts +20 -0
- package/dist/mcp/server.d.mts.map +1 -0
- package/dist/mcp/server.mjs +52 -0
- package/dist/mcp/server.mjs.map +1 -0
- package/dist/mcp/tools.cjs +218 -0
- package/dist/mcp/tools.d.cts +8 -0
- package/dist/mcp/tools.d.cts.map +1 -0
- package/dist/mcp/tools.d.mts +8 -0
- package/dist/mcp/tools.d.mts.map +1 -0
- package/dist/mcp/tools.mjs +219 -0
- package/dist/mcp/tools.mjs.map +1 -0
- package/dist/mcp/utils.cjs +75 -0
- package/dist/mcp/utils.mjs +69 -0
- package/dist/mcp/utils.mjs.map +1 -0
- package/dist/mount/index.cjs +4 -0
- package/dist/mount/index.d.cts +3 -0
- package/dist/mount/index.d.mts +3 -0
- package/dist/mount/index.mjs +3 -0
- package/dist/mount/materializer.cjs +167 -0
- package/dist/mount/materializer.d.cts +97 -0
- package/dist/mount/materializer.d.cts.map +1 -0
- package/dist/mount/materializer.d.mts +97 -0
- package/dist/mount/materializer.d.mts.map +1 -0
- package/dist/mount/materializer.mjs +167 -0
- package/dist/mount/materializer.mjs.map +1 -0
- package/dist/mount/types.d.cts +90 -0
- package/dist/mount/types.d.cts.map +1 -0
- package/dist/mount/types.d.mts +90 -0
- package/dist/mount/types.d.mts.map +1 -0
- package/dist/mount-config.cjs +61 -0
- package/dist/mount-config.d.cts +19 -0
- package/dist/mount-config.d.cts.map +1 -0
- package/dist/mount-config.d.mts +19 -0
- package/dist/mount-config.d.mts.map +1 -0
- package/dist/mount-config.mjs +61 -0
- package/dist/mount-config.mjs.map +1 -0
- package/dist/projectors/aup-projector.cjs +190 -0
- package/dist/projectors/aup-projector.d.cts +59 -0
- package/dist/projectors/aup-projector.d.cts.map +1 -0
- package/dist/projectors/aup-projector.d.mts +59 -0
- package/dist/projectors/aup-projector.d.mts.map +1 -0
- package/dist/projectors/aup-projector.mjs +188 -0
- package/dist/projectors/aup-projector.mjs.map +1 -0
- package/dist/projectors/index.cjs +6 -0
- package/dist/projectors/index.d.cts +2 -0
- package/dist/projectors/index.d.mts +2 -0
- package/dist/projectors/index.mjs +3 -0
- package/dist/scaffold/afs.cjs +195 -0
- package/dist/scaffold/afs.d.cts +16 -0
- package/dist/scaffold/afs.d.cts.map +1 -0
- package/dist/scaffold/afs.d.mts +16 -0
- package/dist/scaffold/afs.d.mts.map +1 -0
- package/dist/scaffold/afs.mjs +195 -0
- package/dist/scaffold/afs.mjs.map +1 -0
- package/dist/scaffold/composition.cjs +92 -0
- package/dist/scaffold/composition.d.cts +10 -0
- package/dist/scaffold/composition.d.cts.map +1 -0
- package/dist/scaffold/composition.d.mts +10 -0
- package/dist/scaffold/composition.d.mts.map +1 -0
- package/dist/scaffold/composition.mjs +92 -0
- package/dist/scaffold/composition.mjs.map +1 -0
- package/dist/scaffold/dsl-error.cjs +21 -0
- package/dist/scaffold/dsl-error.d.cts +11 -0
- package/dist/scaffold/dsl-error.d.cts.map +1 -0
- package/dist/scaffold/dsl-error.d.mts +11 -0
- package/dist/scaffold/dsl-error.d.mts.map +1 -0
- package/dist/scaffold/dsl-error.mjs +20 -0
- package/dist/scaffold/dsl-error.mjs.map +1 -0
- package/dist/scaffold/index.d.mts +12 -0
- package/dist/scaffold/manifest-dsl.cjs +188 -0
- package/dist/scaffold/manifest-dsl.d.cts +8 -0
- package/dist/scaffold/manifest-dsl.d.cts.map +1 -0
- package/dist/scaffold/manifest-dsl.d.mts +8 -0
- package/dist/scaffold/manifest-dsl.d.mts.map +1 -0
- package/dist/scaffold/manifest-dsl.mjs +188 -0
- package/dist/scaffold/manifest-dsl.mjs.map +1 -0
- package/dist/scaffold/module-dsl.cjs +284 -0
- package/dist/scaffold/module-dsl.d.cts +8 -0
- package/dist/scaffold/module-dsl.d.cts.map +1 -0
- package/dist/scaffold/module-dsl.d.mts +8 -0
- package/dist/scaffold/module-dsl.d.mts.map +1 -0
- package/dist/scaffold/module-dsl.mjs +284 -0
- package/dist/scaffold/module-dsl.mjs.map +1 -0
- package/dist/scaffold/resolver.cjs +156 -0
- package/dist/scaffold/resolver.d.cts +7 -0
- package/dist/scaffold/resolver.d.cts.map +1 -0
- package/dist/scaffold/resolver.d.mts +7 -0
- package/dist/scaffold/resolver.d.mts.map +1 -0
- package/dist/scaffold/resolver.mjs +156 -0
- package/dist/scaffold/resolver.mjs.map +1 -0
- package/dist/scaffold/runtime.cjs +24 -0
- package/dist/scaffold/runtime.d.cts +19 -0
- package/dist/scaffold/runtime.d.cts.map +1 -0
- package/dist/scaffold/runtime.d.mts +19 -0
- package/dist/scaffold/runtime.d.mts.map +1 -0
- package/dist/scaffold/runtime.mjs +25 -0
- package/dist/scaffold/runtime.mjs.map +1 -0
- package/dist/scaffold/shell-dsl.cjs +279 -0
- package/dist/scaffold/shell-dsl.d.cts +8 -0
- package/dist/scaffold/shell-dsl.d.cts.map +1 -0
- package/dist/scaffold/shell-dsl.d.mts +8 -0
- package/dist/scaffold/shell-dsl.d.mts.map +1 -0
- package/dist/scaffold/shell-dsl.mjs +279 -0
- package/dist/scaffold/shell-dsl.mjs.map +1 -0
- package/dist/scaffold/surface-dsl.cjs +182 -0
- package/dist/scaffold/surface-dsl.d.cts +8 -0
- package/dist/scaffold/surface-dsl.d.cts.map +1 -0
- package/dist/scaffold/surface-dsl.d.mts +8 -0
- package/dist/scaffold/surface-dsl.d.mts.map +1 -0
- package/dist/scaffold/surface-dsl.mjs +182 -0
- package/dist/scaffold/surface-dsl.mjs.map +1 -0
- package/dist/scaffold/surfaces.cjs +84 -0
- package/dist/scaffold/surfaces.d.cts +23 -0
- package/dist/scaffold/surfaces.d.cts.map +1 -0
- package/dist/scaffold/surfaces.d.mts +24 -0
- package/dist/scaffold/surfaces.d.mts.map +1 -0
- package/dist/scaffold/surfaces.mjs +84 -0
- package/dist/scaffold/surfaces.mjs.map +1 -0
- package/dist/scaffold/types.d.cts +264 -0
- package/dist/scaffold/types.d.cts.map +1 -0
- package/dist/scaffold/types.d.mts +265 -0
- package/dist/scaffold/types.d.mts.map +1 -0
- package/dist/scaffold/workspace-dsl.cjs +339 -0
- package/dist/scaffold/workspace-dsl.d.cts +49 -0
- package/dist/scaffold/workspace-dsl.d.cts.map +1 -0
- package/dist/scaffold/workspace-dsl.d.mts +49 -0
- package/dist/scaffold/workspace-dsl.d.mts.map +1 -0
- package/dist/scaffold/workspace-dsl.mjs +337 -0
- package/dist/scaffold/workspace-dsl.mjs.map +1 -0
- package/dist/scope/index.d.mts +3 -0
- package/dist/scope/read-blocklet-scope.cjs +29 -0
- package/dist/scope/read-blocklet-scope.d.cts +8 -0
- package/dist/scope/read-blocklet-scope.d.cts.map +1 -0
- package/dist/scope/read-blocklet-scope.d.mts +8 -0
- package/dist/scope/read-blocklet-scope.d.mts.map +1 -0
- package/dist/scope/read-blocklet-scope.mjs +30 -0
- package/dist/scope/read-blocklet-scope.mjs.map +1 -0
- package/dist/scope/resolve-scoped-afs.cjs +87 -0
- package/dist/scope/resolve-scoped-afs.d.cts +7 -0
- package/dist/scope/resolve-scoped-afs.d.cts.map +1 -0
- package/dist/scope/resolve-scoped-afs.d.mts +7 -0
- package/dist/scope/resolve-scoped-afs.d.mts.map +1 -0
- package/dist/scope/resolve-scoped-afs.mjs +88 -0
- package/dist/scope/resolve-scoped-afs.mjs.map +1 -0
- package/dist/scope/types.d.cts +25 -0
- package/dist/scope/types.d.cts.map +1 -0
- package/dist/scope/types.d.mts +25 -0
- package/dist/scope/types.d.mts.map +1 -0
- package/dist/session/backends.cjs +90 -0
- package/dist/session/backends.d.cts +35 -0
- package/dist/session/backends.d.cts.map +1 -0
- package/dist/session/backends.d.mts +35 -0
- package/dist/session/backends.d.mts.map +1 -0
- package/dist/session/backends.mjs +89 -0
- package/dist/session/backends.mjs.map +1 -0
- package/dist/session/replication-resolver.cjs +323 -0
- package/dist/session/replication-resolver.d.cts +71 -0
- package/dist/session/replication-resolver.d.cts.map +1 -0
- package/dist/session/replication-resolver.d.mts +71 -0
- package/dist/session/replication-resolver.d.mts.map +1 -0
- package/dist/session/replication-resolver.mjs +323 -0
- package/dist/session/replication-resolver.mjs.map +1 -0
- package/dist/session/role-level.cjs +36 -0
- package/dist/session/role-level.d.cts +24 -0
- package/dist/session/role-level.d.cts.map +1 -0
- package/dist/session/role-level.d.mts +24 -0
- package/dist/session/role-level.d.mts.map +1 -0
- package/dist/session/role-level.mjs +35 -0
- package/dist/session/role-level.mjs.map +1 -0
- package/dist/session/session-dir-providers.cjs +254 -0
- package/dist/session/session-dir-providers.d.cts +32 -0
- package/dist/session/session-dir-providers.d.cts.map +1 -0
- package/dist/session/session-dir-providers.d.mts +32 -0
- package/dist/session/session-dir-providers.d.mts.map +1 -0
- package/dist/session/session-dir-providers.mjs +252 -0
- package/dist/session/session-dir-providers.mjs.map +1 -0
- package/dist/session/session-id.cjs +20 -0
- package/dist/session/session-id.d.cts +15 -0
- package/dist/session/session-id.d.cts.map +1 -0
- package/dist/session/session-id.d.mts +15 -0
- package/dist/session/session-id.d.mts.map +1 -0
- package/dist/session/session-id.mjs +20 -0
- package/dist/session/session-id.mjs.map +1 -0
- package/dist/session/session-user-afs.cjs +899 -0
- package/dist/session/session-user-afs.d.cts +296 -0
- package/dist/session/session-user-afs.d.cts.map +1 -0
- package/dist/session/session-user-afs.d.mts +296 -0
- package/dist/session/session-user-afs.d.mts.map +1 -0
- package/dist/session/session-user-afs.mjs +896 -0
- package/dist/session/session-user-afs.mjs.map +1 -0
- package/dist/session/settings-cascade.cjs +69 -0
- package/dist/session/settings-cascade.d.cts +81 -0
- package/dist/session/settings-cascade.d.cts.map +1 -0
- package/dist/session/settings-cascade.d.mts +81 -0
- package/dist/session/settings-cascade.d.mts.map +1 -0
- package/dist/session/settings-cascade.mjs +69 -0
- package/dist/session/settings-cascade.mjs.map +1 -0
- package/dist/session/settings-resolver.cjs +770 -0
- package/dist/session/settings-resolver.d.cts +177 -0
- package/dist/session/settings-resolver.d.cts.map +1 -0
- package/dist/session/settings-resolver.d.mts +177 -0
- package/dist/session/settings-resolver.d.mts.map +1 -0
- package/dist/session/settings-resolver.mjs +771 -0
- package/dist/session/settings-resolver.mjs.map +1 -0
- package/dist/session/settings-schema-store.cjs +0 -0
- package/dist/session/settings-schema-store.d.cts +72 -0
- package/dist/session/settings-schema-store.d.cts.map +1 -0
- package/dist/session/settings-schema-store.d.mts +72 -0
- package/dist/session/settings-schema-store.d.mts.map +1 -0
- package/dist/session/settings-schema-store.mjs +0 -0
- package/dist/session/settings-schema-store.mjs.map +1 -0
- package/dist/system-mounts/index.cjs +14 -0
- package/dist/system-mounts/index.d.cts +6 -0
- package/dist/system-mounts/index.d.mts +6 -0
- package/dist/system-mounts/index.mjs +6 -0
- package/dist/system-mounts/install.cjs +101 -0
- package/dist/system-mounts/install.d.cts +36 -0
- package/dist/system-mounts/install.d.cts.map +1 -0
- package/dist/system-mounts/install.d.mts +37 -0
- package/dist/system-mounts/install.d.mts.map +1 -0
- package/dist/system-mounts/install.mjs +102 -0
- package/dist/system-mounts/install.mjs.map +1 -0
- package/dist/system-mounts/installers.cjs +247 -0
- package/dist/system-mounts/installers.d.cts +13 -0
- package/dist/system-mounts/installers.d.cts.map +1 -0
- package/dist/system-mounts/installers.d.mts +14 -0
- package/dist/system-mounts/installers.d.mts.map +1 -0
- package/dist/system-mounts/installers.mjs +244 -0
- package/dist/system-mounts/installers.mjs.map +1 -0
- package/dist/system-mounts/lists.cjs +122 -0
- package/dist/system-mounts/lists.d.cts +34 -0
- package/dist/system-mounts/lists.d.cts.map +1 -0
- package/dist/system-mounts/lists.d.mts +34 -0
- package/dist/system-mounts/lists.d.mts.map +1 -0
- package/dist/system-mounts/lists.mjs +122 -0
- package/dist/system-mounts/lists.mjs.map +1 -0
- package/dist/system-mounts/types.d.cts +124 -0
- package/dist/system-mounts/types.d.cts.map +1 -0
- package/dist/system-mounts/types.d.mts +125 -0
- package/dist/system-mounts/types.d.mts.map +1 -0
- package/dist/system-mounts/validate.cjs +56 -0
- package/dist/system-mounts/validate.d.cts +34 -0
- package/dist/system-mounts/validate.d.cts.map +1 -0
- package/dist/system-mounts/validate.d.mts +34 -0
- package/dist/system-mounts/validate.d.mts.map +1 -0
- package/dist/system-mounts/validate.mjs +56 -0
- package/dist/system-mounts/validate.mjs.map +1 -0
- package/dist/terminal-llm.cjs +90 -0
- package/dist/terminal-llm.d.cts +50 -0
- package/dist/terminal-llm.d.cts.map +1 -0
- package/dist/terminal-llm.d.mts +50 -0
- package/dist/terminal-llm.d.mts.map +1 -0
- package/dist/terminal-llm.mjs +90 -0
- package/dist/terminal-llm.mjs.map +1 -0
- package/dist/terminal-repl.cjs +371 -0
- package/dist/terminal-repl.d.cts +69 -0
- package/dist/terminal-repl.d.cts.map +1 -0
- package/dist/terminal-repl.d.mts +69 -0
- package/dist/terminal-repl.d.mts.map +1 -0
- package/dist/terminal-repl.mjs +370 -0
- package/dist/terminal-repl.mjs.map +1 -0
- package/dist/transport/idle-timer.cjs +136 -0
- package/dist/transport/idle-timer.d.cts +92 -0
- package/dist/transport/idle-timer.d.cts.map +1 -0
- package/dist/transport/idle-timer.d.mts +92 -0
- package/dist/transport/idle-timer.d.mts.map +1 -0
- package/dist/transport/idle-timer.mjs +132 -0
- package/dist/transport/idle-timer.mjs.map +1 -0
- package/dist/web-component-dsl.cjs +153 -0
- package/dist/web-component-dsl.d.cts +27 -0
- package/dist/web-component-dsl.d.cts.map +1 -0
- package/dist/web-component-dsl.d.mts +27 -0
- package/dist/web-component-dsl.d.mts.map +1 -0
- package/dist/web-component-dsl.mjs +152 -0
- package/dist/web-component-dsl.mjs.map +1 -0
- package/package.json +81 -0
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
//#region src/terminal-repl.ts
|
|
2
|
+
const ARC_ART = ["▄▀█ █▀█ █▀▀", "█▀█ █▀▄ █▄▄"];
|
|
3
|
+
const TAGLINE = "Agentic Realm Computer";
|
|
4
|
+
const COPYRIGHT = "Copyright (c) 2026 ArcBlock Inc. All rights reserved.";
|
|
5
|
+
const R = "\x1B[0m";
|
|
6
|
+
const ART_GRADIENT = [[
|
|
7
|
+
100,
|
|
8
|
+
220,
|
|
9
|
+
255
|
|
10
|
+
], [
|
|
11
|
+
180,
|
|
12
|
+
120,
|
|
13
|
+
255
|
|
14
|
+
]];
|
|
15
|
+
const TAGLINE_GRADIENT = [
|
|
16
|
+
[
|
|
17
|
+
100,
|
|
18
|
+
255,
|
|
19
|
+
255
|
|
20
|
+
],
|
|
21
|
+
[
|
|
22
|
+
80,
|
|
23
|
+
220,
|
|
24
|
+
255
|
|
25
|
+
],
|
|
26
|
+
[
|
|
27
|
+
60,
|
|
28
|
+
180,
|
|
29
|
+
255
|
|
30
|
+
],
|
|
31
|
+
[
|
|
32
|
+
100,
|
|
33
|
+
140,
|
|
34
|
+
255
|
|
35
|
+
],
|
|
36
|
+
[
|
|
37
|
+
180,
|
|
38
|
+
120,
|
|
39
|
+
255
|
|
40
|
+
],
|
|
41
|
+
[
|
|
42
|
+
220,
|
|
43
|
+
100,
|
|
44
|
+
255
|
|
45
|
+
]
|
|
46
|
+
];
|
|
47
|
+
function interpColor(t, stops) {
|
|
48
|
+
const scaled = t * (stops.length - 1);
|
|
49
|
+
const i = Math.min(Math.floor(scaled), stops.length - 2);
|
|
50
|
+
const frac = scaled - i;
|
|
51
|
+
const a = stops[i] ?? [
|
|
52
|
+
0,
|
|
53
|
+
0,
|
|
54
|
+
0
|
|
55
|
+
];
|
|
56
|
+
const b = stops[i + 1] ?? [
|
|
57
|
+
0,
|
|
58
|
+
0,
|
|
59
|
+
0
|
|
60
|
+
];
|
|
61
|
+
return [
|
|
62
|
+
Math.round(a[0] + (b[0] - a[0]) * frac),
|
|
63
|
+
Math.round(a[1] + (b[1] - a[1]) * frac),
|
|
64
|
+
Math.round(a[2] + (b[2] - a[2]) * frac)
|
|
65
|
+
];
|
|
66
|
+
}
|
|
67
|
+
function rainbowText(text) {
|
|
68
|
+
const chars = [...text];
|
|
69
|
+
return chars.map((ch, i) => {
|
|
70
|
+
if (ch === " ") return ch;
|
|
71
|
+
const [r, g, b] = interpColor(chars.length > 1 ? i / (chars.length - 1) : 0, TAGLINE_GRADIENT);
|
|
72
|
+
return `\x1b[38;2;${r};${g};${b}m${ch}${R}`;
|
|
73
|
+
}).join("");
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Render the ARC terminal banner.
|
|
77
|
+
*
|
|
78
|
+
* Uses 24-bit truecolor gradient (matches Node splash.ts exactly).
|
|
79
|
+
*
|
|
80
|
+
* Output (colored):
|
|
81
|
+
* ▄▀█ █▀█ █▀▀ Agentic Realm Computer
|
|
82
|
+
* █▀█ █▀▄ █▄▄ v1.0.0 (abc1234) · 2026-04-23
|
|
83
|
+
* Copyright (c) 2026 ArcBlock Inc. All rights reserved.
|
|
84
|
+
*
|
|
85
|
+
* Session: <id> · N providers · Type help for commands.
|
|
86
|
+
*/
|
|
87
|
+
function renderArcBanner(opts) {
|
|
88
|
+
const color = opts.color !== false;
|
|
89
|
+
const { version, commit, date, providerCount, sessionId } = opts;
|
|
90
|
+
const tc = (rgb, s) => color ? `\x1b[38;2;${rgb[0]};${rgb[1]};${rgb[2]}m${s}${R}` : s;
|
|
91
|
+
const cyan = (s) => color ? `\x1b[96m${s}${R}` : s;
|
|
92
|
+
const dim = (s) => color ? `\x1b[2m${s}${R}` : s;
|
|
93
|
+
const art = ARC_ART.map((line, i) => color ? tc(ART_GRADIENT[i], line) : line);
|
|
94
|
+
const tagline = color ? rainbowText(TAGLINE) : TAGLINE;
|
|
95
|
+
const versionStr = [
|
|
96
|
+
cyan(`v${version}`),
|
|
97
|
+
dim(`(${commit})`),
|
|
98
|
+
dim("·"),
|
|
99
|
+
dim(date)
|
|
100
|
+
].join(" ");
|
|
101
|
+
const copyrightStr = dim(COPYRIGHT);
|
|
102
|
+
const gap = " ";
|
|
103
|
+
const lines = [
|
|
104
|
+
` ${art[0]}${gap}${tagline}`,
|
|
105
|
+
` ${art[1]}${gap}${versionStr}`,
|
|
106
|
+
` ${copyrightStr}`
|
|
107
|
+
];
|
|
108
|
+
if (providerCount !== void 0 || sessionId) {
|
|
109
|
+
const parts = [];
|
|
110
|
+
if (sessionId) parts.push(`Session: ${dim(sessionId)}`);
|
|
111
|
+
if (providerCount !== void 0) {
|
|
112
|
+
const plural = providerCount === 1 ? "provider" : "providers";
|
|
113
|
+
parts.push(`${providerCount} ${plural}`);
|
|
114
|
+
}
|
|
115
|
+
parts.push(`Type ${cyan("help")} for commands.`);
|
|
116
|
+
lines.push("", ` ${parts.join(dim(" · "))}`);
|
|
117
|
+
}
|
|
118
|
+
return lines.join("\r\n");
|
|
119
|
+
}
|
|
120
|
+
/** Generate a random hex session ID. */
|
|
121
|
+
function genSessionId() {
|
|
122
|
+
const arr = new Uint8Array(8);
|
|
123
|
+
if (typeof crypto !== "undefined" && crypto.getRandomValues) crypto.getRandomValues(arr);
|
|
124
|
+
else for (let i = 0; i < arr.length; i++) arr[i] = Math.floor(Math.random() * 256);
|
|
125
|
+
return Array.from(arr, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
126
|
+
}
|
|
127
|
+
function resolvePath(cwd, raw) {
|
|
128
|
+
if (!raw || raw === ".") return cwd;
|
|
129
|
+
const parts = (raw.startsWith("/") ? raw : `${cwd === "/" ? "" : cwd}/${raw}`).split("/").filter(Boolean);
|
|
130
|
+
const resolved = [];
|
|
131
|
+
for (const p of parts) if (p === "..") resolved.pop();
|
|
132
|
+
else if (p !== ".") resolved.push(p);
|
|
133
|
+
return `/${resolved.join("/")}`;
|
|
134
|
+
}
|
|
135
|
+
function parseArgs(input) {
|
|
136
|
+
const args = [];
|
|
137
|
+
let current = "";
|
|
138
|
+
let quote = null;
|
|
139
|
+
for (const ch of input) if (quote) if (ch === quote) quote = null;
|
|
140
|
+
else current += ch;
|
|
141
|
+
else if (ch === "\"" || ch === "'") quote = ch;
|
|
142
|
+
else if (ch === " " || ch === " ") {
|
|
143
|
+
if (current) {
|
|
144
|
+
args.push(current);
|
|
145
|
+
current = "";
|
|
146
|
+
}
|
|
147
|
+
} else current += ch;
|
|
148
|
+
if (current) args.push(current);
|
|
149
|
+
return args;
|
|
150
|
+
}
|
|
151
|
+
function makeAnsi(color) {
|
|
152
|
+
const r = color ? "\x1B[0m" : "";
|
|
153
|
+
const red = color ? "\x1B[31m" : "";
|
|
154
|
+
const blue = color ? "\x1B[34m" : "";
|
|
155
|
+
const yellow = color ? "\x1B[33m" : "";
|
|
156
|
+
const bold = color ? "\x1B[1m" : "";
|
|
157
|
+
return {
|
|
158
|
+
r,
|
|
159
|
+
red,
|
|
160
|
+
blue,
|
|
161
|
+
yellow,
|
|
162
|
+
bold,
|
|
163
|
+
err: (msg) => `${red}Error:${r} ${msg}`,
|
|
164
|
+
help: () => [
|
|
165
|
+
`${bold}Available commands:${r}`,
|
|
166
|
+
"",
|
|
167
|
+
` ${bold}AFS Commands:${r}`,
|
|
168
|
+
` ${yellow}ls${r} [path] List directory contents (default: current dir)`,
|
|
169
|
+
` ${yellow}read${r} <path> Read file content`,
|
|
170
|
+
` ${yellow}write${r} <path> <content> Write content to file`,
|
|
171
|
+
` ${yellow}stat${r} [path] Get file or directory info`,
|
|
172
|
+
` ${yellow}exec${r} <path> [args] Execute an action`,
|
|
173
|
+
` ${yellow}explain${r} [path] Explain path capabilities`,
|
|
174
|
+
` ${yellow}search${r} <path> <query> Search content`,
|
|
175
|
+
"",
|
|
176
|
+
` ${bold}REPL Commands:${r}`,
|
|
177
|
+
` ${yellow}cd${r} [path] Change working directory`,
|
|
178
|
+
` ${yellow}pwd${r} Print working directory`,
|
|
179
|
+
` ${yellow}help${r} Show this help`,
|
|
180
|
+
` ${yellow}clear${r} Clear screen`,
|
|
181
|
+
` ${yellow}exit${r} / ${yellow}quit${r} Exit session`
|
|
182
|
+
].join("\r\n")
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
async function cmdLs(afs, path, ansi) {
|
|
186
|
+
try {
|
|
187
|
+
const items = (await afs.list(path, { maxDepth: 1 })).data ?? [];
|
|
188
|
+
if (!items.length) return "(empty)";
|
|
189
|
+
return items.map((e) => {
|
|
190
|
+
const isDir = e.meta?.kind === "directory" || (e.meta?.childrenCount ?? 0) > 0;
|
|
191
|
+
const name = e.path.split("/").at(-1) ?? e.path;
|
|
192
|
+
return isDir ? `${ansi.blue}${name}/${ansi.r}` : name;
|
|
193
|
+
}).join("\r\n");
|
|
194
|
+
} catch (e) {
|
|
195
|
+
return ansi.err(e instanceof Error ? e.message : String(e));
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
async function cmdRead(afs, path, ansi) {
|
|
199
|
+
try {
|
|
200
|
+
const content = (await afs.read(path)).data?.content;
|
|
201
|
+
if (content === void 0 || content === null) return ansi.err("Not found or not readable");
|
|
202
|
+
if (typeof content === "string") return content;
|
|
203
|
+
if (content instanceof Uint8Array) return new TextDecoder().decode(content);
|
|
204
|
+
return JSON.stringify(content, null, 2);
|
|
205
|
+
} catch (e) {
|
|
206
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
207
|
+
if (/not found|ENOENT/i.test(msg)) return ansi.err(`Not found: ${path}`);
|
|
208
|
+
return ansi.err(msg);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
async function cmdWrite(afs, path, content, ansi) {
|
|
212
|
+
try {
|
|
213
|
+
await afs.write(path, { content });
|
|
214
|
+
return `Written: ${path}`;
|
|
215
|
+
} catch (e) {
|
|
216
|
+
return ansi.err(e instanceof Error ? e.message : String(e));
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
async function cmdStat(afs, path, ansi) {
|
|
220
|
+
try {
|
|
221
|
+
const meta = (await afs.stat(path))?.data?.meta ?? {};
|
|
222
|
+
const lines = [`${ansi.bold}Path:${ansi.r} ${path}`];
|
|
223
|
+
for (const [k, v] of Object.entries(meta)) if (v !== void 0 && v !== null) lines.push(`${ansi.yellow}${k}:${ansi.r} ${JSON.stringify(v)}`);
|
|
224
|
+
return lines.join("\r\n");
|
|
225
|
+
} catch (e) {
|
|
226
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
227
|
+
if (/not found|ENOENT/i.test(msg)) return ansi.err(`Not found: ${path}`);
|
|
228
|
+
return ansi.err(msg);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
async function cmdExec(afs, path, args, ansi) {
|
|
232
|
+
try {
|
|
233
|
+
const data = (await afs.exec(path, args))?.data;
|
|
234
|
+
if (data === void 0 || data === null) return "(no output)";
|
|
235
|
+
if (typeof data === "string") return data;
|
|
236
|
+
return JSON.stringify(data, null, 2);
|
|
237
|
+
} catch (e) {
|
|
238
|
+
return ansi.err(e instanceof Error ? e.message : String(e));
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
async function cmdExplain(afs, path, ansi) {
|
|
242
|
+
try {
|
|
243
|
+
const result = await afs.explain(path);
|
|
244
|
+
if (!result) return "(no explanation)";
|
|
245
|
+
return result.content ?? "(no explanation)";
|
|
246
|
+
} catch (e) {
|
|
247
|
+
return ansi.err(e instanceof Error ? e.message : String(e));
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
async function cmdSearch(afs, path, query, ansi) {
|
|
251
|
+
try {
|
|
252
|
+
const items = (await afs.search(path, query))?.data ?? [];
|
|
253
|
+
if (!Array.isArray(items) || !items.length) return "(no results)";
|
|
254
|
+
return items.map((e) => {
|
|
255
|
+
const entry = e;
|
|
256
|
+
return typeof entry.path === "string" ? entry.path : JSON.stringify(e);
|
|
257
|
+
}).join("\r\n");
|
|
258
|
+
} catch (e) {
|
|
259
|
+
return ansi.err(e instanceof Error ? e.message : String(e));
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
async function cmdCd(afs, cwd, target) {
|
|
263
|
+
const newCwd = resolvePath(cwd, target);
|
|
264
|
+
if (newCwd === "/") return { newCwd };
|
|
265
|
+
try {
|
|
266
|
+
const meta = (await afs.stat(newCwd))?.data?.meta ?? {};
|
|
267
|
+
if (!(meta.kind === "directory" || meta.childrenCount !== void 0 || newCwd.split("/").filter(Boolean).length === 1)) return {
|
|
268
|
+
newCwd: cwd,
|
|
269
|
+
error: `Not a directory: ${newCwd}`
|
|
270
|
+
};
|
|
271
|
+
return { newCwd };
|
|
272
|
+
} catch {
|
|
273
|
+
try {
|
|
274
|
+
await afs.list(newCwd, { maxDepth: 1 });
|
|
275
|
+
return { newCwd };
|
|
276
|
+
} catch {
|
|
277
|
+
return {
|
|
278
|
+
newCwd: cwd,
|
|
279
|
+
error: `Not found: ${newCwd}`
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Create a platform-agnostic AFS REPL session.
|
|
286
|
+
*
|
|
287
|
+
* Used by both the CF Worker terminal and the Node daemon terminal.
|
|
288
|
+
* Transport (WebSocket send/receive) is handled by the caller.
|
|
289
|
+
*/
|
|
290
|
+
function createAfsReplSession(afs, opts) {
|
|
291
|
+
const sessionId = genSessionId();
|
|
292
|
+
const ansi = makeAnsi(opts.color !== false);
|
|
293
|
+
let cwd = "/";
|
|
294
|
+
let cachedProviderCount = null;
|
|
295
|
+
return {
|
|
296
|
+
sessionId,
|
|
297
|
+
getPrompt() {
|
|
298
|
+
return `afs ${cwd === "/" ? "/" : cwd.split("/").at(-1)}> `;
|
|
299
|
+
},
|
|
300
|
+
async countProviders() {
|
|
301
|
+
if (cachedProviderCount !== null) return cachedProviderCount;
|
|
302
|
+
try {
|
|
303
|
+
const result = await afs.list("/");
|
|
304
|
+
const seen = /* @__PURE__ */ new Set();
|
|
305
|
+
for (const e of result.data ?? []) if (typeof e?.path === "string") seen.add(e.path);
|
|
306
|
+
cachedProviderCount = seen.size || 0;
|
|
307
|
+
} catch {
|
|
308
|
+
cachedProviderCount = 0;
|
|
309
|
+
}
|
|
310
|
+
return cachedProviderCount;
|
|
311
|
+
},
|
|
312
|
+
async route(line) {
|
|
313
|
+
const trimmed = line.trim();
|
|
314
|
+
if (!trimmed) return {};
|
|
315
|
+
const args = parseArgs(trimmed.startsWith("afs ") ? trimmed.slice(4).trim() : trimmed);
|
|
316
|
+
const cmd = args[0]?.toLowerCase() ?? "";
|
|
317
|
+
switch (cmd) {
|
|
318
|
+
case "ls": {
|
|
319
|
+
const rawPath = args[1] ?? cwd;
|
|
320
|
+
return { output: await cmdLs(afs, resolvePath(cwd, rawPath), ansi) };
|
|
321
|
+
}
|
|
322
|
+
case "read":
|
|
323
|
+
case "cat":
|
|
324
|
+
if (!args[1]) return { output: ansi.err("Usage: read <path>") };
|
|
325
|
+
return { output: (await cmdRead(afs, resolvePath(cwd, args[1]), ansi)).replace(/\n/g, "\r\n") };
|
|
326
|
+
case "write":
|
|
327
|
+
if (!args[1]) return { output: ansi.err("Usage: write <path> <content>") };
|
|
328
|
+
return { output: await cmdWrite(afs, resolvePath(cwd, args[1]), args.slice(2).join(" "), ansi) };
|
|
329
|
+
case "stat": {
|
|
330
|
+
const rawPath = args[1] ?? cwd;
|
|
331
|
+
return { output: await cmdStat(afs, resolvePath(cwd, rawPath), ansi) };
|
|
332
|
+
}
|
|
333
|
+
case "exec": {
|
|
334
|
+
if (!args[1]) return { output: ansi.err("Usage: exec <path> [args...]") };
|
|
335
|
+
const path = resolvePath(cwd, args[1]);
|
|
336
|
+
const execArgs = {};
|
|
337
|
+
for (let i = 2; i < args.length; i++) {
|
|
338
|
+
const kv = args[i].split("=");
|
|
339
|
+
if (kv.length === 2) execArgs[kv[0]] = kv[1];
|
|
340
|
+
else execArgs[`arg${i - 2}`] = args[i];
|
|
341
|
+
}
|
|
342
|
+
return { output: await cmdExec(afs, path, execArgs, ansi) };
|
|
343
|
+
}
|
|
344
|
+
case "explain": {
|
|
345
|
+
const rawPath = args[1] ?? cwd;
|
|
346
|
+
return { output: await cmdExplain(afs, resolvePath(cwd, rawPath), ansi) };
|
|
347
|
+
}
|
|
348
|
+
case "search":
|
|
349
|
+
if (!args[1] || !args[2]) return { output: ansi.err("Usage: search <path> <query>") };
|
|
350
|
+
return { output: await cmdSearch(afs, resolvePath(cwd, args[1]), args.slice(2).join(" "), ansi) };
|
|
351
|
+
case "cd": {
|
|
352
|
+
const target = args[1] ?? "/";
|
|
353
|
+
const { newCwd, error } = await cmdCd(afs, cwd, target);
|
|
354
|
+
cwd = newCwd;
|
|
355
|
+
return { output: error ? ansi.err(error) : void 0 };
|
|
356
|
+
}
|
|
357
|
+
case "pwd": return { output: cwd };
|
|
358
|
+
case "help": return { output: ansi.help() };
|
|
359
|
+
case "clear": return { clear: true };
|
|
360
|
+
case "exit":
|
|
361
|
+
case "quit": return { exit: true };
|
|
362
|
+
default: return { output: `${ansi.err(`Unknown command: ${cmd}`)} — type ${ansi.yellow}help${ansi.r} for available commands` };
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
//#endregion
|
|
369
|
+
export { createAfsReplSession, renderArcBanner };
|
|
370
|
+
//# sourceMappingURL=terminal-repl.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"terminal-repl.mjs","names":[],"sources":["../src/terminal-repl.ts"],"sourcesContent":["/**\n * Shared AFS terminal REPL — portable, CF-compatible.\n *\n * Contains the business logic for the AFS interactive terminal:\n * - ARC banner rendering (ASCII art, version, session info)\n * - REPL session factory (command routing, cwd management)\n *\n * No Node.js APIs. Usable in Cloudflare Workers, Node, Bun, browsers.\n *\n * Transport (WebSocket / readline) is left to the caller:\n * - CF Worker: runtimes/cloudflare/src/terminal-handler.ts\n * - Node daemon: runtimes/node/src/daemon/server.ts\n */\n\nimport type { AFS } from \"@aigne/afs\";\n\n// ---------------------------------------------------------------------------\n// Banner\n// ---------------------------------------------------------------------------\n\nconst ARC_ART = [\"▄▀█ █▀█ █▀▀\", \"█▀█ █▀▄ █▄▄\"];\nconst TAGLINE = \"Agentic Realm Computer\";\nconst COPYRIGHT = \"Copyright (c) 2026 ArcBlock Inc. All rights reserved.\";\nconst R = \"\\x1b[0m\";\n\n// Truecolor gradient for ASCII art: light cyan → purple (matches splash.ts)\nconst ART_GRADIENT: readonly [number, number, number][] = [\n [100, 220, 255],\n [180, 120, 255],\n];\n\n// Per-character tagline gradient (matches splash.ts TAGLINE_TRUECOLOR)\nconst TAGLINE_GRADIENT: readonly [number, number, number][] = [\n [100, 255, 255],\n [80, 220, 255],\n [60, 180, 255],\n [100, 140, 255],\n [180, 120, 255],\n [220, 100, 255],\n];\n\nfunction interpColor(\n t: number,\n stops: readonly (readonly [number, number, number])[],\n): [number, number, number] {\n const scaled = t * (stops.length - 1);\n const i = Math.min(Math.floor(scaled), stops.length - 2);\n const frac = scaled - i;\n const a = stops[i] ?? [0, 0, 0];\n const b = stops[i + 1] ?? [0, 0, 0];\n return [\n Math.round(a[0] + (b[0] - a[0]) * frac),\n Math.round(a[1] + (b[1] - a[1]) * frac),\n Math.round(a[2] + (b[2] - a[2]) * frac),\n ];\n}\n\nfunction rainbowText(text: string): string {\n const chars = [...text];\n return chars\n .map((ch, i) => {\n if (ch === \" \") return ch;\n const t = chars.length > 1 ? i / (chars.length - 1) : 0;\n const [r, g, b] = interpColor(t, TAGLINE_GRADIENT);\n return `\\x1b[38;2;${r};${g};${b}m${ch}${R}`;\n })\n .join(\"\");\n}\n\nexport interface BannerOptions {\n version: string;\n commit: string;\n date: string;\n /** Provider count to display in the session line. */\n providerCount?: number;\n /** Session ID to display in the session line. */\n sessionId?: string;\n /** Use ANSI color codes. Default: true. */\n color?: boolean;\n}\n\n/**\n * Render the ARC terminal banner.\n *\n * Uses 24-bit truecolor gradient (matches Node splash.ts exactly).\n *\n * Output (colored):\n * ▄▀█ █▀█ █▀▀ Agentic Realm Computer\n * █▀█ █▀▄ █▄▄ v1.0.0 (abc1234) · 2026-04-23\n * Copyright (c) 2026 ArcBlock Inc. All rights reserved.\n *\n * Session: <id> · N providers · Type help for commands.\n */\nexport function renderArcBanner(opts: BannerOptions): string {\n const color = opts.color !== false;\n const { version, commit, date, providerCount, sessionId } = opts;\n\n const tc = (rgb: readonly [number, number, number], s: string) =>\n color ? `\\x1b[38;2;${rgb[0]};${rgb[1]};${rgb[2]}m${s}${R}` : s;\n const cyan = (s: string) => (color ? `\\x1b[96m${s}${R}` : s);\n const dim = (s: string) => (color ? `\\x1b[2m${s}${R}` : s);\n\n const art = ARC_ART.map((line, i) => (color ? tc(ART_GRADIENT[i]!, line) : line));\n const tagline = color ? rainbowText(TAGLINE) : TAGLINE;\n const versionStr = [cyan(`v${version}`), dim(`(${commit})`), dim(\"·\"), dim(date)].join(\" \");\n const copyrightStr = dim(COPYRIGHT);\n const gap = \" \";\n\n const lines: string[] = [\n ` ${art[0]}${gap}${tagline}`,\n ` ${art[1]}${gap}${versionStr}`,\n ` ${copyrightStr}`,\n ];\n\n if (providerCount !== undefined || sessionId) {\n const parts: string[] = [];\n if (sessionId) parts.push(`Session: ${dim(sessionId)}`);\n if (providerCount !== undefined) {\n const plural = providerCount === 1 ? \"provider\" : \"providers\";\n parts.push(`${providerCount} ${plural}`);\n }\n parts.push(`Type ${cyan(\"help\")} for commands.`);\n lines.push(\"\", ` ${parts.join(dim(\" · \"))}`);\n }\n\n return lines.join(\"\\r\\n\");\n}\n\n// ---------------------------------------------------------------------------\n// Session\n// ---------------------------------------------------------------------------\n\nexport interface AfsReplResult {\n /** Text to display in the terminal (pre-formatted, CRLF line endings). */\n output?: string;\n /** If true, the terminal should clear its screen. */\n clear?: boolean;\n /** If true, the session is ending; caller should close the connection. */\n exit?: boolean;\n}\n\nexport interface AfsReplSession {\n /** Unique session ID (hex string). */\n readonly sessionId: string;\n /** Get current prompt string (e.g. `afs data> `). */\n getPrompt(): string;\n /**\n * Count mounted providers via `afs.list(\"/\")`.\n * Safe to call before the first command — result is cached.\n */\n countProviders(): Promise<number>;\n /**\n * Route a line of user input.\n * Handles builtins (cd, pwd, help, clear, exit) and AFS primitives\n * (ls, read, write, stat, exec, explain, search).\n */\n route(line: string): Promise<AfsReplResult>;\n}\n\nexport interface AfsReplOptions {\n version: string;\n commit: string;\n date: string;\n /** Use ANSI color. Default: true. */\n color?: boolean;\n}\n\n/** Generate a random hex session ID. */\nfunction genSessionId(): string {\n const arr = new Uint8Array(8);\n if (typeof crypto !== \"undefined\" && crypto.getRandomValues) {\n crypto.getRandomValues(arr);\n } else {\n for (let i = 0; i < arr.length; i++) arr[i] = Math.floor(Math.random() * 256);\n }\n return Array.from(arr, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n}\n\n// ---------------------------------------------------------------------------\n// Path helpers\n// ---------------------------------------------------------------------------\n\nfunction resolvePath(cwd: string, raw: string): string {\n if (!raw || raw === \".\") return cwd;\n const absolute = raw.startsWith(\"/\") ? raw : `${cwd === \"/\" ? \"\" : cwd}/${raw}`;\n const parts = absolute.split(\"/\").filter(Boolean);\n const resolved: string[] = [];\n for (const p of parts) {\n if (p === \"..\") resolved.pop();\n else if (p !== \".\") resolved.push(p);\n }\n return `/${resolved.join(\"/\")}`;\n}\n\n// ---------------------------------------------------------------------------\n// Arg parser\n// ---------------------------------------------------------------------------\n\nfunction parseArgs(input: string): string[] {\n const args: string[] = [];\n let current = \"\";\n let quote: '\"' | \"'\" | null = null;\n for (const ch of input) {\n if (quote) {\n if (ch === quote) quote = null;\n else current += ch;\n } else if (ch === '\"' || ch === \"'\") {\n quote = ch;\n } else if (ch === \" \" || ch === \"\\t\") {\n if (current) {\n args.push(current);\n current = \"\";\n }\n } else {\n current += ch;\n }\n }\n if (current) args.push(current);\n return args;\n}\n\n// ---------------------------------------------------------------------------\n// Color helpers (injected from opts.color)\n// ---------------------------------------------------------------------------\n\ninterface Ansi {\n r: string;\n red: string;\n blue: string;\n yellow: string;\n bold: string;\n err(msg: string): string;\n help(): string;\n}\n\nfunction makeAnsi(color: boolean): Ansi {\n const r = color ? \"\\x1b[0m\" : \"\";\n const red = color ? \"\\x1b[31m\" : \"\";\n const blue = color ? \"\\x1b[34m\" : \"\";\n const yellow = color ? \"\\x1b[33m\" : \"\";\n const bold = color ? \"\\x1b[1m\" : \"\";\n return {\n r,\n red,\n blue,\n yellow,\n bold,\n err: (msg) => `${red}Error:${r} ${msg}`,\n help: () =>\n [\n `${bold}Available commands:${r}`,\n \"\",\n ` ${bold}AFS Commands:${r}`,\n ` ${yellow}ls${r} [path] List directory contents (default: current dir)`,\n ` ${yellow}read${r} <path> Read file content`,\n ` ${yellow}write${r} <path> <content> Write content to file`,\n ` ${yellow}stat${r} [path] Get file or directory info`,\n ` ${yellow}exec${r} <path> [args] Execute an action`,\n ` ${yellow}explain${r} [path] Explain path capabilities`,\n ` ${yellow}search${r} <path> <query> Search content`,\n \"\",\n ` ${bold}REPL Commands:${r}`,\n ` ${yellow}cd${r} [path] Change working directory`,\n ` ${yellow}pwd${r} Print working directory`,\n ` ${yellow}help${r} Show this help`,\n ` ${yellow}clear${r} Clear screen`,\n ` ${yellow}exit${r} / ${yellow}quit${r} Exit session`,\n ].join(\"\\r\\n\"),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Command implementations (pure AFS API calls, color-aware)\n// ---------------------------------------------------------------------------\n\nasync function cmdLs(afs: AFS, path: string, ansi: Ansi): Promise<string> {\n try {\n const result = await afs.list(path, { maxDepth: 1 });\n const items = result.data ?? [];\n if (!items.length) return \"(empty)\";\n return items\n .map((e) => {\n const isDir =\n (e.meta as Record<string, unknown> | undefined)?.kind === \"directory\" ||\n (((e.meta as Record<string, unknown> | undefined)?.childrenCount as number | undefined) ??\n 0) > 0;\n const name = e.path.split(\"/\").at(-1) ?? e.path;\n return isDir ? `${ansi.blue}${name}/${ansi.r}` : name;\n })\n .join(\"\\r\\n\");\n } catch (e) {\n return ansi.err(e instanceof Error ? e.message : String(e));\n }\n}\n\nasync function cmdRead(afs: AFS, path: string, ansi: Ansi): Promise<string> {\n try {\n const result = await afs.read(path);\n const content = result.data?.content;\n if (content === undefined || content === null) return ansi.err(\"Not found or not readable\");\n if (typeof content === \"string\") return content;\n if (content instanceof Uint8Array) return new TextDecoder().decode(content);\n return JSON.stringify(content, null, 2);\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n if (/not found|ENOENT/i.test(msg)) return ansi.err(`Not found: ${path}`);\n return ansi.err(msg);\n }\n}\n\nasync function cmdWrite(afs: AFS, path: string, content: string, ansi: Ansi): Promise<string> {\n try {\n await afs.write(path, { content });\n return `Written: ${path}`;\n } catch (e) {\n return ansi.err(e instanceof Error ? e.message : String(e));\n }\n}\n\nasync function cmdStat(afs: AFS, path: string, ansi: Ansi): Promise<string> {\n try {\n const result = await afs.stat(path);\n const meta = (result?.data?.meta as Record<string, unknown>) ?? {};\n const lines = [`${ansi.bold}Path:${ansi.r} ${path}`];\n for (const [k, v] of Object.entries(meta)) {\n if (v !== undefined && v !== null)\n lines.push(`${ansi.yellow}${k}:${ansi.r} ${JSON.stringify(v)}`);\n }\n return lines.join(\"\\r\\n\");\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n if (/not found|ENOENT/i.test(msg)) return ansi.err(`Not found: ${path}`);\n return ansi.err(msg);\n }\n}\n\nasync function cmdExec(\n afs: AFS,\n path: string,\n args: Record<string, unknown>,\n ansi: Ansi,\n): Promise<string> {\n try {\n const result = await afs.exec(path, args);\n const data = result?.data;\n if (data === undefined || data === null) return \"(no output)\";\n if (typeof data === \"string\") return data;\n return JSON.stringify(data, null, 2);\n } catch (e) {\n return ansi.err(e instanceof Error ? e.message : String(e));\n }\n}\n\nasync function cmdExplain(afs: AFS, path: string, ansi: Ansi): Promise<string> {\n try {\n const result = await afs.explain(path);\n if (!result) return \"(no explanation)\";\n return result.content ?? \"(no explanation)\";\n } catch (e) {\n return ansi.err(e instanceof Error ? e.message : String(e));\n }\n}\n\nasync function cmdSearch(afs: AFS, path: string, query: string, ansi: Ansi): Promise<string> {\n try {\n const result = await afs.search(path, query);\n const items = result?.data ?? [];\n if (!Array.isArray(items) || !items.length) return \"(no results)\";\n return items\n .map((e: unknown) => {\n const entry = e as Record<string, unknown>;\n return typeof entry.path === \"string\" ? entry.path : JSON.stringify(e);\n })\n .join(\"\\r\\n\");\n } catch (e) {\n return ansi.err(e instanceof Error ? e.message : String(e));\n }\n}\n\nasync function cmdCd(\n afs: AFS,\n cwd: string,\n target: string,\n): Promise<{ newCwd: string; error?: string }> {\n const newCwd = resolvePath(cwd, target);\n if (newCwd === \"/\") return { newCwd };\n try {\n const result = await afs.stat(newCwd);\n const meta = (result?.data?.meta as Record<string, unknown>) ?? {};\n const isDir =\n meta.kind === \"directory\" ||\n meta.childrenCount !== undefined ||\n newCwd.split(\"/\").filter(Boolean).length === 1;\n if (!isDir) return { newCwd: cwd, error: `Not a directory: ${newCwd}` };\n return { newCwd };\n } catch {\n try {\n await afs.list(newCwd, { maxDepth: 1 });\n return { newCwd };\n } catch {\n return { newCwd: cwd, error: `Not found: ${newCwd}` };\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Create a platform-agnostic AFS REPL session.\n *\n * Used by both the CF Worker terminal and the Node daemon terminal.\n * Transport (WebSocket send/receive) is handled by the caller.\n */\nexport function createAfsReplSession(afs: AFS, opts: AfsReplOptions): AfsReplSession {\n const sessionId = genSessionId();\n const ansi = makeAnsi(opts.color !== false);\n let cwd = \"/\";\n let cachedProviderCount: number | null = null;\n\n return {\n sessionId,\n\n getPrompt(): string {\n const dir = cwd === \"/\" ? \"/\" : cwd.split(\"/\").at(-1);\n return `afs ${dir}> `;\n },\n\n async countProviders(): Promise<number> {\n if (cachedProviderCount !== null) return cachedProviderCount;\n try {\n const result = await afs.list(\"/\");\n const seen = new Set<string>();\n for (const e of result.data ?? []) {\n if (typeof e?.path === \"string\") seen.add(e.path);\n }\n cachedProviderCount = seen.size || 0;\n } catch {\n cachedProviderCount = 0;\n }\n return cachedProviderCount;\n },\n\n async route(line: string): Promise<AfsReplResult> {\n const trimmed = line.trim();\n if (!trimmed) return {};\n\n // Strip optional \"afs \" prefix (users may type `afs ls /`)\n const input = trimmed.startsWith(\"afs \") ? trimmed.slice(4).trim() : trimmed;\n const args = parseArgs(input);\n const cmd = args[0]?.toLowerCase() ?? \"\";\n\n switch (cmd) {\n case \"ls\": {\n const rawPath = args[1] ?? cwd;\n const path = resolvePath(cwd, rawPath);\n return { output: await cmdLs(afs, path, ansi) };\n }\n case \"read\":\n case \"cat\": {\n if (!args[1]) return { output: ansi.err(\"Usage: read <path>\") };\n const path = resolvePath(cwd, args[1]);\n const out = await cmdRead(afs, path, ansi);\n return { output: out.replace(/\\n/g, \"\\r\\n\") };\n }\n case \"write\": {\n if (!args[1]) return { output: ansi.err(\"Usage: write <path> <content>\") };\n const path = resolvePath(cwd, args[1]);\n const content = args.slice(2).join(\" \");\n return { output: await cmdWrite(afs, path, content, ansi) };\n }\n case \"stat\": {\n const rawPath = args[1] ?? cwd;\n const path = resolvePath(cwd, rawPath);\n return { output: await cmdStat(afs, path, ansi) };\n }\n case \"exec\": {\n if (!args[1]) return { output: ansi.err(\"Usage: exec <path> [args...]\") };\n const path = resolvePath(cwd, args[1]);\n const execArgs: Record<string, unknown> = {};\n for (let i = 2; i < args.length; i++) {\n const kv = args[i]!.split(\"=\");\n if (kv.length === 2) execArgs[kv[0]!] = kv[1];\n else execArgs[`arg${i - 2}`] = args[i];\n }\n return { output: await cmdExec(afs, path, execArgs, ansi) };\n }\n case \"explain\": {\n const rawPath = args[1] ?? cwd;\n const path = resolvePath(cwd, rawPath);\n return { output: await cmdExplain(afs, path, ansi) };\n }\n case \"search\": {\n if (!args[1] || !args[2]) return { output: ansi.err(\"Usage: search <path> <query>\") };\n const path = resolvePath(cwd, args[1]);\n const query = args.slice(2).join(\" \");\n return { output: await cmdSearch(afs, path, query, ansi) };\n }\n case \"cd\": {\n const target = args[1] ?? \"/\";\n const { newCwd, error } = await cmdCd(afs, cwd, target);\n cwd = newCwd;\n return { output: error ? ansi.err(error) : undefined };\n }\n case \"pwd\":\n return { output: cwd };\n case \"help\":\n return { output: ansi.help() };\n case \"clear\":\n return { clear: true };\n case \"exit\":\n case \"quit\":\n return { exit: true };\n default:\n return {\n output: `${ansi.err(`Unknown command: ${cmd}`)} — type ${ansi.yellow}help${ansi.r} for available commands`,\n };\n }\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/transport/idle-timer.ts
|
|
3
|
+
/**
|
|
4
|
+
* Per-WebSocket idle timer — runtime-neutral.
|
|
5
|
+
*
|
|
6
|
+
* Why: long-lived WebSockets that sit idle still consume runtime resources.
|
|
7
|
+
* On Cloudflare Durable Objects this is direct billing (`server.accept()`
|
|
8
|
+
* keeps the DO active for the full WS lifetime); on Node it's memory and
|
|
9
|
+
* file descriptors. Both runtimes benefit from closing WebSockets that
|
|
10
|
+
* haven't seen a client message in a configurable window.
|
|
11
|
+
*
|
|
12
|
+
* What: arm a timer per connection, reset on every inbound message; on
|
|
13
|
+
* expiry, close the WS with a close code ≥ 4000 so the AUP client suppresses
|
|
14
|
+
* its auto-reconnect loop (see `web-page/core.ts` — code ≥ 4000 means
|
|
15
|
+
* "server rejected, do not reconnect"). The user reconnects on next
|
|
16
|
+
* interaction; the existing `sessionId`-based handshake restores per-session
|
|
17
|
+
* state.
|
|
18
|
+
*
|
|
19
|
+
* On Cloudflare, once all WebSockets close, the DO is auto-evicted by the
|
|
20
|
+
* Workers runtime and duration billing stops. On Node, the WS object is GC'd
|
|
21
|
+
* and the file descriptor returned to the OS.
|
|
22
|
+
*/
|
|
23
|
+
/** Close code used for intentional idle close (must be ≥ 4000). */
|
|
24
|
+
const IDLE_CLOSE_CODE = 4001;
|
|
25
|
+
/** Short ASCII reason — CF caps reason at 123 bytes. */
|
|
26
|
+
const IDLE_CLOSE_REASON = "idle-timeout";
|
|
27
|
+
/** Lower bound — under 1s is almost certainly a misconfiguration. */
|
|
28
|
+
const MIN_TIMEOUT_MS = 1e3;
|
|
29
|
+
/** Upper bound — keep one connection alive at most 24h on a single client. */
|
|
30
|
+
const MAX_TIMEOUT_MS = 1440 * 6e4;
|
|
31
|
+
function createIdleTimer(opts) {
|
|
32
|
+
const { timeoutMs, onIdle } = opts;
|
|
33
|
+
const setT = opts.setTimeout ?? globalThis.setTimeout;
|
|
34
|
+
const clearT = opts.clearTimeout ?? globalThis.clearTimeout;
|
|
35
|
+
if (timeoutMs <= 0) return {
|
|
36
|
+
rearm() {},
|
|
37
|
+
cancel() {}
|
|
38
|
+
};
|
|
39
|
+
let handle = null;
|
|
40
|
+
const fire = () => {
|
|
41
|
+
handle = null;
|
|
42
|
+
try {
|
|
43
|
+
onIdle();
|
|
44
|
+
} catch {}
|
|
45
|
+
};
|
|
46
|
+
return {
|
|
47
|
+
rearm() {
|
|
48
|
+
if (handle !== null) clearT(handle);
|
|
49
|
+
handle = setT(fire, timeoutMs);
|
|
50
|
+
},
|
|
51
|
+
cancel() {
|
|
52
|
+
if (handle !== null) {
|
|
53
|
+
clearT(handle);
|
|
54
|
+
handle = null;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Best-effort `{ type: string }` sniff of an inbound WS message event, used
|
|
61
|
+
* only to decide whether it should rearm the idle timer. Any parse failure
|
|
62
|
+
* (binary frame, non-JSON text, missing `.data`) is treated as "not a
|
|
63
|
+
* recognized synthetic type" — i.e. it still counts as real activity. This
|
|
64
|
+
* keeps `ignoreMessageTypes` strictly opt-in and never silently swallows a
|
|
65
|
+
* message the caller didn't ask to ignore.
|
|
66
|
+
*/
|
|
67
|
+
function messageTypeOf(event) {
|
|
68
|
+
try {
|
|
69
|
+
const data = event?.data;
|
|
70
|
+
if (typeof data !== "string") return void 0;
|
|
71
|
+
const parsed = JSON.parse(data);
|
|
72
|
+
return typeof parsed?.type === "string" ? parsed.type : void 0;
|
|
73
|
+
} catch {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Wire an idle timer to a WebSocket-like object: arm immediately, rearm on
|
|
79
|
+
* every inbound message, cancel on close/error. On expiry, close the socket
|
|
80
|
+
* with `IDLE_CLOSE_CODE` and `IDLE_CLOSE_REASON`.
|
|
81
|
+
*
|
|
82
|
+
* Returns the timer so callers can `cancel()` it during external teardown.
|
|
83
|
+
*/
|
|
84
|
+
function attachIdleClose(server, timeoutMs, options) {
|
|
85
|
+
const timer = createIdleTimer({
|
|
86
|
+
timeoutMs,
|
|
87
|
+
onIdle: () => {
|
|
88
|
+
try {
|
|
89
|
+
if (server.readyState === 1) server.close(IDLE_CLOSE_CODE, IDLE_CLOSE_REASON);
|
|
90
|
+
} catch {}
|
|
91
|
+
},
|
|
92
|
+
setTimeout: options?.setTimeout,
|
|
93
|
+
clearTimeout: options?.clearTimeout
|
|
94
|
+
});
|
|
95
|
+
timer.rearm();
|
|
96
|
+
const ignoreTypes = options?.ignoreMessageTypes;
|
|
97
|
+
server.addEventListener("message", (event) => {
|
|
98
|
+
if (ignoreTypes?.length) {
|
|
99
|
+
const type = messageTypeOf(event);
|
|
100
|
+
if (type !== void 0 && ignoreTypes.includes(type)) return;
|
|
101
|
+
}
|
|
102
|
+
timer.rearm();
|
|
103
|
+
});
|
|
104
|
+
server.addEventListener("close", () => timer.cancel());
|
|
105
|
+
server.addEventListener("error", () => timer.cancel());
|
|
106
|
+
if (options?.rearmOnOutbound && server.send) {
|
|
107
|
+
const orig = server.send.bind(server);
|
|
108
|
+
server.send = (data) => {
|
|
109
|
+
timer.rearm();
|
|
110
|
+
orig(data);
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
return timer;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Parse an env-supplied idle timeout. Accepts undefined / empty / non-numeric
|
|
117
|
+
* (returns `defaultMs`), `0` (returns `0` — disabled), and clamps to
|
|
118
|
+
* [MIN_TIMEOUT_MS, MAX_TIMEOUT_MS] for any positive value.
|
|
119
|
+
*/
|
|
120
|
+
function resolveIdleTimeoutMs(value, defaultMs) {
|
|
121
|
+
if (value === void 0 || value === "") return defaultMs;
|
|
122
|
+
if (!/^-?\d+$/.test(value.trim())) return defaultMs;
|
|
123
|
+
const n = Number.parseInt(value, 10);
|
|
124
|
+
if (Number.isNaN(n)) return defaultMs;
|
|
125
|
+
if (n <= 0) return 0;
|
|
126
|
+
if (n < MIN_TIMEOUT_MS) return MIN_TIMEOUT_MS;
|
|
127
|
+
if (n > MAX_TIMEOUT_MS) return MAX_TIMEOUT_MS;
|
|
128
|
+
return n;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
//#endregion
|
|
132
|
+
exports.IDLE_CLOSE_CODE = IDLE_CLOSE_CODE;
|
|
133
|
+
exports.IDLE_CLOSE_REASON = IDLE_CLOSE_REASON;
|
|
134
|
+
exports.attachIdleClose = attachIdleClose;
|
|
135
|
+
exports.createIdleTimer = createIdleTimer;
|
|
136
|
+
exports.resolveIdleTimeoutMs = resolveIdleTimeoutMs;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
//#region src/transport/idle-timer.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Per-WebSocket idle timer — runtime-neutral.
|
|
4
|
+
*
|
|
5
|
+
* Why: long-lived WebSockets that sit idle still consume runtime resources.
|
|
6
|
+
* On Cloudflare Durable Objects this is direct billing (`server.accept()`
|
|
7
|
+
* keeps the DO active for the full WS lifetime); on Node it's memory and
|
|
8
|
+
* file descriptors. Both runtimes benefit from closing WebSockets that
|
|
9
|
+
* haven't seen a client message in a configurable window.
|
|
10
|
+
*
|
|
11
|
+
* What: arm a timer per connection, reset on every inbound message; on
|
|
12
|
+
* expiry, close the WS with a close code ≥ 4000 so the AUP client suppresses
|
|
13
|
+
* its auto-reconnect loop (see `web-page/core.ts` — code ≥ 4000 means
|
|
14
|
+
* "server rejected, do not reconnect"). The user reconnects on next
|
|
15
|
+
* interaction; the existing `sessionId`-based handshake restores per-session
|
|
16
|
+
* state.
|
|
17
|
+
*
|
|
18
|
+
* On Cloudflare, once all WebSockets close, the DO is auto-evicted by the
|
|
19
|
+
* Workers runtime and duration billing stops. On Node, the WS object is GC'd
|
|
20
|
+
* and the file descriptor returned to the OS.
|
|
21
|
+
*/
|
|
22
|
+
/** Close code used for intentional idle close (must be ≥ 4000). */
|
|
23
|
+
declare const IDLE_CLOSE_CODE = 4001;
|
|
24
|
+
/** Short ASCII reason — CF caps reason at 123 bytes. */
|
|
25
|
+
declare const IDLE_CLOSE_REASON = "idle-timeout";
|
|
26
|
+
interface IdleTimerOptions {
|
|
27
|
+
/** Idle window in ms. `0` disables the timer (useful for tests / opt-out). */
|
|
28
|
+
timeoutMs: number;
|
|
29
|
+
/** Invoked when the idle window elapses without a `rearm()`. */
|
|
30
|
+
onIdle: () => void;
|
|
31
|
+
/** Test seam — defaults to `globalThis.setTimeout`. */
|
|
32
|
+
setTimeout?: typeof setTimeout;
|
|
33
|
+
/** Test seam — defaults to `globalThis.clearTimeout`. */
|
|
34
|
+
clearTimeout?: typeof clearTimeout;
|
|
35
|
+
}
|
|
36
|
+
interface IdleTimer {
|
|
37
|
+
/** Reset (or start) the idle countdown. Safe to call repeatedly. */
|
|
38
|
+
rearm(): void;
|
|
39
|
+
/** Stop the timer. After cancel, `rearm()` resumes it. */
|
|
40
|
+
cancel(): void;
|
|
41
|
+
}
|
|
42
|
+
declare function createIdleTimer(opts: IdleTimerOptions): IdleTimer;
|
|
43
|
+
/**
|
|
44
|
+
* Minimal WebSocket surface used by `attachIdleClose`. Both the CF Workers
|
|
45
|
+
* `WebSocket` and the Node `ws` library satisfy this shape.
|
|
46
|
+
*/
|
|
47
|
+
interface IdleCloseTarget {
|
|
48
|
+
readyState: number;
|
|
49
|
+
close(code?: number, reason?: string): void;
|
|
50
|
+
send?: (data: any) => void;
|
|
51
|
+
addEventListener(type: "message" | "close" | "error", listener: (event: unknown) => void): void;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Wire an idle timer to a WebSocket-like object: arm immediately, rearm on
|
|
55
|
+
* every inbound message, cancel on close/error. On expiry, close the socket
|
|
56
|
+
* with `IDLE_CLOSE_CODE` and `IDLE_CLOSE_REASON`.
|
|
57
|
+
*
|
|
58
|
+
* Returns the timer so callers can `cancel()` it during external teardown.
|
|
59
|
+
*/
|
|
60
|
+
declare function attachIdleClose(server: IdleCloseTarget, timeoutMs: number, options?: {
|
|
61
|
+
/**
|
|
62
|
+
* When true, wraps `server.send` so that every outbound server push also
|
|
63
|
+
* rearms the idle timer. Without this, a session receiving only passive
|
|
64
|
+
* live-update pushes (no client→server traffic) is considered "idle" and
|
|
65
|
+
* closed after `timeoutMs` even though it has ongoing server activity.
|
|
66
|
+
*/
|
|
67
|
+
rearmOnOutbound?: boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Inbound message `type` values that must NOT rearm the idle timer.
|
|
70
|
+
* Exists for synthetic client keepalive frames (e.g. the AUP web client's
|
|
71
|
+
* `{type:"ping"}`, sent purely to defeat CF-edge / mobile-NAT idle-drop
|
|
72
|
+
* of an otherwise-unused connection — see WS_KEEPALIVE_MESSAGE_TYPE in
|
|
73
|
+
* `@aigne/afs-ui`). Without this, a keepalive ping would itself count as
|
|
74
|
+
* "activity" and the idle-close timer — whose entire purpose is evicting
|
|
75
|
+
* genuinely-unused connections to stop Durable Object duration billing —
|
|
76
|
+
* would never fire for as long as the tab merely sits open (arc#1243).
|
|
77
|
+
* Messages that fail to parse as `{type: string}` JSON are never treated
|
|
78
|
+
* as ignorable, so this can only narrow rearm triggers, never widen them.
|
|
79
|
+
*/
|
|
80
|
+
ignoreMessageTypes?: string[];
|
|
81
|
+
setTimeout?: typeof setTimeout;
|
|
82
|
+
clearTimeout?: typeof clearTimeout;
|
|
83
|
+
}): IdleTimer;
|
|
84
|
+
/**
|
|
85
|
+
* Parse an env-supplied idle timeout. Accepts undefined / empty / non-numeric
|
|
86
|
+
* (returns `defaultMs`), `0` (returns `0` — disabled), and clamps to
|
|
87
|
+
* [MIN_TIMEOUT_MS, MAX_TIMEOUT_MS] for any positive value.
|
|
88
|
+
*/
|
|
89
|
+
declare function resolveIdleTimeoutMs(value: string | undefined, defaultMs: number): number;
|
|
90
|
+
//#endregion
|
|
91
|
+
export { IDLE_CLOSE_CODE, IDLE_CLOSE_REASON, IdleCloseTarget, IdleTimer, IdleTimerOptions, attachIdleClose, createIdleTimer, resolveIdleTimeoutMs };
|
|
92
|
+
//# sourceMappingURL=idle-timer.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"idle-timer.d.cts","names":[],"sources":["../../src/transport/idle-timer.ts"],"mappings":";;AAsBA;;;;;AAGA;;;;;AAOA;;;;;;;;;;cAVa,eAAA;;cAGA,iBAAA;AAAA,UAOI,gBAAA;;EAEf,SAAA;EAaM;EAXN,MAAA;EAc6B;EAZ7B,UAAA,UAAoB,UAAA;EAY4C;EAVhE,YAAA,UAAsB,YAAA;AAAA;AAAA,UAGP,SAAA;EAOiD;EALhE,KAAA;EA2Ce;EAzCf,MAAA;AAAA;AAAA,iBAGc,eAAA,CAAgB,IAAA,EAAM,gBAAA,GAAmB,SAAA;;;;;UAsCxC,eAAA;EACf,UAAA;EACA,KAAA,CAAM,IAAA,WAAe,MAAA;EACrB,IAAA,IAAQ,IAAA;EACR,gBAAA,CAAiB,IAAA,iCAAqC,QAAA,GAAW,KAAA;AAAA;;;AA6BnE;;;;;iBAAgB,eAAA,CACd,MAAA,EAAQ,eAAA,EACR,SAAA,UACA,OAAA;EAwBC;;;;;;EAjBC,eAAA;EAaA;;;;;;;;;AAgDJ;;;EAhDI,kBAAA;EACA,UAAA,UAAoB,UAAA;EACpB,YAAA,UAAsB,YAAA;AAAA,IAEvB,SAAA;;;;;;iBA4Ca,oBAAA,CAAqB,KAAA,sBAA2B,SAAA"}
|