@cmetech/otto 1.0.6 → 1.0.8
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 +32 -32
- package/package.json +6 -6
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/package.json +3 -3
- package/packages/mcp-server/package.json +3 -3
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/package.json +2 -2
- package/packages/pi-tui/package.json +1 -1
- package/packages/rpc-client/package.json +2 -2
- package/pkg/package.json +1 -1
- package/scripts/install.js +57 -0
package/README.md
CHANGED
|
@@ -1,43 +1,43 @@
|
|
|
1
|
-
<!--
|
|
1
|
+
<!-- OTTO — the on-laptop coding & research assistant -->
|
|
2
2
|
|
|
3
|
-
#
|
|
3
|
+
# OTTO
|
|
4
4
|
|
|
5
|
-
> **O**rchestrating **T**ools, **T**asks
|
|
5
|
+
> **O**rchestrating, **T**ools, **T**asks & **O**utcomes
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
A terminal-resident coding, research, and operations assistant for developers, administrators, and project managers — built to keep tool execution local while routing every LLM call through a governable gateway.
|
|
8
8
|
|
|
9
|
-

|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
-
## What
|
|
13
|
+
## What OTTO is
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
OTTO is the **client CLI** users open in a terminal:
|
|
16
16
|
|
|
17
17
|
- **One entrypoint for three roles.** A developer asks it to refactor and run tests. An administrator asks it why a node paged last night. A project manager asks it to summarize this week's open tickets. Same CLI, same conversational interface.
|
|
18
18
|
- **Local execution by default.** Filesystem, bash, git, and tool calls run on the developer's laptop. Nothing leaves the machine unless the task genuinely needs remote data or remote inference.
|
|
19
|
-
- **Chat API in, ACP out.**
|
|
20
|
-
- **Compliance-friendly by construction.** When `OTTO_GATEWAY_URL` is set, every LLM token routes through that gateway so governance, audit, and content moderation all live in one place. With no gateway configured,
|
|
19
|
+
- **Chat API in, ACP out.** OTTO speaks standard chat-completion APIs (Anthropic / OpenAI / Ollama) to the OTTO Gateway, and REST to a local Langflow. It never speaks raw ACP — the Gateway translates and routes downstream.
|
|
20
|
+
- **Compliance-friendly by construction.** When `OTTO_GATEWAY_URL` is set, every LLM token routes through that gateway so governance, audit, and content moderation all live in one place. With no gateway configured, OTTO falls back to direct Anthropic.
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
OTTO is **not** a general-purpose AI assistant. It is a developer agent that also happens to trigger non-coding workflows through Langflow and reach into operational data through OSCAR.
|
|
23
23
|
|
|
24
24
|
This repo (`@cmetech/otto`, binary `otto`) is the **CLI** piece. The diagram above shows where it sits in the larger stack.
|
|
25
25
|
|
|
26
26
|
---
|
|
27
27
|
|
|
28
|
-
## Where
|
|
28
|
+
## Where OTTO fits in the stack
|
|
29
29
|
|
|
30
30
|
Everything inside the dashed laptop boundary in the diagram lives on the user's machine. Only OSCAR and the external systems behind it are remote.
|
|
31
31
|
|
|
32
|
-
| Component | Role | Where it lives | Relationship to
|
|
32
|
+
| Component | Role | Where it lives | Relationship to OTTO |
|
|
33
33
|
|---|---|---|---|
|
|
34
|
-
| **
|
|
35
|
-
| **OTTO Gateway** | Manages all ACP. Translates chat-API requests into ACP calls. Anthropic/OpenAI/Ollama-compatible. Hosts guardrails. | Laptop |
|
|
36
|
-
| **Langflow** | Low-code flow orchestrator for multi-step automations | Laptop |
|
|
37
|
-
| **kiro-cli ACP pool** | Pooled subprocess workers under the Gateway | Laptop | Where inference actually executes;
|
|
38
|
-
| **OSCAR** | Remote operations agent with an ACP interface. Holds network credentials. Reaches into production servers, lab environments, ticket systems, and knowledge bases. | Remote | Reached only via the Gateway's ACP channel —
|
|
34
|
+
| **OTTO** (this repo) | CLI client + conversation surface | Laptop | The user-facing entrypoint |
|
|
35
|
+
| **OTTO Gateway** | Manages all ACP. Translates chat-API requests into ACP calls. Anthropic/OpenAI/Ollama-compatible. Hosts guardrails. | Laptop | OTTO's primary backend — every LLM call lands here first |
|
|
36
|
+
| **Langflow** | Low-code flow orchestrator for multi-step automations | Laptop | OTTO calls it via REST when a task is "automate" rather than "ask" |
|
|
37
|
+
| **kiro-cli ACP pool** | Pooled subprocess workers under the Gateway | Laptop | Where inference actually executes; OTTO never talks to them directly |
|
|
38
|
+
| **OSCAR** | Remote operations agent with an ACP interface. Holds network credentials. Reaches into production servers, lab environments, ticket systems, and knowledge bases. | Remote | Reached only via the Gateway's ACP channel — OTTO never holds ops credentials |
|
|
39
39
|
|
|
40
|
-
The two ACP connections (Gateway ↔ kiro-cli and Gateway ↔ OSCAR) are the load-bearing protocol relationships in the stack.
|
|
40
|
+
The two ACP connections (Gateway ↔ kiro-cli and Gateway ↔ OSCAR) are the load-bearing protocol relationships in the stack. OTTO itself is intentionally protocol-thin.
|
|
41
41
|
|
|
42
42
|
---
|
|
43
43
|
|
|
@@ -45,7 +45,7 @@ The two ACP connections (Gateway ↔ kiro-cli and Gateway ↔ OSCAR) are the loa
|
|
|
45
45
|
|
|
46
46
|
> **The assistant carries the tools. The user keeps the keys.**
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
OTTO is built around a few non-negotiables:
|
|
49
49
|
|
|
50
50
|
**Local-first.** Tool execution, filesystem access, and developer state stay on the laptop. We don't ship work to a cloud worker when a local one will do.
|
|
51
51
|
|
|
@@ -53,7 +53,7 @@ OTTER is built around a few non-negotiables:
|
|
|
53
53
|
|
|
54
54
|
**Extension-first.** New capabilities belong in the `otto` extension, in skills, or in plugins — not in core. The core CLI stays lean. The terminal UI, the flow trigger system, and the prompt engineer all live as extensions.
|
|
55
55
|
|
|
56
|
-
**Provider-agnostic.**
|
|
56
|
+
**Provider-agnostic.** OTTO speaks Anthropic, OpenAI, or Ollama. The Gateway adapts to all three. No architectural decision should privilege one provider over another.
|
|
57
57
|
|
|
58
58
|
**Ship fast, fix fast.** Every release should work, but we'd rather ship and patch than delay and accumulate.
|
|
59
59
|
|
|
@@ -63,7 +63,7 @@ OTTER is built around a few non-negotiables:
|
|
|
63
63
|
|
|
64
64
|
## Status
|
|
65
65
|
|
|
66
|
-
**
|
|
66
|
+
**v1.x — released.** The CLI is functional and published to npm. The package name, binary name, and config-directory name (`~/.otto/`) all use lowercase `otto`; the product is **OTTO**.
|
|
67
67
|
|
|
68
68
|
---
|
|
69
69
|
|
|
@@ -86,7 +86,7 @@ cd otto-cli
|
|
|
86
86
|
./scripts/install.sh
|
|
87
87
|
```
|
|
88
88
|
|
|
89
|
-
The install script installs dependencies, builds the binary, symlinks `otto` into `~/.local/bin/`, and offers to launch the first-run config wizard so you can point
|
|
89
|
+
The install script installs dependencies, builds the binary, symlinks `otto` into `~/.local/bin/`, and offers to launch the first-run config wizard so you can point OTTO at your gateway and (optionally) at Langflow.
|
|
90
90
|
|
|
91
91
|
After install (either path):
|
|
92
92
|
|
|
@@ -96,13 +96,13 @@ otto --help # subcommands
|
|
|
96
96
|
otto config # re-run any part of the config wizard
|
|
97
97
|
```
|
|
98
98
|
|
|
99
|
-
See [`
|
|
99
|
+
See [`INSTALL.md`](INSTALL.md) for prerequisites, per-platform setup (Windows/macOS/Linux), and troubleshooting.
|
|
100
100
|
|
|
101
101
|
---
|
|
102
102
|
|
|
103
|
-
## What
|
|
103
|
+
## What OTTO can do
|
|
104
104
|
|
|
105
|
-
|
|
105
|
+
OTTO classifies each user ask into one of four task types, shown as chips in the diagram above:
|
|
106
106
|
|
|
107
107
|
| Chip | What it means | Where it routes |
|
|
108
108
|
|---|---|---|
|
|
@@ -126,7 +126,7 @@ The extension also registers tools for catalog management, component inspection,
|
|
|
126
126
|
|
|
127
127
|
## Configuration
|
|
128
128
|
|
|
129
|
-
|
|
129
|
+
OTTO reads from `~/.otto/config.json` (created by the first-run wizard) with env-var overrides:
|
|
130
130
|
|
|
131
131
|
| Env var | Purpose | Default |
|
|
132
132
|
|---|---|---|
|
|
@@ -146,10 +146,10 @@ Env vars always win over the config file. Run `otto config` to interactively set
|
|
|
146
146
|
|
|
147
147
|
The activity-flow diagram at the top of this README is the canonical picture of how a request becomes an answer. A few things worth calling out for governance reviewers:
|
|
148
148
|
|
|
149
|
-
1. **
|
|
150
|
-
2. **
|
|
149
|
+
1. **OTTO never speaks ACP.** All inter-agent protocol traffic is handled by the OTTO Gateway. A compromised CLI surface cannot directly issue ACP commands.
|
|
150
|
+
2. **OTTO never holds ops credentials.** Credentials for production servers, ticket systems, and lab environments live with OSCAR (remote). OTTO asks; OSCAR fetches.
|
|
151
151
|
3. **One LLM egress point.** With `OTTO_GATEWAY_URL` set, the laptop has exactly one outbound LLM destination. Audit log, content moderation, rate limiting, and schema validation are configured there, once.
|
|
152
|
-
4. **Local-only requests never leave the laptop.**
|
|
152
|
+
4. **Local-only requests never leave the laptop.** OTTO classifies "Code" and "Research" asks; many resolve against kiro-cli locally without any network call beyond the laptop boundary.
|
|
153
153
|
|
|
154
154
|
The corresponding architecture diagram for the Gateway itself lives in [`docs/branding/otto_architecture_infographic.jpg`](docs/branding/otto_architecture_infographic.jpg). Both diagrams are generated from prompts checked into the same folder.
|
|
155
155
|
|
|
@@ -157,7 +157,7 @@ The corresponding architecture diagram for the Gateway itself lives in [`docs/br
|
|
|
157
157
|
|
|
158
158
|
## Documentation
|
|
159
159
|
|
|
160
|
-
- [`
|
|
160
|
+
- [`INSTALL.md`](INSTALL.md) — install / uninstall / troubleshoot
|
|
161
161
|
- [`docs/user-docs/package-management.md`](docs/user-docs/package-management.md) — install packages that extend OTTO
|
|
162
162
|
- [`docs/branding/`](docs/branding/) — naming, logo prompts, infographics (activity flow + gateway architecture)
|
|
163
163
|
- [`docs/superpowers/specs/`](docs/superpowers/specs/) — design specifications
|
|
@@ -182,11 +182,11 @@ Plans live in [`docs/superpowers/plans/`](docs/superpowers/plans/) — one per p
|
|
|
182
182
|
|
|
183
183
|
## Fork attribution
|
|
184
184
|
|
|
185
|
-
|
|
185
|
+
OTTO (`@cmetech/otto`) is a **permanent hard fork** of [open-gsd/gsd-pi](https://github.com/open-gsd/gsd-pi) by Lex Christopherson, used under the MIT License. The upstream `gsd-pi` provides the agent core, the terminal UI, the extension system, and the multi-step workflow commands. OTTO adds:
|
|
186
186
|
|
|
187
187
|
- The `otto` extension (Langflow flow triggers, flow builder, prompt engineer, catalog tools)
|
|
188
188
|
- Gateway routing for LLM traffic
|
|
189
|
-
-
|
|
189
|
+
- OTTO brand identity and terminal UI styling
|
|
190
190
|
- Compliance and audit posture
|
|
191
191
|
|
|
192
192
|
See [`LICENSE`](LICENSE) for the full list of fork edits.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cmetech/otto",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"description": "Terminal-based developer chat assistant. Permanent hard fork of gsd-pi with LangFlow flow triggers, a flow builder, and optional gateway routing for compliance environments.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -182,11 +182,11 @@
|
|
|
182
182
|
"@anthropic-ai/claude-agent-sdk": "0.2.83",
|
|
183
183
|
"fsevents": "~2.3.3",
|
|
184
184
|
"koffi": "^2.9.0",
|
|
185
|
-
"@cmetech/otto-engine-darwin-arm64": "1.0.
|
|
186
|
-
"@cmetech/otto-engine-darwin-x64": "1.0.
|
|
187
|
-
"@cmetech/otto-engine-linux-arm64-gnu": "1.0.
|
|
188
|
-
"@cmetech/otto-engine-linux-x64-gnu": "1.0.
|
|
189
|
-
"@cmetech/otto-engine-win32-x64-msvc": "1.0.
|
|
185
|
+
"@cmetech/otto-engine-darwin-arm64": "1.0.8",
|
|
186
|
+
"@cmetech/otto-engine-darwin-x64": "1.0.8",
|
|
187
|
+
"@cmetech/otto-engine-linux-arm64-gnu": "1.0.8",
|
|
188
|
+
"@cmetech/otto-engine-linux-x64-gnu": "1.0.8",
|
|
189
|
+
"@cmetech/otto-engine-win32-x64-msvc": "1.0.8"
|
|
190
190
|
},
|
|
191
191
|
"overrides": {
|
|
192
192
|
"gaxios": "7.1.4",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@otto-build/daemon",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"description": "OTTO daemon — background process for project monitoring and Discord integration",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@anthropic-ai/sdk": "^0.52.0",
|
|
32
|
-
"@otto-build/contracts": "^1.0.
|
|
33
|
-
"@otto-build/rpc-client": "^1.0.
|
|
32
|
+
"@otto-build/contracts": "^1.0.8",
|
|
33
|
+
"@otto-build/rpc-client": "^1.0.8",
|
|
34
34
|
"discord.js": "^14.25.1",
|
|
35
35
|
"yaml": "^2.8.0",
|
|
36
36
|
"zod": "^3.24.0"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@otto-build/mcp-server",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"description": "MCP server exposing OTTO orchestration tools for compatible clients",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"otto": {
|
|
@@ -34,8 +34,8 @@
|
|
|
34
34
|
"test": "npm run build:test && node --test dist/mcp-server.test.js dist/remote-questions.test.js"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@otto-build/contracts": "^1.0.
|
|
38
|
-
"@otto-build/rpc-client": "^1.0.
|
|
37
|
+
"@otto-build/contracts": "^1.0.8",
|
|
38
|
+
"@otto-build/rpc-client": "^1.0.8",
|
|
39
39
|
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
40
40
|
"zod": "^4.0.0"
|
|
41
41
|
},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@otto/pi-coding-agent",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"description": "Coding agent CLI (vendored from pi-mono)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"otto": {
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"copy-assets": "node scripts/copy-assets.cjs"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@otto-build/contracts": "^1.0.
|
|
31
|
+
"@otto-build/contracts": "^1.0.8",
|
|
32
32
|
"@mariozechner/jiti": "^2.6.2",
|
|
33
33
|
"@silvia-odwyer/photon-node": "^0.3.4",
|
|
34
34
|
"chalk": "^5.5.0",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@otto-build/rpc-client",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"description": "Standalone RPC client SDK for OTTO — zero internal dependencies",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"otto": {
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"test": "node --test dist/rpc-client.test.js"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@otto-build/contracts": "^1.0.
|
|
37
|
+
"@otto-build/contracts": "^1.0.8"
|
|
38
38
|
},
|
|
39
39
|
"engines": {
|
|
40
40
|
"node": ">=22.0.0"
|
package/pkg/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@loop24/client",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"piConfig": {
|
|
5
5
|
"_comment": "AUTO-SYNCED from root package.json by scripts/sync-piconfig.mjs (runs on prebuild). Do not edit this block directly — edit root package.json and re-run `npm run build` or `npm run sync-piconfig`.",
|
|
6
6
|
"name": "otto",
|
package/scripts/install.js
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
import { execSync, spawnSync, exec as execCb } from 'child_process'
|
|
16
16
|
import { createHash, randomUUID } from 'crypto'
|
|
17
17
|
import { chmodSync, copyFileSync, createWriteStream, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from 'fs'
|
|
18
|
+
import { createRequire } from 'module'
|
|
18
19
|
import { arch, homedir, platform } from 'os'
|
|
19
20
|
import { dirname, resolve, join } from 'path'
|
|
20
21
|
import { Readable } from 'stream'
|
|
@@ -486,6 +487,60 @@ function linkWorkspacePackages() {
|
|
|
486
487
|
} catch { /* non-fatal */ }
|
|
487
488
|
}
|
|
488
489
|
|
|
490
|
+
// ── Step: Copy bundled tools (ripgrep, fd) into ~/.otto/bin/ ───────────────
|
|
491
|
+
|
|
492
|
+
function copyBundledTools() {
|
|
493
|
+
// The @cmetech/otto-engine-* package matching this platform contains rg/fd
|
|
494
|
+
// alongside otto_engine.node. Copy them into ~/.otto/bin/ so the runtime
|
|
495
|
+
// tools-manager finds them at the expected location with no GitHub download.
|
|
496
|
+
const platMap = {
|
|
497
|
+
'darwin-arm64': 'darwin-arm64',
|
|
498
|
+
'darwin-x64': 'darwin-x64',
|
|
499
|
+
'linux-x64': 'linux-x64-gnu',
|
|
500
|
+
'linux-arm64': 'linux-arm64-gnu',
|
|
501
|
+
'win32-x64': 'win32-x64-msvc',
|
|
502
|
+
}
|
|
503
|
+
const key = `${platform()}-${arch()}`
|
|
504
|
+
const suffix = platMap[key]
|
|
505
|
+
if (!suffix) return // unsupported platform — nothing to bundle
|
|
506
|
+
|
|
507
|
+
const nativePkgName = `@cmetech/otto-engine-${suffix}`
|
|
508
|
+
let nativePkgDir
|
|
509
|
+
try {
|
|
510
|
+
const req = createRequire(import.meta.url)
|
|
511
|
+
const pkgJsonPath = req.resolve(`${nativePkgName}/package.json`, { paths: [packageRoot] })
|
|
512
|
+
nativePkgDir = dirname(pkgJsonPath)
|
|
513
|
+
} catch {
|
|
514
|
+
// Native package not installed — optionalDep didn't match (unsupported platform)
|
|
515
|
+
return
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
const binExt = platform() === 'win32' ? '.exe' : ''
|
|
519
|
+
// Must match getBinDir() in packages/pi-coding-agent/src/config.ts:
|
|
520
|
+
// join(getAgentDir(), 'bin') where getAgentDir() is ~/.otto/agent/.
|
|
521
|
+
// If config.ts ever moves the agent dir, update both spots together.
|
|
522
|
+
const dest = join(homedir(), '.otto', 'agent', 'bin')
|
|
523
|
+
mkdirSync(dest, { recursive: true })
|
|
524
|
+
|
|
525
|
+
const tools = ['rg', 'fd']
|
|
526
|
+
const copied = []
|
|
527
|
+
for (const tool of tools) {
|
|
528
|
+
const src = join(nativePkgDir, `${tool}${binExt}`)
|
|
529
|
+
const dst = join(dest, `${tool}${binExt}`)
|
|
530
|
+
if (existsSync(src)) {
|
|
531
|
+
copyFileSync(src, dst)
|
|
532
|
+
if (platform() !== 'win32') {
|
|
533
|
+
chmodSync(dst, 0o755)
|
|
534
|
+
}
|
|
535
|
+
copied.push(tool)
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
if (copied.length > 0) {
|
|
540
|
+
printStep('Bundled tools', `${copied.join(' + ')} copied to ~/.otto/agent/bin/`)
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
|
|
489
544
|
// ── Step: Verify installation ──────────────────────────────────────────────
|
|
490
545
|
|
|
491
546
|
function verifyInstall(local) {
|
|
@@ -536,6 +591,7 @@ const isLocal = args.includes('--local') || args.includes('-l')
|
|
|
536
591
|
if (IS_POSTINSTALL) {
|
|
537
592
|
// Running as npm postinstall hook — just do workspace linking + deps
|
|
538
593
|
linkWorkspacePackages()
|
|
594
|
+
copyBundledTools()
|
|
539
595
|
await installChromium()
|
|
540
596
|
await installRtk()
|
|
541
597
|
} else {
|
|
@@ -550,6 +606,7 @@ if (IS_POSTINSTALL) {
|
|
|
550
606
|
|
|
551
607
|
// Run postinstall steps that npm skipped
|
|
552
608
|
linkWorkspacePackages()
|
|
609
|
+
copyBundledTools()
|
|
553
610
|
await installChromium()
|
|
554
611
|
await installRtk()
|
|
555
612
|
|