Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
153 commits
Select commit Hold shift + click to select a range
44036f4
feat(cli): add agent view supervisor runtime
Jul 22, 2026
1b994c1
feat(cli): add agent view pty workers
Jul 22, 2026
c26c53a
feat(cli): manage agent view session lifecycle
Jul 22, 2026
cddb16b
feat(cli): expose agent view commands
Jul 22, 2026
fff0a6d
feat(cli): add agent view roster ui
Jul 22, 2026
b469884
fix(cli): harden agent view supervisor runtime
Jul 28, 2026
f101d28
fix(cli): harden agent view pty workers
Jul 28, 2026
fb7fc76
fix(cli): preserve agent view lifecycle state
Jul 28, 2026
d7cb728
fix(cli): wire agent view command safeguards
Jul 28, 2026
172322d
Merge branch 'agent/agent-view-commands' into agent/agent-view-roster-ui
Jul 28, 2026
c84e1dc
fix(cli): surface supervisor startup failures
Jul 28, 2026
eca1fc4
fix(cli): handle supervisor subscription failures
Jul 28, 2026
5217c6f
Merge branch 'main' into agent/agent-view-supervisor-runtime
qwen-code-dev-bot Jul 28, 2026
ee693b3
fix(cli): address review feedback on agent-view supervisor (#7799)
Jul 28, 2026
d4c3f0f
Merge branch 'main' into agent/agent-view-supervisor-runtime
qwen-code-dev-bot Jul 28, 2026
214a1cf
fix(cli): address review feedback on agent-view supervisor (#7799)
qwen-code-ci-bot Jul 28, 2026
a901609
fix(cli): address review feedback on agent-view supervisor (#7799)
qwen-code-ci-bot Jul 28, 2026
e149bc1
fix(cli): address review feedback on agent-view supervisor (#7799)
Jul 28, 2026
069b78b
Merge branch 'main' into agent/agent-view-supervisor-runtime
qwen-code-dev-bot Jul 28, 2026
b3caf9b
Merge branch 'main' into agent/agent-view-supervisor-runtime
ZijianZhang989 Jul 29, 2026
4e9ac53
fix(cli): bind streaming supervisor handlers and keep attach stream 8…
qwen-code-ci-bot Jul 30, 2026
437522e
fix(cli): pause attach socket during leftover write and harden error …
Jul 30, 2026
f263b18
fix(cli): harden supervisor shutdown tests and clean up signal listen…
Jul 30, 2026
acef632
fix(cli): guard fire-and-forget promises and add supervisor timeout t…
qwen-code-ci-bot Jul 30, 2026
6302b8e
fix(cli): normalize socket path test prefix and force credential file…
qwen-code-ci-bot Jul 30, 2026
e5f150a
fix(cli): address agent view runtime review feedback
Jul 31, 2026
4a9aa30
test(cli): cover agent view bridge edge cases
Jul 31, 2026
09f6d44
test(core): isolate worktree symlink traversal fixture
Jul 31, 2026
678f884
Revert "test(core): isolate worktree symlink traversal fixture"
Jul 31, 2026
5b69eae
Merge branch 'main' into agent/agent-view-supervisor-runtime
qwen-code-dev-bot Jul 31, 2026
5776467
fix(cli): harden agent view supervisor store, auth, and streaming (#7…
qwen-code-dev-bot Jul 31, 2026
9203dbd
fix(cli): harden agent view store joins, writes, and coverage (#7799)
qwen-code-dev-bot Jul 31, 2026
1bcf793
fix(cli): harden agent view credential writes and subscription handsh…
qwen-code-dev-bot Jul 31, 2026
1ae6b75
fix(cli): harden agent view store normalization, roster safety, and b…
Aug 1, 2026
0264edb
fix(cli): guard response serialization in supervisor server (#7799)
qwen-code-ci-bot Aug 1, 2026
0dd7980
fix(cli): harden agent view pty host teardown
Aug 3, 2026
b10135f
fix(cli): fail fast on pty host auth rejection
Aug 3, 2026
f0ca335
Merge remote-tracking branch 'origin/agent/agent-view-supervisor-runt…
Aug 3, 2026
22280ee
test(cli): cover pty host remote exit polling
Aug 3, 2026
e811cb4
fix(cli): address agent view pty worker review nits
Aug 5, 2026
d1eb5d5
Merge remote-tracking branch 'origin/main' into agent/agent-view-pty-…
Aug 5, 2026
79df20e
fix(cli): harden pty host socket fallback
Aug 5, 2026
e28e3fc
fix(cli): harden agent view lifecycle persistence
Aug 5, 2026
bcc08f4
Merge remote-tracking branch 'origin/main' into agent/agent-view-pty-…
Aug 6, 2026
016322c
fix(cli): harden agent view pty workers
Aug 6, 2026
5c17167
Merge remote-tracking branch 'origin/agent/agent-view-pty-workers' in…
Aug 6, 2026
eb7f0c7
fix(cli): harden agent view lifecycle
Aug 6, 2026
c96c934
fix(cli): harden agent view pty workers
Aug 6, 2026
8c76fd2
test(cli): cover pty host spawn contract
Aug 6, 2026
f791eab
chore(cli): merge agent view lifecycle into agent view commands
qwen-code-dev-bot Aug 6, 2026
7435bd6
fix(cli): harden agent view lifecycle recovery
Aug 7, 2026
c3a6016
fix(cli): guard agent view pty host socket takeover and races
qwen-code-ci-bot Aug 8, 2026
6b85924
fix(cli): fit agent view pty logs under wire cap, strip host token af…
qwen-code-ci-bot Aug 8, 2026
b2deec7
Merge branch 'main' into agent/agent-view-pty-workers
wenshao Aug 8, 2026
4d5a1c1
fix(cli): close agent view lifecycle review gaps
Aug 9, 2026
eca1f8f
fix(cli): harden pty host fallback selection
Aug 9, 2026
f002b19
fix(cli): address agent view worker review blockers
Aug 10, 2026
da92f43
fix(cli): bound attach lease ttl and surface pty host input/listen fa…
Aug 10, 2026
9eb28ee
fix(cli): address lifecycle review suggestions
Aug 10, 2026
e94dde0
fix(cli): serialize pty host socket ownership and keep attach transpo…
Aug 10, 2026
b2e7747
fix(cli): Address round-4 agent-view lifecycle review feedback
Aug 10, 2026
012c4db
fix(cli): escalate pty host shutdown and harden socket path fallback
Aug 11, 2026
37e9171
fix(cli): Address round-5 agent-view lifecycle review feedback
Aug 11, 2026
b61917a
fix(cli): harden win32 kill, decoder reset, and exit tracker
Aug 11, 2026
244d162
fix(cli): skip POSIX signal tests on Windows and reclaim empty lock f…
Aug 11, 2026
cd9e7b2
fix(cli): address R6 review findings and slim test suite
Aug 11, 2026
07513f9
fix(cli): remove abort listener on delay timeout path
Aug 12, 2026
93fad08
fix(cli): don't optimistically resolve exited on SIGINT for remote ha…
Aug 12, 2026
2d2aa67
Merge agent/agent-view-pty-workers into agent/agent-view-lifecycle
Aug 12, 2026
22f610c
Merge remote-tracking branch 'origin/main' into codex/qwen-code-pr-7800
Aug 12, 2026
8dfd4c6
fix(cli): address R7 review findings
Aug 12, 2026
c188aca
Merge branch 'agent/agent-view-pty-workers' into agent/agent-view-lif…
Aug 12, 2026
8bd8ca9
fix(cli): don't optimistically resolve exit tracker on SIGINT
Aug 12, 2026
61632b6
fix(cli): sync non-agent-view files to latest pty-workers base
Aug 12, 2026
a1fee18
Merge remote-tracking branch 'origin/agent/agent-view-pty-workers' in…
Aug 12, 2026
d817313
Merge remote-tracking branch 'origin/agent/agent-view-lifecycle' into…
Aug 12, 2026
4c70e72
fix(cli): address agent view commands review findings
Aug 12, 2026
c56cf4a
test(cli): add SIGINT carve-out test for remote handle kill
Aug 12, 2026
49fe189
fix(cli): Only resolve exited on SIGKILL for remote handle kill
Aug 13, 2026
0283a13
fix(cli): address R8 review findings
Aug 13, 2026
6f67f8d
fix(cli): address remaining R8 critical findings
Aug 13, 2026
9aa91e1
fix(cli): harden agent view command surface and resume guards
Aug 13, 2026
4089a46
fix(cli): add en.js key for /background description to satisfy check-…
Aug 13, 2026
19e1c3d
Merge remote-tracking branch 'origin/main' into codex/qwen-code-pr-7800
Aug 13, 2026
6b64cf3
fix(cli): close agent-view respawn, worker-event and prompt-marker races
Aug 13, 2026
8a3f89f
fix(cli): harden agent view PTY host socket lock and kill default
Aug 13, 2026
b4b2922
fix(cli): address round-2 review findings for agent view commands
Aug 13, 2026
82dc338
fix(cli): close agent-view stale-attach, stop-fallback and hibernate …
Aug 13, 2026
99c493f
Merge remote-tracking branch 'origin/main' into codex/qwen-code-pr-7800
Aug 13, 2026
640d437
fix(cli): fix agent view PTY host dispose signal, ring trim, and lock…
Aug 14, 2026
4b42946
fix(cli): Address round-3 review feedback for agent view commands
Aug 14, 2026
79e8acc
Merge remote-tracking branch 'origin/agent/agent-view-pty-workers' in…
Aug 14, 2026
3fffe40
fix(cli): close R11 stop-clobber, restart marker wedge and ready-wait…
Aug 14, 2026
126dfb5
fix(cli): Address round 4 review feedback on agent view commands
Aug 14, 2026
38b1073
fix(cli): settle remote pty host exit only after the RPC lands
Aug 14, 2026
7e8d984
fix(cli): optional-call shutdown in the lost-RPC regression test
Aug 14, 2026
8572f36
Merge remote-tracking branch 'origin/main' into codex/qwen-code-pr-7800
Aug 17, 2026
509b038
fix(cli): Address round 5 review feedback on agent view commands
Aug 17, 2026
b78e374
fix(cli): close R12 stop-launch orphan, marker clobber and pid-signal…
Aug 17, 2026
538af5a
Merge origin/agent/agent-view-lifecycle into agent/agent-view-commands
Aug 17, 2026
9122f20
fix(cli): Address round 6 review feedback on agent view commands
Aug 17, 2026
f88de85
Merge remote-tracking branch 'origin/agent/agent-view-commands' into …
Aug 17, 2026
adc3bbf
fix(cli): close R13 verdict races, resume casing and stop/respawn lif…
Aug 17, 2026
1d53165
refactor(cli): address review feedback on agent view roster UI
Aug 17, 2026
cfa9750
fix(cli): Address round 7 review feedback on agent view commands
Aug 18, 2026
4c21f39
fix(cli): close R14 respawn EADDRINUSE, dispatch pid timing and stale…
Aug 18, 2026
8606ca3
fix(cli): address round 1 review feedback on agent view roster UI
Aug 18, 2026
8bb64c8
test(cli): pin dispatch error, peek refresh, and attach-not-send beha…
Aug 18, 2026
451058e
chore: revert package-lock.json lightningcss peer flag churn
Aug 18, 2026
b14082e
fix(cli): Harden Agent View lifecycle verdicts, ghost cleanup, and re…
Aug 18, 2026
878eeda
Merge agent/agent-view-pty-workers into agent/agent-view-lifecycle
Aug 18, 2026
b3b4fc0
fix(cli): Address round 8 review feedback on agent view commands
Aug 18, 2026
09ff38d
fix(cli): Address agent view roster review findings
Aug 18, 2026
0023384
fix(cli): Address round 9 review feedback on agent view commands
Aug 18, 2026
ff20a1a
fix(cli): Confirm worker death before terminal verdicts and close ros…
Aug 18, 2026
b8b6f41
fix(cli): Address remaining agent view review findings
Aug 18, 2026
6fc40ee
fix(cli): harden agent view lifecycle races
Aug 19, 2026
f2ffbdc
fix(cli): complete agent view command handoff
Aug 19, 2026
f8961af
fix(cli): serialize agent view lifecycle transitions
Aug 19, 2026
791ea6e
fix(cli): stabilize agent view roster interactions
Aug 19, 2026
d583ee6
Merge remote-tracking branch 'origin/agent/agent-view-lifecycle' into…
Aug 19, 2026
70ead6d
fix(cli): close agent view prompt recovery races
Aug 19, 2026
0cbec77
fix(cli): close agent view review gaps
Aug 19, 2026
f9d7af3
Merge remote-tracking branch 'origin/agent/agent-view-commands' into …
Aug 19, 2026
b6b1097
fix(cli): address critical agent view roster findings
Aug 19, 2026
3c63475
fix(cli): wait for PTY host endpoint shutdown
yiliang114 Aug 19, 2026
eccde8c
Merge remote-tracking branch 'origin/agent/agent-view-pty-workers' in…
yiliang114 Aug 19, 2026
6432b72
fix(cli): close agent view lifecycle races
yiliang114 Aug 19, 2026
9b837b7
Merge remote-tracking branch 'origin/agent/agent-view-lifecycle' into…
yiliang114 Aug 19, 2026
50755ec
fix(cli): close agent view command review gaps
yiliang114 Aug 19, 2026
3963135
Merge remote-tracking branch 'origin/agent/agent-view-commands' into …
yiliang114 Aug 19, 2026
3e41df5
fix(cli): address agent view roster review blockers
Aug 20, 2026
9a7bad8
fix(cli): make agent view lifecycle recoverable
Aug 20, 2026
f916518
Merge remote-tracking branch 'origin/agent/agent-view-lifecycle' into…
Aug 20, 2026
1e1d178
fix(cli): consolidate agent view roster state
Aug 20, 2026
84653bb
fix(cli): gate and harden agent view commands
Aug 20, 2026
b0b103c
fix(cli): close agent view lifecycle races
Aug 20, 2026
3699f15
fix(cli): close Agent View lifecycle edge cases
Aug 20, 2026
146ca15
fix(cli): harden agent view interactions
Aug 20, 2026
d0fa70a
fix(cli): serialize stopped session healing
Aug 21, 2026
fe77fba
Merge remote-tracking branch 'origin/agent/agent-view-lifecycle' into…
Aug 21, 2026
a343c9f
fix(cli): protect advanced startup worktree branches
Aug 21, 2026
75b4af8
Merge remote-tracking branch 'origin/agent/agent-view-commands' into …
Aug 21, 2026
26dd443
fix(cli): close agent view roster state gaps
Aug 21, 2026
94700f3
fix(cli): close remaining command edge cases
Aug 21, 2026
34ce2a1
Merge remote-tracking branch 'origin/agent/agent-view-commands' into …
Aug 21, 2026
fa73dcc
fix(cli): close remaining agent view roster gaps
Aug 21, 2026
c6212f1
fix(cli): isolate PTY host credentials
Aug 21, 2026
14f1ebf
fix(cli): close roster control gaps
Aug 22, 2026
0a86895
Merge remote-tracking branch 'origin/agent/agent-view-commands' into …
Aug 22, 2026
a7cb7c4
fix(cli): close agent view roster edge cases
Aug 23, 2026
d7ccfe3
fix(cli): harden agent view roster interactions
Aug 24, 2026
0791811
fix(cli): filter roster modifyOtherKeys residue
Aug 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions docs/design/2026-08-19-agent-view-command-handoff.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Agent View command handoff

PR 7802 exposes Agent View entry points that must be safe without the roster UI
from PR 7803. This change moves only the runtime behavior required by those
entry points.

- Initial background prompts are passed in the worker argv while dispatch still
waits for the worker-ready event.
- A native `/background` adoption shuts down and exits the foreground runtime
after the supervisor accepts the handoff.
- An attached worker detaches through the existing worker sideband event.
- Interactive resume rejects live managed sessions after direct or picker
resolution.
- `agents` is a reserved command word with an explicit `list` spelling;
ambiguous separator and boolean-assignment forms fail loudly.
- Background dispatch rejects every explicitly supplied per-invocation boolean,
including false and negated forms that are not forwarded to the worker.
- A hibernated worker is treated like an exited worker for foreground
`--continue` takeover.
- A startup worktree created before managed-session routing is discarded on an
early attach or rejection, so it cannot pin a branch without a session
sidecar.

Roster rendering, peek, answer, redraw, and general worker-control polling stay
in PR 7803.
257 changes: 257 additions & 0 deletions packages/cli/src/agent-view/attach-lease.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,257 @@
/**
* @license
* Copyright 2026 Qwen Team
* SPDX-License-Identifier: Apache-2.0
*/

import { describe, expect, it } from 'vitest';
import {
AgentViewAttachLeaseManager,
MAX_AGENT_VIEW_ATTACH_LEASE_TTL_MS,
} from './attach-lease.js';

describe('AgentViewAttachLeaseManager', () => {
it('acquires a lease for an unattached session', () => {
const clock = fakeClock('2026-07-17T00:00:00.000Z');
const manager = new AgentViewAttachLeaseManager({
now: clock.now,
createLeaseId: () => 'lease-1',
defaultTtlMs: 1000,
});

expect(manager.acquire('session-1', { clientId: 'terminal-1' })).toEqual({
ok: true,
lease: {
sessionId: 'session-1',
leaseId: 'lease-1',
clientId: 'terminal-1',
acquiredAt: '2026-07-17T00:00:00.000Z',
lastHeartbeatAt: '2026-07-17T00:00:00.000Z',
expiresAt: '2026-07-17T00:00:01.000Z',
},
});
});

it('uses a random lease id when no id factory is provided', () => {
const manager = new AgentViewAttachLeaseManager();
const result = manager.acquire('session-1');

expect(result).toMatchObject({
ok: true,
lease: {
sessionId: 'session-1',
},
});
if (result.ok) {
expect(result.lease.leaseId).toMatch(
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/,
);
}
});

it('isolates leases across sessions', () => {
const clock = fakeClock('2026-07-17T00:00:00.000Z');
let idCounter = 0;
const manager = new AgentViewAttachLeaseManager({
now: clock.now,
createLeaseId: () => `lease-${++idCounter}`,
});

const first = manager.acquire('session-a', { clientId: 'terminal-a' });
const second = manager.acquire('session-b', { clientId: 'terminal-b' });

expect(first.ok && first.lease.leaseId).toBe('lease-1');
expect(second.ok && second.lease.leaseId).toBe('lease-2');

// Session B's lease must not disturb session A's.
expect(manager.get('session-a')?.leaseId).toBe('lease-1');
expect(manager.heartbeat('session-a', 'lease-1')?.leaseId).toBe('lease-1');

// Releasing session A must not affect session B.
expect(manager.release('session-a', 'lease-1')).toBe(true);
expect(manager.get('session-a')).toBeUndefined();
expect(manager.get('session-b')?.leaseId).toBe('lease-2');
});

it('rejects a second acquire while a lease is active', () => {
const clock = fakeClock('2026-07-17T00:00:00.000Z');
const manager = new AgentViewAttachLeaseManager({
now: clock.now,
createLeaseId: () => 'lease-1',
});
const first = manager.acquire('session-1');

expect(
manager.acquire('session-1', {
leaseId: 'lease-2',
}),
).toEqual({
ok: false,
reason: 'already_attached',
lease: {
sessionId: first.lease.sessionId,
acquiredAt: first.lease.acquiredAt,
lastHeartbeatAt: first.lease.lastHeartbeatAt,
expiresAt: first.lease.expiresAt,
},
});
});

it('does not disclose the active lease id on contested acquire', () => {
const manager = new AgentViewAttachLeaseManager({
createLeaseId: () => 'lease-1',
});
manager.acquire('session-1');

const result = manager.acquire('session-1', { leaseId: 'lease-2' });

expect(result.ok).toBe(false);
if (!result.ok) {
expect('leaseId' in result.lease).toBe(false);
}
});

it('generates a lease id when the provided id is empty', () => {
const manager = new AgentViewAttachLeaseManager({
createLeaseId: () => 'generated-lease',
});

expect(manager.acquire('session-1', { leaseId: '' })).toMatchObject({
ok: true,
lease: {
leaseId: 'generated-lease',
},
});
});

it('releases only the matching lease', () => {
const manager = new AgentViewAttachLeaseManager({
createLeaseId: () => 'lease-1',
});
manager.acquire('session-1');

expect(manager.release('session-1', 'other-lease')).toBe(false);
expect(manager.get('session-1')).toMatchObject({ leaseId: 'lease-1' });
expect(manager.release('session-1', 'lease-1')).toBe(true);
expect(manager.get('session-1')).toBeUndefined();
});

it('rejects non-positive, oversized, and non-finite ttls', () => {
const manager = new AgentViewAttachLeaseManager();

expect(() => manager.acquire('session-1', { ttlMs: 0 })).toThrow(
'Attach lease ttlMs must be positive.',
);
expect(() => manager.acquire('session-1', { ttlMs: Number.NaN })).toThrow(
RangeError,
);
expect(() =>
manager.acquire('session-1', {
ttlMs: MAX_AGENT_VIEW_ATTACH_LEASE_TTL_MS + 1,
}),
).toThrow('Attach lease ttlMs must not exceed');
expect(() => manager.acquire('')).toThrow(
'Agent View session id is required.',
);
expect(manager.get('session-1')).toBeUndefined();
});

it('honors per-call ttls and expires lazily through get and release', () => {
const clock = fakeClock('2026-07-17T00:00:00.000Z');
const manager = new AgentViewAttachLeaseManager({
now: clock.now,
createLeaseId: () => 'lease-1',
defaultTtlMs: 1000,
});
manager.acquire('session-1', { ttlMs: 2000 });

clock.advance(1500);
expect(manager.get('session-1')).toMatchObject({ leaseId: 'lease-1' });
expect(
manager.heartbeat('session-1', 'lease-1', { ttlMs: 3000 }),
).toMatchObject({ expiresAt: '2026-07-17T00:00:04.500Z' });

clock.advance(3000);
expect(manager.get('session-1')).toBeUndefined();
expect(manager.release('session-1', 'lease-1')).toBe(false);
});

it('expires stale leases and allows reacquire', () => {
const clock = fakeClock('2026-07-17T00:00:00.000Z');
const leaseIds = ['lease-1', 'lease-2'];
const manager = new AgentViewAttachLeaseManager({
now: clock.now,
createLeaseId: () => leaseIds.shift() ?? 'missing-lease',
defaultTtlMs: 1000,
});
const first = manager.acquire('session-1');

clock.advance(1000);

expect(manager.expire()).toEqual([first.lease]);
expect(manager.acquire('session-1')).toMatchObject({
ok: true,
lease: {
leaseId: 'lease-2',
acquiredAt: '2026-07-17T00:00:01.000Z',
},
});
});

it('expires corrupted leases with invalid timestamps', () => {
const manager = new AgentViewAttachLeaseManager({
createLeaseId: () => 'lease-1',
});
manager.acquire('session-1');
(
manager as unknown as {
leases: Map<string, { expiresAt: string }>;
}
).leases.get('session-1')!.expiresAt = 'not-a-date';

expect(manager.expire()).toEqual([
expect.objectContaining({
sessionId: 'session-1',
leaseId: 'lease-1',
expiresAt: 'not-a-date',
}),
]);
expect(manager.get('session-1')).toBeUndefined();
});

it('heartbeat extends the matching lease', () => {
const clock = fakeClock('2026-07-17T00:00:00.000Z');
const manager = new AgentViewAttachLeaseManager({
now: clock.now,
createLeaseId: () => 'lease-1',
defaultTtlMs: 1000,
});
manager.acquire('session-1');
clock.advance(500);

expect(manager.heartbeat('session-1', 'wrong-lease')).toBeUndefined();
expect(manager.heartbeat('session-1', 'lease-1')).toMatchObject({
sessionId: 'session-1',
leaseId: 'lease-1',
acquiredAt: '2026-07-17T00:00:00.000Z',
lastHeartbeatAt: '2026-07-17T00:00:00.500Z',
expiresAt: '2026-07-17T00:00:01.500Z',
});

clock.advance(999);
expect(manager.get('session-1')).toMatchObject({ leaseId: 'lease-1' });
});
});

function fakeClock(start: string): {
now: () => Date;
advance: (ms: number) => void;
} {
let nowMs = Date.parse(start);
return {
now: () => new Date(nowMs),
advance: (ms: number) => {
nowMs += ms;
},
};
}
Loading