Input socket for a lease
Los mantenedores suelen responder en 1 día
Evaluación
- Dificultad
- 5/5
- Tiempo estimado
- Más de una semana
- Aptitud para principiantes
- 20/100
- Tipo de issue
- Nueva funcionalidad
- Claridad
- Bien especificado
- Estado de actividad
- Activo
- Stack tecnológico
- node.js, typescript
Línea de trabajo
Start at the upgrade listener in src/ports/uplink-websocket.ts and the attach in src/daemon/main.ts; the new router authenticates through src/auth/index.ts. Read src/modules/types.ts and host.ts for the two-step lease socket, and copy the module shape from src/stream/worker.ts/gateway.ts. The device port is src/core/driver-catalog.ts plus the optional member in src/core/driver.ts; src/daemon/stream-gateway.e2e.test.ts is the e2e pattern. Done: an owned lease upgrades, gets 0x83 then 0x82 with inputUnavailable, closes with the listed codes, and docs are updated.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Part of #1013.
Scope
After this PR, a client with an agent token opens WS /v1/leases/{id}/input on a gateway or a standalone worker. It gets 0x83, then 0x82, and its serve-sim messages reach the device input of the worker that holds the lease. No device takes input yet: no driver has an input member, so every device input is unavailable until #1018 and #1019 add the Android and iOS ones. The socket ends when the lease ends, when either end goes quiet, and when the daemon stops.
This task adds the new optional module input, the upgrade routing in ports, the two-step lease socket seam, the device input port and its optional driver member. It is the feature's widest task (five Behaviours rows, about 20 modules). It does not split further: the socket, its gateway relay and its lifecycle are one path a test drives end to end, and a split would leave a seam with no caller.
In short
A lease holder's app opens one WebSocket for its lease and gets 0x83 (input admitted), then a screen config 0x82. While no driver takes input, that is 0x82 {"width":1,"height":1,"orientation":"portrait","inputUnavailable":true}. Through a gateway, the socket rides #1016's two-way relay to the lease's worker. It closes with 4001 and the lease-end reason (explicit, killed, expired, device-lost) when the lease ends.
New terms: device input, what turns messages into taps on one device, one per lease, shared by up to 8 sockets; unavailable and failed, as the feature's Words used define them (Shared values, "Device input port").
flowchart LR
App[App] -- WS upgrade --> P[ports upgrade router NEW]
P --> H[http: lease resolve for the caller]
H -- open: refusal or accept --> GI[input module, gateway side NEW]
GI -- relayTwoWay #1016 --> WI[input module, worker side NEW]
H -- open: refusal or accept --> WI
WI -- WorkerContext.inputs NEW --> C[DriverCatalog.openInput NEW]
C --> D[driver input member: none yet → unavailable]
Closes a client sees, word for word (each reason cut to 123 bytes of UTF-8):
| Code | Reason | When |
|---|---|---|
| 4001 | explicit, killed, expired or device-lost |
the lease ended and the worker said why |
| 4001 | lease ended |
through a gateway, the lease went and no 0xF1 came within 2 s |
| 1011 | Worker <workerId> stopped answering |
heartbeat silence or uplink lost |
| 1001 | Simlock is stopping |
daemon stop |
| 1013 | Input is unavailable for this lease |
a 9th socket, a failed device input, or a reconnect within 10 s of a failed open |
Refusals before the upgrade, through a gateway:
$ websocat -H "Authorization: Bearer $AGENT_TOKEN" wss://gw:7480/v1/leases/L-42/input
websocat: WebSocketError: Received unexpected status code (503 Service Unavailable)
# input off on the worker: {"error":{"code":"INPUT_UNAVAILABLE","message":"Worker w1 does not take input for lease L-42; turn on capabilities.input.enabled there"}}
# no head from the worker in 10 s: {"error":{"code":"WORKER_UNREACHABLE","message":"Worker w1 did not answer the input socket within 10 s"}}
| Request | Today | After |
|---|---|---|
upgrade /v1/leases/L-42/input, owner, input on |
404, socket destroyed | 101, then 0x83, 0x82 |
| upgrade, another agent's lease | 404 | 404 UNKNOWN_LEASE |
| upgrade, no token | 404 | 401 UNAUTHENTICATED |
| upgrade, input off on the answering daemon | 404 | 404 |
plain GET /v1/leases/L-42/input, no upgrade |
404 | 426 |
upgrade /v1/uplink with a worker token, on a gateway |
101 | 101 (unchanged) |
upgrade /v1/leases/L-42/stream |
404 | 404 (only input takes sockets) |
If this goes wrong, a user sees T3 Code's device panel say "input socket refused" or never mark input as connected.
Technical spec
Facts
Commit e1f2f43e6.
| # | Fact | Source |
|---|---|---|
| F1 | The gateway's only upgrade listener answers 404 and destroys the socket for any path but /v1/uplink. |
src/ports/uplink-websocket.ts:214-227 |
| F2 | It is attached to the gateway's HTTP server through onServerCreated: (server) => uplinks.attach(server); a worker's HttpGateway gets no such hook, so a worker upgrades nothing. |
src/daemon/main.ts:1158-1165, src/daemon/main.ts:807-811, src/http/server.ts:41-49 |
| F3 | Only uplink-websocket.ts imports ws (8.18.3), with new WebSocketServer({ noServer: true }); the ports barrel does not re-export it, so the CLI and MCP server never load ws. |
src/ports/AGENTS.md:53, package.json:82, src/ports/uplink-websocket.ts:181, src/ports/index.ts:53-58 |
| F4 | The uplink authenticates the bearer token before handleUpgrade, answering 401 or 403 and destroying the socket on refusal. |
src/ports/uplink-websocket.ts:249-264 |
| F5 | The uplink's worker side pings every 15 s and terminates when no pong came since the last ping. | src/ports/uplink-websocket.ts:39-41, src/ports/uplink-websocket.ts:325-340 |
| F6 | HTTP auth resolves a bearer token from request headers through Auth.authenticateRequest(headers). |
src/auth/index.ts:46-47 |
| F7 | A module mount is (Request, identity) → Promise<Response>, mounted under /v1/<module name>; it cannot take an upgrade. |
src/modules/types.ts:85-90, src/modules/host.ts:377-381 |
| F8 | A worker module returns capability, relayTarget, mount, findings, hooks; the host collects relay targets by module name. |
src/modules/types.ts:103-109, src/modules/host.ts:307-310 |
| F9 | ModuleScreens hands a module the drivers' capture, routed by platform, without the drivers; the worker builds it from DriverCatalog. |
src/modules/types.ts:120-129, src/daemon/main.ts:519 |
| F10 | DriverCatalog.openScreen routes to the driver's optional screenCapture member and throws ScreenNotSupportedError when it is absent. |
src/core/driver-catalog.ts:53, src/core/driver-catalog.ts:96-107, src/core/driver.ts:372-374 |
| F11 | FakeDriver takes screenCapture as an option, and the stream e2e test fakes the screen through it. |
src/core/fake-driver.ts:131, src/core/fake-driver.ts:239, src/daemon/stream-gateway.e2e.test.ts:115-121 |
| F12 | beforeDeviceReclaim is how a worker module hears a lease end, with ModuleEndedLease.reason explicit, killed, expired or device-lost. |
src/modules/types.ts:44-50, src/modules/types.ts:96-101, src/modules/host.ts:312-318 |
| F13 | A worker emits lease.released or lease.expired when it commits the end, before lease-end participants run. |
src/leasing/lease-lifecycle.ts:178-196 |
| F14 | The gateway removes a lease from its index when that relayed event arrives, and FleetLeases.onRemoved hands listeners the entry with no reason. |
src/gateway/owner-routed-facts.ts:84-98, src/modules/types.ts:164-177 |
| F15 | Both daemons run moduleHost.beforeDrain() before stopping the HTTP gateway, which destroys open sockets without a close frame. |
src/daemon/main.ts:741-744, src/daemon/main.ts:1102-1107, src/http/server.ts:206-221 |
| F16 | The stream's gateway side maps RELAY_TARGET_MISSING to 503 with a "turn on capabilities.stream.enabled there" message. |
src/stream/gateway-link.ts:68-72 |
| F17 | A module's error codes are declared in its definition.ts statuses, not in the contract (STREAM_UNAVAILABLE). |
src/stream/definition.ts:58-65 |
| F18 | Optional modules are listed in one registry array; a module's capability name is its config section capabilities.<name>.enabled. |
src/module-registry/index.ts:1-7, src/core/config.ts:256-258 |
| F19 | The stream's worker side checks the device against registry.snapshot when a stream opens. |
src/stream/worker-link.ts:124-131 |
| F20 | The relay's head deadline is 330 s and a channel's accept wait 30 s; neither is a bound this task can rely on for a quick refusal. | src/gateway/relay.ts:31-36, src/link/channel.ts:49-50 |
| F21 | ws throws RangeError for a close reason over 123 bytes. |
node_modules/ws/lib/sender.js:190-196 |
| F22 | Expo serve-sim refuses a socket past 8 with close 1013, sends 0x83 on attach, then the 0x82 config. |
expo/expo-device-hub v1357114:packages/serve-sim/packages/serve-sim/src/device-session.ts:136, :1384-1392, :1449-1453 |
| F23 | Expo serve-sim answers 0x10 with 0x90 and JSON {requestId, ok, error?}. |
expo/expo-device-hub v1357114:packages/serve-sim/packages/serve-sim/src/device-session.ts:1781-1806 |
| F24 | Expo serve-sim's 0x82 carries inputUnavailable and keyboardUnavailable. |
expo/expo-device-hub v1357114:packages/serve-sim/packages/serve-sim/src/device-session.ts:2808-2826 |
| F25 | T3 Code accepts a 0x82 only with width and height above 0 and one of four orientations: portrait, portrait_upside_down, landscape_left, landscape_right. |
pingdotgg/t3code v1316d48:packages/client-runtime/src/device/stream.ts:31-40 |
| F26 | T3 Code opens /helper/ws?device=<id>, sends nothing first, marks input admitted on 0x83 and blocked by inputUnavailable in 0x82. |
pingdotgg/t3code v1316d48:packages/client-runtime/src/device/stream.ts:1075-1102 |
| F27 | T3 Code sends input only after 0x83 and while 0x82 does not say unavailable; earlier input is dropped. |
pingdotgg/t3code v1316d48:packages/client-runtime/src/device/stream.ts:1275-1282 |
| F28 | T3 Code treats close 1008 and 4401 as unauthorized and retries any other close after 1 s. | pingdotgg/t3code v1316d48:packages/client-runtime/src/device/stream.ts:1133-1151 |
| F29 | The stream module's worker and gateway files show the module shape this one copies. | src/stream/worker.ts:4-21, src/stream/gateway.ts:4-14 |
| F30 | pnpm openapi <file> writes the OpenAPI document to the named file and exits 2 without one. |
scripts/openapi.mjs:1-11 |
| F31 | capabilities.stream.enabled is documented on the configuration page; access control lists what an agent token may do. |
website/src/content/docs/docs/reference/configuration.mdx:314, website/astro.config.mjs:102, website/astro.config.mjs:131 |
Modules touched
Searches: upgrade, WebSocketServer, onServerCreated, ModuleMount, relayTarget, ModuleScreens, screenCapture, class DriverCatalog, beforeDeviceReclaim, optionalModules, capabilities.stream over src/, website/, ui/src.
src/input/(new):definition.ts,index.ts,worker.ts,gateway.ts, the session (messages, sharing, heartbeat, lease end) and its manualAGENTS.md.src/core/input.ts(new),src/core/index.ts: message tags and JSON shapes from the feature's Shared values "Input messages", and theDeviceInputport types.src/core/driver.ts: an optionalinputmember besidescreenCapture(F10).src/core/driver-catalog.ts:openInput, routed to that member; a driver without one answers{unavailable}.src/core/fake-driver.ts,src/core/testing.ts:FakeDrivertakes aninputoption, as it takesscreenCapture(F11).src/ports/: a new upgrade router file besideuplink-websocket.ts, andAGENTS.md. The router is not re-exported fromsrc/ports/index.ts(F3).src/modules/types.ts,src/modules/host.ts: the two-step lease socket handler onWorkerModuleandGatewayModule,WorkerContext.inputs.src/http/: the lease socket resolution next to #1015's lease route.src/daemon/main.ts: the router replaces theuplinks.attach(server)call at 1163 on the gateway and is added on the worker's listener;inputsfromDriverCatalog.src/module-registry/index.ts: addinputModule.website/src/content/docs/docs/using-devices/watching-the-screen.mdx,.../reference/configuration.mdx,.../gateway/access-control.mdx.
flowchart LR
daemon[daemon/main.ts *] --> ports[ports upgrade router NEW]
daemon --> host[modules/host.ts *]
ports --> http[http lease resolution *]
http --> input[input module NEW]
host --> input
input --> core[core/input.ts NEW]
input -- GatewayContext.relayTwoWay --> gw[gateway relay #1016]
input -- WorkerContext.inputs --> cat[core/driver-catalog.ts *]
cat --> drv[core/driver.ts input member *]
sequenceDiagram
participant App
participant GW as Gateway (ports, http, input)
participant W as Worker (input)
App->>GW: GET /v1/leases/L-42/input, Upgrade: websocket
GW->>GW: authenticate, resolve L-42 for the caller
alt not theirs or unknown
GW-->>App: 404 UNKNOWN_LEASE, socket destroyed
else
GW->>W: relayTwoWay, target input, lease L-42 (10 s signal)
alt input off on the worker
W-->>GW: RELAY_TARGET_MISSING
GW-->>App: 503 INPUT_UNAVAILABLE, socket destroyed
else no head in 10 s
GW-->>App: 503 WORKER_UNREACHABLE, socket destroyed
else head
GW-->>App: 101 Switching Protocols
W-->>App: 0x83, 0x82
App->>W: 0x03 touch
W-->>GW: 0xF0 every 5 s (dropped)
Note over GW,W: 15 s with no bytes from W
GW-->>App: close 1011
end
end
Surface and extension points
src/input/index.tsexportsinputModule, anOptionalModuleDefinition(F18, F29). Its worker factory returns aWorkerModulewithcapability,leaseRoute(426 for a plain GET), a lease socket handler,relayTwoWay(the worker end of #1016's two-way relay, see the feature's Two-way relay row), andhooks.beforeDeviceReclaimandhooks.beforeDrain. Its gateway factory returnsleaseRoute, a lease socket handler andhooks.beforeDrain.- Lease socket seam, written to the feature's Shared values "Lease socket":
WorkerModule.socketandGatewayModule.socket, eachopen(request, identity, lease) → Promise<Response | accept>. AResponseis sent as the refusal and the socket destroyed; anaccept(socket)runs after the 101. The socket type is a small port interface (send,close(code, reason),onMessage,onClose), so no module importsws(F3). The gateway'sopencallsrelayTwoWayand answers its refusal, so a 503 always comes before the upgrade. portsgains one upgrade router per HTTP server:/v1/uplinkgoes to the uplink's handler exactly asattachdoes today;/v1/leases/{id}/<segment>goes to http's lease resolution; anything else gets 404 and is destroyed (F1).attachstays foruplink-websocket.test.ts;main.tscalls the router instead, so only oneupgradelistener exists per server.- Device input port, written to the feature's Shared values "Device input port":
Driver.input?: DeviceInputFactory(optional, likescreenCapture),DriverCatalog.openInput(platform, device, signal), andWorkerContext.inputs: ModuleInputsmodeled onModuleScreens(F9). A driver without the member answers{unavailable: "<platform> devices take no input"}. #1018 and #1019 are the two implementations, so the port is added now (architecture rule 19).
Contract and event changes
none. Searched src/contract/ for relay, capability and error shapes: #1016 makes the relay change and bumps the protocol; INPUT_UNAVAILABLE is a module error code declared in src/input/definition.ts (F17); the capability input uses the existing {name, state, reason?} shape. No event is added; opening and refusing sockets is logged only.
New wire fields, all from the client: each WebSocket message is one tag byte and UTF-8 JSON (feature Shared values "Input messages"); a message over 64 KiB, bad JSON, an unknown tag, a position outside 0..1, or 0x07 is dropped and the socket stays open (F22's server drops the same way). Config capabilities.input.enabled: boolean, default false.
Other code on the same state
Searches: on("upgrade" (1 hit, F1), handleUpgrade (1), screenCapture (driver, catalog, fake driver, stream e2e), beforeDeviceReclaim (1: stream), beforeDrain (module host, 2 daemons), leases.onRemoved (1: agent-device relay-host-link).
- The uplink's upgrade handling (F1): now behind the router; an uplink upgrade behaves byte for byte as today.
src/ports/uplink-websocket.test.tsalready proves it and stays green unchanged. - The stream module's
beforeDeviceReclaim(F12): both modules hear the same lease end; neither waits for the other, and each closes only its own sockets. DriverCatalog.openScreen(F10):openInputsits beside it and reads a different driver member; neither changes the other.- #1015's lease route (feature Shared values "Lease route"): this task reuses its lease resolution for upgrades, and adds
leaseRouteoninputfor the 426. - The lease ending while a socket opens: the worker session registers the socket for its lease first, then re-checks
registry.snapshot.leases(as the stream checks the registry at open, F19); a lease already gone closes the socket 4001 with the reason it recorded, orlease ended. The gateway does the same againstFleetLeases.resolveafter the relay's head. - The gateway's
onRemovedand the worker's0xF1(F13, F14): the relayed lease event usually reaches the gateway before the worker's0xF1. OnonRemoved, the gateway waits up to 2 s for that socket's0xF1; the0xF1reason wins; with none, it closes 4001lease ended. HttpGateway.stop(F15): the input module closes its sockets with 1001 inbeforeDrain, which runs first, so no socket is destroyed without a close frame.
Failure modes
| Call | Outcome | What happens | Limit, counted from |
|---|---|---|---|
| Upgrade auth (F4, F6) | no or unknown token | 401, socket destroyed | none, synchronous |
| Lease resolution | not theirs, unknown | 404 UNKNOWN_LEASE, socket destroyed |
none |
relayTwoWay open |
head | 101, then the worker's 0x83 and 0x82 | 10 s, from the open |
relayTwoWay open |
RELAY_TARGET_MISSING |
503 INPUT_UNAVAILABLE before the upgrade (F16) |
same |
relayTwoWay open |
WORKER_UNREACHABLE, or no head in 10 s |
503 WORKER_UNREACHABLE before the upgrade; the 10 s signal aborts the open (F20) |
same |
| Worker heartbeat | silent | close 1011, relay ended | 15 s from the last byte from the worker |
| Uplink | closed | every socket on that worker closes 1011 | at once |
| Client ping | no pong | socket terminated, its share of the device input released | 15 s from the ping, pings every 15 s |
inputs.openInput |
{unavailable} (every platform in this task) |
0x83, then 0x82 {"width":1,"height":1,"orientation":"portrait","inputUnavailable":true}; messages dropped |
none |
inputs.openInput |
rejects | close 1013; the failure is remembered for 10 s, and sockets in that window get close 1013 without a new open | the open's own bound, set by #1018/#1019 |
| Device input | onFailed |
every socket of the lease closes 1013; the device input closes | at once |
| Socket count | 9th socket | close 1013 before 0x83 (F22) | none |
| Lease end (F12) | any reason | 0xF1 {code:4001, reason} on the channel, then close 4001 with the reason |
the participant's own signal |
Gateway onRemoved (F14) |
lease gone, socket still open | wait for that socket's 0xF1; then close 4001 with its reason, or lease ended |
2 s, from onRemoved |
| Daemon stop (F15) | beforeDrain |
close 1001 Simlock is stopping on every socket |
before the HTTP gateway stops |
| Any close | reason over 123 bytes | cut at a character boundary to 123 bytes (F21) | none |
State: the device input per lease, its socket set and the 10 s failed-open memory, in memory only. A worker restart drops them; through a gateway the uplink closes, so its sockets close 1011; standalone, the TCP connection closes. Two sockets opening at once for one lease share one device input: the first open runs, the second waits for it.
Rules in play
- Architecture rule 11, "Every wait that crosses a process boundary is bounded": the relay open (10 s), the worker silence (15 s), the client pong (15 s) and the gateway's wait for
0xF1(2 s) are each counted from a fixed point. - Architecture rule 10, "A rule is enforced in exactly one place": lease ownership is checked only by http's lease resolution; the module re-checks only that the lease still exists.
- Architecture rule 3, "Adding a driver must require zero core changes": the input member and
openInputland insrc/core/here, so #1018 and #1019 add driver code only. - Architecture rule 15, "Dependencies point from the optional to the required":
inputimportsmodules,coreandcontract; nothing required importsinput. - Architecture rule 18, "A module hands out a capability, not its parts":
index.tsexports onlyinputModule. - Architecture rule 19, "An extension point is added when a second implementation is named": the driver input member has #1018 and #1019 as its implementations.
src/ports/AGENTS.md:53, "Onlyuplink-websocket.tsimportsws": the router lives beside it in ports and owns the only otherwsimport; the rule's wording changes to name both files.- Documentation rule 9, "A change to the public surface updates the website in the same change": the route,
capabilities.input.enabledandINPUT_UNAVAILABLEgo on the three pages under Modules touched. - ADR 0049 §1–§6: lease routes, the module lease route, expo serve-sim messages, the shared device input, the two-way relay's heartbeat and lease end.
Tests
Seam: the gateway and standalone worker HTTP listeners with a device input faked through FakeDriver({input}), in a new src/daemon/input-lease.e2e.test.ts modeled on src/daemon/stream-gateway.e2e.test.ts; the session's message handling in src/input/ modeled on src/stream/worker-link.test.ts.
- A caller opens
WS /v1/leases/{id}/inputand gets 0x83 then 0x82, or a refused upgrade: own lease; another's 404; unknown 404; operator; input off on the answering daemon 404; off on the lease's worker 503INPUT_UNAVAILABLE; worker gives no head in 10 s 503WORKER_UNREACHABLE; plain GET 426; no token 401; a proxy-signed (ambient) identity withoutSec-Fetch-Site: same-origin403FORBIDDEN, as ADR 0033 §5 (decided in delivery, pending the maintainer); a 9th socket closed 1013; an unavailable device input gets"inputUnavailable":true; a failed open closes 1013 and a reconnect within 10 s is refused 1013 without a new open. - A client following T3 Code's order drives a faked device through a gateway: waits for 0x83; touch begin/move/end, key, button arrive in order; a second socket shares the same device input; the device input closes when the last socket closes; a size change reaches every socket as 0x82.
- A client sending a bad message keeps its socket and nothing reaches the device: bad JSON; unknown tag; x outside 0..1; 0x07 dropped; 0x10 answered 0x90
{ok:false}. - An input socket closes with 4001 and the reason when the lease ends, and a reconnect gets 404:
explicit,expired,killed,device-lost; through a gateway the worker's reason wins; a lease that ends while the socket opens. - An input socket closes when either end goes quiet or away: client misses its pong (worker and gateway); worker heartbeat stops (1011); uplink drops (1011); daemon stops (1001); the gateway sees the lease go (4001).
The uplink's upgrade, unchanged, stays proven by src/ports/uplink-websocket.test.ts.
Done when
pnpm testpasses, includingsrc/daemon/input-lease.e2e.test.tsandsrc/ports/uplink-websocket.test.tsunchanged.- With
capabilities.input.enabledtrue on a standalone worker, an agent token's upgrade to its own lease's/v1/leases/{id}/inputgets 0x83 then 0x82{"width":1,"height":1,"orientation":"portrait","inputUnavailable":true}; another token gets 404. pnpm openapi /tmp/openapi.jsonwrites a document listingGET /v1/leases/{id}/inputwith 101, 401, 404, 426 and 503 (INPUT_UNAVAILABLE,WORKER_UNREACHABLE).- The three website pages under Modules touched describe the input socket,
capabilities.input.enabledandINPUT_UNAVAILABLE.
Out of scope
- Any device actually taking input: Android in #1018, iOS simulators and physical iPhones in #1019.
- Rotation:
0x07is dropped on every platform. - The two-way relay itself and its protocol bump (#1016).
- The lease stream route and the lease route seam for plain HTTP (#1015).
- Input from the console; a preview
{url, token}.
Depends on
- #1015
- #1016
Written by an agent.
- Lenguaje dominante
- TypeScript
- Estrellas
- 22
- Forks
- 2
- Merge medio
- 9 h 19 min
- PR fusionados (30 d)
- 430
Preparar el entorno
Este proyecto no incluye contenedor de desarrollo, Dockerfile ni guía de contribución, así que la configuración corre por tu cuenta: empieza por su README y consulta nuestra guía para la primera contribución para los pasos generales.
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de callstackincubator/simlock
-
bug:new
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
callstackincubator/simlock#1035 ·
Los mantenedores suelen responder en 1 día
-
bug:ready
Dificultad 2/5 1-3 horas Aptitud para principiantes 70/100
callstackincubator/simlock#639 · 4 comentarios ·
Los mantenedores suelen responder en 1 día
-
feature:spec
Dificultad 5/5 Más de una semana Aptitud para principiantes 12/100
callstackincubator/simlock#1024 ·
Los mantenedores suelen responder en 1 día
-
A lease renew right after a gateway restart answers UNKNOWN_LEASE and the client drops the leaseAbierto
Dificultad 4/5 3-5 días Aptitud para principiantes 45/100
callstackincubator/simlock#983 · 2 comentarios ·
Los mantenedores suelen responder en 1 día
-
request:new
Dificultad 5/5 Más de una semana Aptitud para principiantes 35/100
callstackincubator/simlock#948 · 1 comentario ·
Los mantenedores suelen responder en 1 día
Todos los issues de callstackincubator/simlock
Issues similares
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
scaleway/ultraviolet#7089 ·
Los mantenedores suelen responder en 2 días
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 67/100
tencent-connect/dsh-qqbot#81 ·
Los mantenedores suelen responder en 1 día
-
[Bug]: Pen taps on sidebar rows start a drag and lose their clickPosiblemente ocupada @makhnatkin la tomó hoy. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 62/100
Los mantenedores suelen responder en 1 día
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 66/100
clangd/vscode-clangd#1009 ·