@platless/axom-cli 0.1.0 → 0.5.9
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/README.md +1 -1
- package/dist/authScopes.js +19 -0
- package/dist/axom-patch/cli/README.md +132 -0
- package/dist/axom-patch/cli/account-limits/README.md +27 -0
- package/dist/axom-patch/cli/account-limits/antigravity-proxy.mjs +47 -0
- package/dist/axom-patch/cli/account-limits/antigravity-read.mjs +90 -0
- package/dist/axom-patch/cli/account-limits/antigravity.mjs +46 -0
- package/dist/axom-patch/cli/account-limits/generate.py +120 -0
- package/dist/axom-patch/cli/account-limits/kimi-proxy.mjs +64 -0
- package/dist/axom-patch/cli/account-limits/normalize.mjs +151 -0
- package/dist/axom-patch/cli/claude-account-limits.json +37 -0
- package/dist/axom-patch/cli/codex-account-limits.json +37 -0
- package/dist/axom-patch/cli/commandcode-account-limits.json +30 -0
- package/dist/axom-patch/cli/nightly-task.md +152 -0
- package/dist/axom-patch/cli/pi-steering.json +37 -0
- package/dist/axom-patch/cli/pi-subagent-subwork.json +23 -0
- package/dist/axom-patch/cli/probes/claude-late-async-terminal.mjs +38 -0
- package/dist/axom-patch/cli/probes/pi-steering.mjs +80 -0
- package/dist/axom-patch/cli/probes/pi-subagent-subwork.mjs +211 -0
- package/dist/axom-patch/cli/probes/qoder-steering.mjs +89 -0
- package/dist/axom-patch/cli/probes/qoder-subagent-origin.mjs +61 -0
- package/dist/axom-patch/cli/probes/zcode-subagent-subwork.mjs +257 -0
- package/dist/axom-patch/cli/qoder-background-terminal.md +82 -0
- package/dist/axom-patch/cli/qoder-foreground-output.md +42 -0
- package/dist/axom-patch/cli/qoder-steering.json +52 -0
- package/dist/axom-patch/cli/qoder-steering.md +30 -0
- package/dist/axom-patch/cli/qoder-subagent-origin.json +73 -0
- package/dist/axom-patch/cli/qoder-subagent-subwork.md +73 -0
- package/dist/axom-patch/cli/runtime.json +63 -0
- package/dist/axom-patch/cli/steering/claude-steering-js.patch +89 -0
- package/dist/axom-patch/cli/steering/claude-steering-types.patch +28 -0
- package/dist/axom-patch/cli/steering/codex-steering.patch +57 -0
- package/dist/axom-patch/cli/steering/pi-steering.js +79 -0
- package/dist/axom-patch/cli/zcode-account-limits.json +31 -0
- package/dist/axom-patch/cli/zcode-models.json +38 -0
- package/dist/axom-patch/cli/zcode-subagent-subwork.json +73 -0
- package/dist/cli.js +36 -1
- package/dist/commands/auth.js +4 -13
- package/dist/commands/execute.js +4 -4
- package/dist/commands/record.js +6 -6
- package/dist/commands/struct.js +4 -4
- package/dist/commands/workstation.js +2 -2
- package/dist/credentials.js +2 -2
- package/dist/install/claude/commands.js +13 -13
- package/dist/keepers/acp/keeper.mjs +3083 -0
- package/dist/keepers/acp/manifest.json +9 -0
- package/dist/keepers/terminal/keeper.mjs +8469 -0
- package/dist/keepers/terminal/manifest.json +9 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/conpty_console_list_agent.js +25 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/eventEmitter2.js +47 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/index.js +52 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/interfaces.js +7 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/shared/conout.js +10 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/terminal.js +190 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/types.js +7 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/unixTerminal.js +351 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/utils.js +38 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/windowsConoutConnection.js +131 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/windowsPtyAgent.js +344 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/windowsTerminal.js +209 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/worker/conoutSocketWorker.js +22 -0
- package/dist/keepers/terminal/node_modules/node-pty/package.json +66 -0
- package/dist/keepers/terminal/node_modules/node-pty/prebuilds/darwin-arm64/pty.node +0 -0
- package/dist/keepers/terminal/node_modules/node-pty/prebuilds/darwin-arm64/spawn-helper +0 -0
- package/dist/keepers/terminal/node_modules/node-pty/prebuilds/darwin-x64/pty.node +0 -0
- package/dist/keepers/terminal/node_modules/node-pty/prebuilds/darwin-x64/spawn-helper +0 -0
- package/dist/keepers/terminal/node_modules/node-pty/prebuilds/linux-arm64/pty.node +0 -0
- package/dist/keepers/terminal/node_modules/node-pty/prebuilds/linux-x64/pty.node +0 -0
- package/dist/mcp.js +32 -14
- package/dist/runtime-deps/qoder-sdk/package-lock.json +1189 -0
- package/dist/runtime-deps/qoder-sdk/package.json +8 -0
- package/dist/test/keeperKit.js +67 -0
- package/dist/workstation/acp/acpAgents.js +2514 -681
- package/dist/workstation/acp/acpClient.js +95 -318
- package/dist/workstation/acp/activityBusy.js +43 -0
- package/dist/workstation/acp/activityReporting.js +54 -0
- package/dist/workstation/acp/adoption.js +28 -356
- package/dist/workstation/acp/authUrlSniffer.js +36 -0
- package/dist/workstation/acp/binaryInstall.js +100 -27
- package/dist/workstation/acp/builds/gc.js +245 -0
- package/dist/workstation/acp/builds/install/binary.js +28 -0
- package/dist/workstation/acp/builds/install/npm.js +235 -0
- package/dist/workstation/acp/builds/install/uv.js +254 -0
- package/dist/workstation/acp/builds/migrate.js +195 -0
- package/dist/workstation/acp/builds/model.js +128 -0
- package/dist/workstation/acp/builds/nodeGate.js +100 -0
- package/dist/workstation/acp/builds/store.js +352 -0
- package/dist/workstation/acp/commandTableProbe.js +68 -0
- package/dist/workstation/acp/configOptions.js +103 -1
- package/dist/workstation/acp/delegationMcp.js +24 -0
- package/dist/workstation/acp/envSecrets.js +27 -0
- package/dist/workstation/acp/initializeResponse.js +285 -0
- package/dist/workstation/acp/installErrors.js +12 -2
- package/dist/workstation/acp/installProbe.js +1 -1
- package/dist/workstation/acp/managedPatches.js +144 -0
- package/dist/workstation/acp/outbox.js +330 -0
- package/dist/workstation/acp/patchAssets.js +80 -0
- package/dist/workstation/acp/permission.js +335 -37
- package/dist/workstation/acp/processor/checkpoint.js +87 -0
- package/dist/workstation/acp/processor/commands.js +35 -0
- package/dist/workstation/acp/processor/control.js +355 -0
- package/dist/workstation/acp/processor/emit.js +26 -0
- package/dist/workstation/acp/processor/jsonrpc.js +172 -0
- package/dist/workstation/acp/processor/memoryLog.js +49 -0
- package/dist/workstation/acp/processor/origins.js +48 -0
- package/dist/workstation/acp/processor/output.js +67 -0
- package/dist/workstation/acp/processor/projection.js +42 -0
- package/dist/workstation/acp/processor/record.js +128 -0
- package/dist/workstation/acp/processor/runtime.js +181 -0
- package/dist/workstation/acp/processor/sdkSchemas.js +61 -0
- package/dist/workstation/acp/processor/session.js +525 -0
- package/dist/workstation/acp/processor/sideChannel.js +80 -0
- package/dist/workstation/acp/processor/state.js +74 -0
- package/dist/workstation/acp/processor/step.js +459 -0
- package/dist/workstation/acp/processor/test/fixtureLog.js +65 -0
- package/dist/workstation/acp/processor/test/harness.js +120 -0
- package/dist/workstation/acp/processor/test/largeIdEcho.js +50 -0
- package/dist/workstation/acp/processor/test/rawAgent.js +70 -0
- package/dist/workstation/acp/processor/transport/generations.js +76 -0
- package/dist/workstation/acp/processor/transport/keeper.js +130 -0
- package/dist/workstation/acp/processor/transport/local.js +269 -0
- package/dist/workstation/acp/processor/transport/types.js +78 -0
- package/dist/workstation/acp/processor/updates.js +364 -0
- package/dist/workstation/acp/processorSession.js +1512 -0
- package/dist/workstation/acp/qoderStartup.js +45 -0
- package/dist/workstation/acp/registry/catalog.js +385 -4
- package/dist/workstation/acp/registry/detect.js +55 -0
- package/dist/workstation/acp/registry/launch.js +61 -119
- package/dist/workstation/acp/sessionUpdateMapper.js +56 -27
- package/dist/workstation/acp/steering.js +58 -0
- package/dist/workstation/acp/switching.js +114 -0
- package/dist/workstation/acp/terminalLogin.js +171 -0
- package/dist/workstation/acp/terminalLoginSpec.js +41 -0
- package/dist/workstation/acp/test/adapterFixtures.js +256 -0
- package/dist/workstation/acp/test/daemonLife.js +106 -0
- package/dist/workstation/acp/test/fakeAgent.js +185 -9
- package/dist/workstation/acp/test/keeperWorld.js +267 -0
- package/dist/workstation/acp/test/memoryOutbox.js +55 -0
- package/dist/workstation/acp/test/raw/fixtures.js +196 -0
- package/dist/workstation/acp/test/raw/qoderCaptures.js +125 -0
- package/dist/workstation/acp/test/raw/sanitize.js +344 -0
- package/dist/workstation/acp/test/raw/sources.js +249 -0
- package/dist/workstation/acp/test/realAdapter.js +377 -0
- package/dist/workstation/acp/test/scriptAgent.js +206 -0
- package/dist/workstation/acp/test/sessionFrames.js +42 -0
- package/dist/workstation/acp/timedCommand.js +4 -2
- package/dist/workstation/acp/uvxInstall.js +72 -122
- package/dist/workstation/acp/validate.js +33 -5
- package/dist/workstation/agentFlow.js +103 -0
- package/dist/workstation/agentSessions.js +1686 -348
- package/dist/workstation/channels/agent.js +14 -6
- package/dist/workstation/channels/computer.js +203 -7
- package/dist/workstation/channels/computerExecs.js +200 -0
- package/dist/workstation/channels/management.js +86 -6
- package/dist/workstation/config.js +3 -1
- package/dist/workstation/connection/encryptedChannel.js +88 -21
- package/dist/workstation/daemon.js +309 -6
- package/dist/workstation/daemonctl.js +28 -2
- package/dist/workstation/desktop/binding.js +36 -0
- package/dist/workstation/desktop/bridge.js +212 -0
- package/dist/workstation/desktop/flow-control.js +52 -0
- package/dist/workstation/desktop/focused-text.js +130 -0
- package/dist/workstation/desktop/protocol.js +35 -0
- package/dist/workstation/exec/attach.js +126 -0
- package/dist/workstation/exec/command.js +40 -0
- package/dist/workstation/exec/durable.js +517 -0
- package/dist/workstation/exec/fallback.js +106 -0
- package/dist/workstation/exec/policy.js +837 -0
- package/dist/workstation/exec/shaping.js +211 -0
- package/dist/workstation/exec.js +3 -112
- package/dist/workstation/files/adapters/computerFileFrames.js +51 -0
- package/dist/workstation/files/adapters/toolRequests.js +121 -0
- package/dist/workstation/files/client.js +455 -0
- package/dist/workstation/files/errors.js +28 -0
- package/dist/workstation/files/fence.js +350 -0
- package/dist/workstation/files/find/fileIndex.js +153 -0
- package/dist/workstation/files/find/fuzzy.js +155 -0
- package/dist/workstation/files/host.js +122 -0
- package/dist/workstation/files/hostProtocol.js +2 -0
- package/dist/workstation/files/media/cache.js +620 -0
- package/dist/workstation/files/media/encoding.js +308 -0
- package/dist/workstation/files/media/estimator.js +100 -0
- package/dist/workstation/files/media/media.js +325 -0
- package/dist/workstation/files/media/packedAudio.js +23 -0
- package/dist/workstation/files/media/scheduler.js +551 -0
- package/dist/workstation/files/media/types.js +5 -0
- package/dist/workstation/files/scope.js +45 -0
- package/dist/workstation/files/structured.js +284 -0
- package/dist/workstation/files/text.js +356 -0
- package/dist/workstation/files/uploads.js +351 -0
- package/dist/workstation/journal.js +65 -236
- package/dist/workstation/keepers/acp/client.js +101 -0
- package/dist/workstation/keepers/acp/envelope.js +62 -0
- package/dist/workstation/keepers/acp/host.js +419 -0
- package/dist/workstation/keepers/acp/main.js +18 -0
- package/dist/workstation/keepers/acp/memoryStream.js +121 -0
- package/dist/workstation/keepers/acp/params.js +137 -0
- package/dist/workstation/keepers/acp/protocol.js +66 -0
- package/dist/workstation/keepers/acp/recover.js +120 -0
- package/dist/workstation/keepers/acp/session.js +584 -0
- package/dist/workstation/keepers/acp/stderr.js +154 -0
- package/dist/workstation/keepers/kit/activity.js +103 -0
- package/dist/workstation/keepers/kit/bootstrap.js +164 -0
- package/dist/workstation/keepers/kit/buildVersion.js +51 -0
- package/dist/workstation/keepers/kit/bundle.js +120 -0
- package/dist/workstation/keepers/kit/client.js +432 -0
- package/dist/workstation/keepers/kit/identity.js +21 -0
- package/dist/workstation/keepers/kit/ipc.js +112 -0
- package/dist/workstation/keepers/kit/launchConfig.js +8 -0
- package/dist/workstation/keepers/kit/launcher.js +249 -0
- package/dist/workstation/keepers/kit/lock.js +123 -0
- package/dist/workstation/keepers/kit/orphanSweep.js +86 -0
- package/dist/workstation/keepers/kit/paths.js +75 -0
- package/dist/workstation/keepers/kit/protocol.js +43 -0
- package/dist/workstation/keepers/kit/server.js +518 -0
- package/dist/workstation/keepers/kit/streamLog.js +697 -0
- package/dist/workstation/keepers/legacy.js +296 -0
- package/dist/workstation/keepers/policy.js +576 -0
- package/dist/workstation/keepers/stop.js +34 -0
- package/dist/workstation/keepers/terminal/client.js +213 -0
- package/dist/workstation/keepers/terminal/exec.js +981 -0
- package/dist/workstation/keepers/terminal/generations.js +129 -0
- package/dist/workstation/keepers/terminal/keeper.js +62 -0
- package/dist/workstation/keepers/terminal/main.js +43 -0
- package/dist/workstation/keepers/terminal/orphanSweep.js +3 -0
- package/dist/workstation/keepers/terminal/params.js +27 -0
- package/dist/workstation/keepers/terminal/protocol.js +56 -0
- package/dist/workstation/keepers/terminal/pty.js +330 -0
- package/dist/workstation/oauth/deviceAuthorization.js +21 -12
- package/dist/workstation/protocol/accountLimits.js +47 -0
- package/dist/workstation/protocol/agent.js +201 -8
- package/dist/workstation/protocol/common.js +36 -0
- package/dist/workstation/protocol/computer.js +107 -7
- package/dist/workstation/protocol/management.js +50 -2
- package/dist/workstation/qoderAdapter/backgroundProcess.js +118 -0
- package/dist/workstation/qoderAdapter/backgroundTerminal.js +193 -0
- package/dist/workstation/qoderAdapter/backgroundTerminalFold.js +372 -0
- package/dist/workstation/qoderAdapter/callbackContext.js +76 -0
- package/dist/workstation/qoderAdapter/completedContinuation.js +139 -0
- package/dist/workstation/qoderAdapter/contract.js +78 -0
- package/dist/workstation/qoderAdapter/foregroundOutput.js +36 -0
- package/dist/workstation/qoderAdapter/history.js +85 -0
- package/dist/workstation/qoderAdapter/identityIndex.js +191 -0
- package/dist/workstation/qoderAdapter/inputQueue.js +42 -0
- package/dist/workstation/qoderAdapter/main.js +95 -0
- package/dist/workstation/qoderAdapter/mapper.js +117 -0
- package/dist/workstation/qoderAdapter/observerPlugin.js +245 -0
- package/dist/workstation/qoderAdapter/observerReceiver.js +187 -0
- package/dist/workstation/qoderAdapter/permissions.js +61 -0
- package/dist/workstation/qoderAdapter/profile.js +93 -0
- package/dist/workstation/qoderAdapter/sdkDriver.js +48 -0
- package/dist/workstation/qoderAdapter/sdkRuntime.js +93 -0
- package/dist/workstation/qoderAdapter/sdkRuntimeInstall.js +145 -0
- package/dist/workstation/qoderAdapter/session.js +319 -0
- package/dist/workstation/qoderAdapter/subagentMeta.js +28 -0
- package/dist/workstation/qoderAdapter/subwork.js +85 -0
- package/dist/workstation/qoderAdapter/taskControl.js +38 -0
- package/dist/workstation/qoderAdapter/taskLedger.js +163 -0
- package/dist/workstation/qoderAdapter/types.js +1 -0
- package/dist/workstation/qoderAdapter/usage.js +37 -0
- package/dist/workstation/register.js +4 -0
- package/dist/workstation/systemMetrics.js +110 -1
- package/dist/workstation/tools/browser.js +394 -0
- package/dist/workstation/tools/client.js +277 -0
- package/dist/workstation/tools/info.js +50 -0
- package/dist/workstation/tools/keeperProcess.js +124 -0
- package/dist/workstation/tools/router.js +55 -0
- package/dist/workstation/tools/terminalRouter.js +222 -0
- package/dist/workstation/tools/validation.js +86 -0
- package/dist/workstation/update/coordinator.js +32 -0
- package/dist/workstation/update/npmInstaller.js +2 -0
- package/dist/workstation/update/ptyPreflight.js +45 -0
- package/dist/workstation/update/taskRegistry.js +141 -23
- package/dist/workstation/update/watchdog.js +66 -0
- package/package.json +20 -7
- package/skills/axom/SKILL.md +55 -17
- package/skills/axom-definition/SKILL.md +32 -32
- package/skills/axom-platform/SKILL.md +39 -39
- package/dist/workstation/acp/acpSession.js +0 -1047
- package/dist/workstation/acp/contract.js +0 -494
- package/dist/workstation/acp/draftInterceptor.js +0 -154
|
@@ -1,19 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
2
|
+
* `uv tool` plumbing for uvx-distributed adapters (`fast-agent-acp`, `minion-code` — the ACP
|
|
3
|
+
* registry's `distribution.uvx`). Since Task 15b these are installed as daemon-owned, per-version
|
|
4
|
+
* builds (`builds/install/uv.ts`): every `uv` call here runs with `UV_TOOL_DIR`/`UV_TOOL_BIN_DIR`
|
|
5
|
+
* pointed into one build's own directory, never at the user's `uv tool dir` or `~/.local/bin`, and only
|
|
6
|
+
* at install time — a launch reads the entry recorded in `builds.json` and never starts `uv`.
|
|
6
7
|
*
|
|
7
|
-
* ## Why
|
|
8
|
+
* ## Why not `uvx <pkg>`
|
|
8
9
|
*
|
|
9
10
|
* `uvx <pkg>` resolves through uv's own ephemeral-environment cache — directories named by a hash
|
|
10
11
|
* of the resolved environment, a layout this codebase has never verified and has no reason to
|
|
11
|
-
* trust.
|
|
12
|
-
*
|
|
13
|
-
* install` instead puts the tool under `uv tool dir` — one stable path per machine that `uv tool
|
|
14
|
-
* list` describes completely — which is the same guarantee `readNpxCache`/`findOnPath` give for the
|
|
15
|
-
* npx and binary paths. Everything here exists to read that directory the way `installProbe.ts`
|
|
16
|
-
* reads npm's.
|
|
12
|
+
* trust. `uv tool install` instead puts the tool under `UV_TOOL_DIR` — a path we choose — and `uv
|
|
13
|
+
* tool list` (run with the same env) describes it completely.
|
|
17
14
|
*
|
|
18
15
|
* ## Measured evidence (2026-09-05, uv 0.11.5, macOS aarch64) — this is what the parsing below is
|
|
19
16
|
* built on, not a guess
|
|
@@ -68,48 +65,41 @@
|
|
|
68
65
|
* (true for `httpie` among its three); otherwise **neither** — this refuses rather than guesses.
|
|
69
66
|
* uv's listing order is stable on one machine but not a documented contract, this path has never
|
|
70
67
|
* been exercised against either real registry package, and a wrong guess here launches the wrong
|
|
71
|
-
* binary silently, which is worse than a refusal a caller can act on. See {@link
|
|
68
|
+
* binary silently, which is worse than a refusal a caller can act on. See {@link uvToolEntrypointFrom}
|
|
72
69
|
* for the resulting three-outcome contract.
|
|
70
|
+
*
|
|
71
|
+
* ## Re-measured for per-build dirs (2026-10-11, uv 0.12.23, macOS aarch64, local wheel)
|
|
72
|
+
*
|
|
73
|
+
* With `UV_TOOL_DIR=<b>/tools UV_TOOL_BIN_DIR=<b>/bin`, `uv tool install` writes only under `<b>`
|
|
74
|
+
* (plus uv's download cache): the entry script's shebang is `<b>/tools/<pkg>/bin/python` (absolute),
|
|
75
|
+
* `<b>/bin/<exe>` is an absolute symlink to it, and `uv-receipt.toml` records both. A tree renamed
|
|
76
|
+
* after install therefore does not run — which is why uv builds are installed in place under a
|
|
77
|
+
* completion marker rather than staged and renamed (`builds/model.ts`).
|
|
73
78
|
*/
|
|
74
79
|
import { runTimedCommand } from './timedCommand.js';
|
|
75
|
-
/**
|
|
76
|
-
* Wall-clock budget for one `uv tool list` / `uv tool dir` read — a local, no-network directory
|
|
77
|
-
* probe, not a download. "A few seconds is generous" for that: 10s leaves ample headroom above
|
|
78
|
-
* every measured run (low tens of milliseconds — see this module's own doc comment) while still
|
|
79
|
-
* keeping a genuinely stuck `uv` (a broken shim, a filesystem wedged mid-fsck) from parking
|
|
80
|
-
* `AcpAgents.roster` or a launch indefinitely.
|
|
81
|
-
*/
|
|
80
|
+
/** Wall-clock budget for one `uv tool list` — a local, no-network directory read, not a download. */
|
|
82
81
|
export const UV_PROBE_TIMEOUT_MS = 10_000;
|
|
83
82
|
/**
|
|
84
|
-
* Wall-clock budget for one `uv tool install <spec>` — a real package download, not a probe.
|
|
85
|
-
*
|
|
86
|
-
* Matches `installProbe.ts`'s `ADAPTER_INSTALL_TIMEOUT_MS` and `binaryInstall.ts`'s
|
|
87
|
-
* `ARCHIVE_DOWNLOAD_TIMEOUT_MS` deliberately, for the same reason `binaryInstall.ts`'s own constant
|
|
88
|
-
* gives for matching the first of those: this is the third of three siblings (npx, binary archive,
|
|
89
|
-
* uvx tool) fetching a whole ACP adapter over the network, and there is no reason the one added
|
|
90
|
-
* last should time out sooner than the other two just because it arrived later.
|
|
83
|
+
* Wall-clock budget for one `uv tool install <spec>` — a real package download, not a probe. Matches
|
|
84
|
+
* the npm and binary adapter install budgets: there is no reason the third sibling should time out sooner.
|
|
91
85
|
*/
|
|
92
86
|
export const UV_TOOL_INSTALL_TIMEOUT_MS = 300_000;
|
|
93
87
|
/**
|
|
94
|
-
* Default `RunUv`: runs `uv <args>` through {@link runTimedCommand}
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
* machine without `uv` installed is a normal machine, not an error condition this module gets to
|
|
98
|
-
* raise; a `uv` that hangs past its budget is reported with a message naming the command and the
|
|
99
|
-
* budget, not silently swallowed.
|
|
88
|
+
* Default `RunUv`: runs `uv <args>` through {@link runTimedCommand}, with every failure — a non-zero
|
|
89
|
+
* exit, `uv` not being on `PATH` at all (`ENOENT`), or the run exceeding `timeoutMs` — folded into
|
|
90
|
+
* `{ ok: false }` rather than thrown. A machine without `uv` is a normal machine.
|
|
100
91
|
*/
|
|
101
|
-
async function defaultRunUv(args, timeoutMs) {
|
|
102
|
-
const result = await runTimedCommand('uv', args, timeoutMs);
|
|
92
|
+
export async function defaultRunUv(args, timeoutMs, env) {
|
|
93
|
+
const result = await runTimedCommand('uv', args, timeoutMs, env ? { env: { ...process.env, ...env } } : {});
|
|
103
94
|
if (result.ok)
|
|
104
95
|
return { ok: true, stdout: result.stdout };
|
|
105
|
-
return { ok: false, stdout: '', error: result.message };
|
|
96
|
+
return { ok: false, stdout: '', error: result.message, ...(result.code ? { code: result.code } : {}) };
|
|
106
97
|
}
|
|
107
98
|
/**
|
|
108
99
|
* Parses `uv tool list --show-paths` output (also tolerates the plain `uv tool list` form, with no
|
|
109
|
-
* `(<path>)` suffixes
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
* roster) matches neither pattern and yields no entries, which is the correct answer.
|
|
100
|
+
* `(<path>)` suffixes). A tool header line reads `<name> vX.Y.Z` or `<name> vX.Y.Z (<tool dir>)`; each
|
|
101
|
+
* executable line under it reads `- <name>` or `- <name> (<absolute path>)`. `No tools installed`
|
|
102
|
+
* matches neither pattern and yields no entries, which is the correct answer.
|
|
113
103
|
*/
|
|
114
104
|
function parseToolList(stdout) {
|
|
115
105
|
const entries = [];
|
|
@@ -132,117 +122,77 @@ function parseToolList(stdout) {
|
|
|
132
122
|
return entries;
|
|
133
123
|
}
|
|
134
124
|
/**
|
|
135
|
-
* One `uv tool list --show-paths` snapshot, parsed
|
|
136
|
-
* `uv`
|
|
137
|
-
*
|
|
138
|
-
* look every uvx-distributed agent up in one snapshot instead of spawning `uv` again per agent (see
|
|
139
|
-
* that call site's own doc comment for why a per-agent spawn was a defect worth hoisting out of).
|
|
140
|
-
* `uv` missing, failing, or timing out degrades to `[]` — "nothing installed" — the same as every
|
|
141
|
-
* other reader of {@link RunUv} in this module; it never throws. `timeoutMs` defaults to
|
|
142
|
-
* {@link UV_PROBE_TIMEOUT_MS} — this is the probe half of `RunUv`'s two budgets, never the
|
|
143
|
-
* `uv tool install` one.
|
|
125
|
+
* One `uv tool list --show-paths` snapshot, parsed, of the tool dir `env` names (a build's own; see
|
|
126
|
+
* `builds/install/uv.ts`). `uv` missing, failing, or timing out degrades to `[]` — "nothing
|
|
127
|
+
* installed"; it never throws.
|
|
144
128
|
*/
|
|
145
|
-
export async function listUvTools(run = defaultRunUv, timeoutMs = UV_PROBE_TIMEOUT_MS) {
|
|
146
|
-
const result = await run(['tool', 'list', '--show-paths'], timeoutMs);
|
|
129
|
+
export async function listUvTools(run = defaultRunUv, timeoutMs = UV_PROBE_TIMEOUT_MS, env) {
|
|
130
|
+
const result = await (env ? run(['tool', 'list', '--show-paths'], timeoutMs, env) : run(['tool', 'list', '--show-paths'], timeoutMs));
|
|
147
131
|
if (!result.ok)
|
|
148
132
|
return [];
|
|
149
133
|
return parseToolList(result.stdout);
|
|
150
134
|
}
|
|
151
|
-
|
|
152
|
-
|
|
135
|
+
/** PEP 503 name comparison: `Fast_Agent.ACP` and `fast-agent-acp` are the same distribution. */
|
|
136
|
+
function sameDistribution(a, b) {
|
|
137
|
+
const normal = (name) => name.toLowerCase().replace(/[-_.]+/g, '-');
|
|
138
|
+
return normal(a) === normal(b);
|
|
153
139
|
}
|
|
154
|
-
|
|
155
|
-
|
|
140
|
+
/** The tool entry for `pkg` in a {@link listUvTools} snapshot, by PEP 503 name. */
|
|
141
|
+
export function findUvTool(tools, pkg) {
|
|
142
|
+
return tools.find((entry) => sameDistribution(entry.name, pkg));
|
|
156
143
|
}
|
|
157
144
|
/**
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
|
|
161
|
-
export async function uvToolVersion(pkg, run = defaultRunUv) {
|
|
162
|
-
return (await findTool(pkg, run))?.version;
|
|
163
|
-
}
|
|
164
|
-
/**
|
|
165
|
-
* Picks `pkg`'s launchable executable — the one `resolveLaunch`'s uvx branch runs instead of
|
|
166
|
-
* shelling out to `uvx <pkg>` — out of an already-parsed `uv tool list --show-paths` snapshot
|
|
167
|
-
* ({@link listUvTools}).
|
|
168
|
-
*
|
|
169
|
-
* Three shapes, in order:
|
|
170
|
-
* 1. Exactly one executable declared → that one, whatever it is named. One candidate is not a
|
|
171
|
-
* guess.
|
|
145
|
+
* Picks `pkg`'s launchable executable out of an already-parsed `uv tool list --show-paths` snapshot
|
|
146
|
+
* ({@link listUvTools}). Three shapes, in order:
|
|
147
|
+
* 1. Exactly one executable declared → that one, whatever it is named.
|
|
172
148
|
* 2. Several declared, and one matches the package's own name (true for `httpie` among its three,
|
|
173
149
|
* measured) → that one.
|
|
174
|
-
* 3. Several declared, none matching → **refuse** (`ambiguous`, carrying every candidate name).
|
|
175
|
-
*
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
* that hangs or fails for a reason nobody can trace back to this choice, so this reports the
|
|
180
|
-
* ambiguity instead of resolving it.
|
|
181
|
-
*
|
|
182
|
-
* `not-installed` also covers: no such tool in `uv tool list`, `uv` itself missing or failing, a
|
|
183
|
-
* matched executable whose recorded path is empty (the plain, no-`--show-paths` form this also
|
|
184
|
-
* parses carries no paths at all) — none of these are launchable either, and none of them are
|
|
185
|
-
* ambiguous the way case 3 is.
|
|
186
|
-
*
|
|
187
|
-
* Takes the parsed listing rather than a runner on purpose: a caller that already read
|
|
188
|
-
* `uv tool list` once (`AcpAgents.roster`, so 39 registry entries share one spawn) hands that
|
|
189
|
-
* result straight in here instead of this function spawning `uv` again per package. {@link
|
|
190
|
-
* uvToolEntrypoint} is the thin wrapper for the one real caller (the actual launch path) that has
|
|
191
|
-
* no such snapshot yet and needs to read it fresh.
|
|
150
|
+
* 3. Several declared, none matching → **refuse** (`ambiguous`, carrying every candidate name). uv's
|
|
151
|
+
* listing order is not a documented contract, and a wrong guess launches the wrong binary silently.
|
|
152
|
+
*
|
|
153
|
+
* `not-installed` also covers a matched executable whose recorded path is empty (the plain,
|
|
154
|
+
* no-`--show-paths` form carries no paths at all).
|
|
192
155
|
*/
|
|
193
156
|
export function uvToolEntrypointFrom(pkg, tools) {
|
|
194
|
-
const entry =
|
|
157
|
+
const entry = findUvTool(tools, pkg);
|
|
195
158
|
if (!entry || entry.executables.length === 0)
|
|
196
159
|
return { ok: false, reason: 'not-installed' };
|
|
197
160
|
if (entry.executables.length === 1) {
|
|
198
161
|
const [only] = entry.executables;
|
|
199
162
|
return only.path ? { ok: true, path: only.path } : { ok: false, reason: 'not-installed' };
|
|
200
163
|
}
|
|
201
|
-
const match = entry.executables.find((exe) => exe.name
|
|
164
|
+
const match = entry.executables.find((exe) => sameDistribution(exe.name, pkg));
|
|
202
165
|
if (match) {
|
|
203
166
|
return match.path ? { ok: true, path: match.path } : { ok: false, reason: 'not-installed' };
|
|
204
167
|
}
|
|
205
168
|
return { ok: false, reason: 'ambiguous', candidates: entry.executables.map((exe) => exe.name) };
|
|
206
169
|
}
|
|
207
170
|
/**
|
|
208
|
-
*
|
|
209
|
-
*
|
|
210
|
-
*
|
|
211
|
-
* uvToolEntrypointFrom}'s doc comment).
|
|
171
|
+
* Parses a registry `uvx.package` specifier. Both pins the live registry uses are understood —
|
|
172
|
+
* `fast-agent-acp==0.10.1` and `minion-code@0.1.44` (`uvx`'s `pkg@version` form). Anything else after
|
|
173
|
+
* the name (a range, a URL) is not a pin this layer can name a build after, and is refused.
|
|
212
174
|
*/
|
|
213
|
-
export
|
|
214
|
-
|
|
175
|
+
export function parseUvxSpec(spec) {
|
|
176
|
+
const match = /^\s*([A-Za-z0-9][A-Za-z0-9._-]*)(\[[A-Za-z0-9._,\s-]*\])?\s*(?:(?:==|@)\s*([A-Za-z0-9][A-Za-z0-9.+_-]*))?\s*$/.exec(spec);
|
|
177
|
+
if (!match)
|
|
178
|
+
throw new Error(`Unsupported uvx package specifier '${spec}'`);
|
|
179
|
+
return { name: match[1], extras: (match[2] ?? '').replace(/\s+/g, ''), ...(match[3] ? { version: match[3] } : {}) };
|
|
215
180
|
}
|
|
216
|
-
/**
|
|
217
|
-
* The package name half of a `uv tool install` specifier: `pkg==1.2.3` → `pkg`. Returns the input
|
|
218
|
-
* unchanged when it carries no `==` pin — the ACP registry is not required to pin `uvx` specifiers
|
|
219
|
-
* the way it pins `npx` ones (see `registryTypes.ts`'s `UvxDistribution`).
|
|
220
|
-
*/
|
|
181
|
+
/** The package name half of a uvx specifier: `pkg==1.2.3` / `pkg@1.2.3` / `pkg[x]` → `pkg`. Unparseable input is returned unchanged. */
|
|
221
182
|
export function uvPackageName(spec) {
|
|
222
|
-
|
|
223
|
-
|
|
183
|
+
try {
|
|
184
|
+
return parseUvxSpec(spec).name;
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
return spec;
|
|
188
|
+
}
|
|
224
189
|
}
|
|
225
|
-
/** The version half of a
|
|
190
|
+
/** The version half of a uvx specifier: `pkg==1.2.3` / `pkg@1.2.3` → `1.2.3`; `undefined` with no pin. */
|
|
226
191
|
export function uvPackageVersion(spec) {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
* `alreadyInstalled: true` without spawning `uv tool install` when a quick `uv tool list` probe
|
|
233
|
-
* (bounded by {@link UV_PROBE_TIMEOUT_MS}) already reports the pinned version — the same "don't
|
|
234
|
-
* repeat work that's already done" rule `installNpxPackage` follows against the npx cache. The
|
|
235
|
-
* actual install, when it runs, is a real download and gets {@link UV_TOOL_INSTALL_TIMEOUT_MS}, not
|
|
236
|
-
* the probe's budget.
|
|
237
|
-
*/
|
|
238
|
-
export async function installUvTool(spec, run = defaultRunUv) {
|
|
239
|
-
const pkg = uvPackageName(spec);
|
|
240
|
-
const pinned = uvPackageVersion(spec);
|
|
241
|
-
if (pinned && (await uvToolVersion(pkg, run)) === pinned) {
|
|
242
|
-
return { ok: true, alreadyInstalled: true };
|
|
192
|
+
try {
|
|
193
|
+
return parseUvxSpec(spec).version;
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
196
|
+
return undefined;
|
|
243
197
|
}
|
|
244
|
-
const result = await run(['tool', 'install', spec], UV_TOOL_INSTALL_TIMEOUT_MS);
|
|
245
|
-
if (result.ok)
|
|
246
|
-
return { ok: true, alreadyInstalled: false };
|
|
247
|
-
return { ok: false, error: result.error ?? `uv tool install ${spec} failed` };
|
|
248
198
|
}
|
|
@@ -18,10 +18,13 @@
|
|
|
18
18
|
* question. Its two wire names behave differently here, and the difference is the suffix, not the
|
|
19
19
|
* family:
|
|
20
20
|
*
|
|
21
|
-
* - `elicitation_request` (`TimelineEvent.
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
21
|
+
* - `elicitation_request` (`TimelineEvent.ElicitationRequested`) is request-shaped and, since the
|
|
22
|
+
* platform grew a named decode branch for it (`TimelineEventWire.decodeElicitationRequested`,
|
|
23
|
+
* landing a `WorkItemKind.USER_INTERACTION` item that parks the run), is now a member of this
|
|
24
|
+
* set: a bridge emitting it is answerable, not rejected. The reply that unblocks the agent's
|
|
25
|
+
* `elicitation/create` travels back on its own frame — `AgentFrame.AgentElicitationAnswer` — not
|
|
26
|
+
* through `permission_request`'s `agent_answer`, because ACP's `CreateElicitationResponse.content`
|
|
27
|
+
* is a structured object `agent_answer`'s single-string `outcome` cannot carry.
|
|
25
28
|
* - `elicitation` (`TimelineEvent.UserInteractionRequested`) carries no request suffix, so this gate
|
|
26
29
|
* never looks at it and a bridge emitting it passes through. That is now correct rather than
|
|
27
30
|
* merely harmless: `TimelineEventWire.decode` has a named `elicitation` branch that rebuilds the
|
|
@@ -32,7 +35,7 @@
|
|
|
32
35
|
* run never parks on. Well-formedness is defined in exactly one place, that decoder; this gate
|
|
33
36
|
* deliberately does not carry a second copy of the shape rules to drift from it.
|
|
34
37
|
*/
|
|
35
|
-
export const KNOWN_REQUEST_EVENT_NAMES = new Set(['permission_request']);
|
|
38
|
+
export const KNOWN_REQUEST_EVENT_NAMES = new Set(['permission_request', 'elicitation_request']);
|
|
36
39
|
/**
|
|
37
40
|
* Does this name carry the "answer me exactly once" promise?
|
|
38
41
|
*
|
|
@@ -130,5 +133,30 @@ function inspect(event) {
|
|
|
130
133
|
}
|
|
131
134
|
}
|
|
132
135
|
}
|
|
136
|
+
// `elicitation_request`'s counterpart to the `permission_request` checks above — added by Task 18,
|
|
137
|
+
// which is also this event's first real producer (`permission.ts`'s `handleFormElicitation`).
|
|
138
|
+
// `validate.test.ts` used to pin the opposite — `{requestId: 'r1'}` alone passing — on the explicit
|
|
139
|
+
// reasoning that a shape rule with no producer to catch would only be guarding against a caller
|
|
140
|
+
// that did not exist; that premise no longer holds, so the rule now exists too. `mode`/`message` are
|
|
141
|
+
// the two fields `elicitationRequestFromPayload` (`ElicitationRequest.kt`) requires no matter which
|
|
142
|
+
// mode arrives — a payload missing either is dropped silently server-side (`runCatching { ... }
|
|
143
|
+
// .getOrNull()`), the same "advisory here, silent there" gap the `permission_request` checks above
|
|
144
|
+
// exist to close.
|
|
145
|
+
if (event.eventName === 'elicitation_request') {
|
|
146
|
+
if (!nonEmptyString(payload.requestId)) {
|
|
147
|
+
return { reason: 'invalid elicitation_request', detail: 'requestId must be a non-empty string' };
|
|
148
|
+
}
|
|
149
|
+
const request = payload.request;
|
|
150
|
+
if (request === null || typeof request !== 'object' || Array.isArray(request)) {
|
|
151
|
+
return { reason: 'invalid elicitation_request', detail: 'request must be an object' };
|
|
152
|
+
}
|
|
153
|
+
const requestPayload = request;
|
|
154
|
+
if (!nonEmptyString(requestPayload.mode)) {
|
|
155
|
+
return { reason: 'invalid elicitation_request', detail: 'request.mode must be a non-empty string' };
|
|
156
|
+
}
|
|
157
|
+
if (!nonEmptyString(requestPayload.message)) {
|
|
158
|
+
return { reason: 'invalid elicitation_request', detail: 'request.message must be a non-empty string' };
|
|
159
|
+
}
|
|
160
|
+
}
|
|
133
161
|
return null;
|
|
134
162
|
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The agent channel's global socket gate (Task 20, spec 2026-10-11 §5.6; `desktop/bridge.ts` is the precedent).
|
|
3
|
+
*
|
|
4
|
+
* Session frames are sent only while the encrypted socket's `bufferedAmount` is below {@link SOCKET_HIGH_WATER_BYTES}; once it
|
|
5
|
+
* reaches that, they wait until it has drained to {@link SOCKET_LOW_WATER_BYTES}. The channel's heartbeat is written straight to
|
|
6
|
+
* the same socket by the channel itself, so what this bounds is how much it can find queued ahead of it: about 1 MiB plus one
|
|
7
|
+
* frame instead of everything a talkative agent produced — on a slow link, seconds instead of minutes, and a heartbeat that misses
|
|
8
|
+
* its ack closes the channel.
|
|
9
|
+
*
|
|
10
|
+
* What goes through the gate, and what does not (B §4.3/§5):
|
|
11
|
+
*
|
|
12
|
+
* - **session frames** (`agent_event`, `agent_turn_done`: numbered, recorded in the outbox, acknowledged by the server) wait for
|
|
13
|
+
* the gate **and** their session's window (`acp/outbox.ts`). `agent_turn_done` is one of them, not a control frame: the server
|
|
14
|
+
* moves `lastSeenSeq` on it, so letting it overtake lower-seq events would make the server drop them as duplicates;
|
|
15
|
+
* - **subagent relations** (`agent_event{eventName:'subagent_spawned'}`, the server's `SubagentSpawned`) that resolve a child
|
|
16
|
+
* frame recorded before them bypass the session window — with the frames before them, in seq order — but not the gate: the
|
|
17
|
+
* server caps its acks below the first child frame still waiting for its relation (`ExternalAgentEventApplier.noteApplied`,
|
|
18
|
+
* `nativePendingBefore - 1`), so a window that held the relation back would wait for an ack that cannot come (the server
|
|
19
|
+
* poisons after 30 s and every reopen repeats it). Mechanism and the producing side: `acp/outbox.ts`;
|
|
20
|
+
* - **bulk unnumbered** frames (`agent_backfill_events`) wait for the gate only — they are never acknowledged, so no session
|
|
21
|
+
* window could ever open for them;
|
|
22
|
+
* - **control frames** bypass both and are written at once: RPC replies (`agent_opened`, `agent_steered`,
|
|
23
|
+
* `agent_config_option_set`, `agent_native_sessions`, `agent_native_deleted`, `agent_verified`, `agent_authenticated`,
|
|
24
|
+
* `agent_installed`, `agent_delegation_renewed`, `agent_provider_task_stopped`, `agent_backfill_done`), levels
|
|
25
|
+
* (`agent_session_state`, `agent_runtime_profile`, `agent_provider_task_event`), `agent_session_lost`, `agent_resume_offer`,
|
|
26
|
+
* `agent_auth_url`/`agent_auth_done`, and the channel's own heartbeat. They are small and rare, an answer the server is waiting
|
|
27
|
+
* for (a 10–120 s timeout) must not queue behind a session's backlog, and an answer to a user (a permission card's state) must
|
|
28
|
+
* not wait for the window that answer is about to open. They still count against the gate: they add to `bufferedAmount`, which
|
|
29
|
+
* session frames then wait on.
|
|
30
|
+
*/
|
|
31
|
+
/** Session frames stop once the socket holds this much unsent (spec §5.6). */
|
|
32
|
+
export const SOCKET_HIGH_WATER_BYTES = 1024 * 1024;
|
|
33
|
+
/** …and resume once it has drained to this (spec §5.6). */
|
|
34
|
+
export const SOCKET_LOW_WATER_BYTES = 256 * 1024;
|
|
35
|
+
/** How often a closed gate looks at the socket again. */
|
|
36
|
+
export const SOCKET_POLL_MS = 25;
|
|
37
|
+
export class SocketGate {
|
|
38
|
+
bufferedAmount;
|
|
39
|
+
closed = false;
|
|
40
|
+
timer;
|
|
41
|
+
waiters = new Set();
|
|
42
|
+
/** `bufferedAmount` of the bound socket; `undefined`: no socket to measure (the gate stays open). */
|
|
43
|
+
constructor(bufferedAmount = undefined) {
|
|
44
|
+
this.bufferedAmount = bufferedAmount;
|
|
45
|
+
}
|
|
46
|
+
/** A new connection (or none): its own buffer; whatever waited is woken to look again. */
|
|
47
|
+
rebind(bufferedAmount) {
|
|
48
|
+
this.bufferedAmount = bufferedAmount;
|
|
49
|
+
this.closed = false;
|
|
50
|
+
this.wake();
|
|
51
|
+
}
|
|
52
|
+
/** May a session frame be written now? Closes at the high water mark, reopens at the low one. */
|
|
53
|
+
isOpen() {
|
|
54
|
+
const buffered = this.bufferedAmount?.() ?? 0;
|
|
55
|
+
if (this.closed) {
|
|
56
|
+
if (buffered > SOCKET_LOW_WATER_BYTES)
|
|
57
|
+
return false;
|
|
58
|
+
this.closed = false;
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
if (buffered >= SOCKET_HIGH_WATER_BYTES) {
|
|
62
|
+
this.closed = true;
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
/** Calls `then` once the gate is open again (polling the socket while it is closed). */
|
|
68
|
+
whenOpen(then) {
|
|
69
|
+
this.waiters.add(then);
|
|
70
|
+
this.poll();
|
|
71
|
+
}
|
|
72
|
+
/** Resolves when the gate is open. */
|
|
73
|
+
opened() {
|
|
74
|
+
if (this.isOpen())
|
|
75
|
+
return Promise.resolve();
|
|
76
|
+
return new Promise((resolve) => this.whenOpen(resolve));
|
|
77
|
+
}
|
|
78
|
+
poll() {
|
|
79
|
+
if (this.timer || this.waiters.size === 0)
|
|
80
|
+
return;
|
|
81
|
+
this.timer = setTimeout(() => {
|
|
82
|
+
this.timer = undefined;
|
|
83
|
+
if (this.isOpen())
|
|
84
|
+
this.wake();
|
|
85
|
+
else
|
|
86
|
+
this.poll();
|
|
87
|
+
}, SOCKET_POLL_MS);
|
|
88
|
+
this.timer.unref?.();
|
|
89
|
+
}
|
|
90
|
+
wake() {
|
|
91
|
+
const waiters = [...this.waiters];
|
|
92
|
+
this.waiters.clear();
|
|
93
|
+
for (const waiter of waiters)
|
|
94
|
+
waiter();
|
|
95
|
+
}
|
|
96
|
+
/** Stops polling (daemon shutdown). Waiters are dropped. */
|
|
97
|
+
dispose() {
|
|
98
|
+
if (this.timer)
|
|
99
|
+
clearTimeout(this.timer);
|
|
100
|
+
this.timer = undefined;
|
|
101
|
+
this.waiters.clear();
|
|
102
|
+
}
|
|
103
|
+
}
|