clawport-ui 0.1.0 → 0.2.0

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/BRANDING.md CHANGED
@@ -42,8 +42,8 @@ TypeScript interfaces, function names, component names, and variable names. Thes
42
42
  | `setPortalSubtitle` (setter) | Same as `setPortalName` | |
43
43
  | `setPortalEmoji` (setter) | Same as `setPortalName` | |
44
44
  | `setPortalIcon` (setter) | Same as `setPortalName` | |
45
- | `OrgMap` (component) | `components/ManorMap.tsx`, `app/page.tsx`, `docs/COMPONENTS.md` | React Flow org chart component. |
46
- | `OrgMapProps` (interface) | `components/ManorMap.tsx` | Props type for OrgMap. |
45
+ | `OrgMap` (component) | `components/OrgMap.tsx`, `app/page.tsx`, `docs/COMPONENTS.md` | React Flow org chart component. |
46
+ | `OrgMapProps` (interface) | `components/OrgMap.tsx` | Props type for OrgMap. |
47
47
  | `HomePage` (component) | `app/page.tsx` | Home page component. |
48
48
  | `handleIconUpload` (function) | `app/settings/page.tsx` | Icon upload handler. |
49
49
  | `iconInputRef` (ref) | `app/settings/page.tsx` | File input ref. |
@@ -77,8 +77,9 @@ Changing these breaks existing users' saved data. Requires a migration function
77
77
 
78
78
  | Location | Current Value |
79
79
  |----------|---------------|
80
- | `package.json` `name` | `clawport` |
81
- | `package-lock.json` `name` | `clawport` |
80
+ | `package.json` `name` | `clawport-ui` |
81
+ | `package-lock.json` `name` | `clawport-ui` |
82
+ | npm package | [`clawport-ui`](https://www.npmjs.com/package/clawport-ui) |
82
83
  | Git clone URLs in docs | `https://github.com/openclaw/clawport.git` |
83
84
 
84
85
  ## 7. Workspace Paths
package/CLAUDE.md CHANGED
@@ -10,6 +10,19 @@ npx tsc --noEmit # Type-check (expect 0 errors)
10
10
  npx next build # Production build
11
11
  ```
12
12
 
13
+ ### CLI (global install)
14
+
15
+ ```bash
16
+ npm install -g clawport-ui
17
+ clawport setup # Auto-detect config, write .env.local into package dir
18
+ clawport dev # Start dev server
19
+ clawport start # Build + start production server
20
+ clawport status # Check gateway reachability + env config
21
+ clawport help # Show usage
22
+ ```
23
+
24
+ The CLI resolves its own package root via `import.meta.url`, so all commands work regardless of the user's current working directory. Entry point: `bin/clawport.mjs`.
25
+
13
26
  ## Project Overview
14
27
 
15
28
  ClawPort is a Next.js 16 dashboard for managing OpenClaw AI agents. It provides an org chart (Org Map), direct agent chat with multimodal support, cron monitoring, and memory browsing. All AI calls route through the OpenClaw gateway -- no separate API keys needed.
@@ -187,11 +200,12 @@ Used by: `lib/memory.ts`, `lib/cron-runs.ts`, `lib/kanban/chat-store.ts`, `lib/c
187
200
  | `AgentAvatar.tsx` | Agent emoji/image avatar with optional background |
188
201
  | `DynamicFavicon.tsx` | Updates favicon based on portal emoji/icon settings |
189
202
 
190
- ### Scripts
203
+ ### Scripts & CLI
191
204
 
192
205
  | File | Purpose |
193
206
  |------|---------|
194
- | `scripts/setup.mjs` | `npm run setup` -- auto-detects WORKSPACE_PATH, OPENCLAW_BIN, gateway token; writes `.env.local` |
207
+ | `bin/clawport.mjs` | CLI entry point -- `clawport dev`, `clawport setup`, `clawport status`, etc. Resolves package root via `import.meta.url` |
208
+ | `scripts/setup.mjs` | `npm run setup` / `clawport setup` -- auto-detects WORKSPACE_PATH, OPENCLAW_BIN, gateway token; writes `.env.local`. Accepts `--cwd=<path>` flag for CLI usage |
195
209
 
196
210
  ## Testing
197
211
 
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 John Rice
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -14,14 +14,24 @@ ClawPort is an open-source dashboard for managing, monitoring, and talking direc
14
14
  - [OpenClaw](https://openclaw.ai) installed and running
15
15
  - OpenClaw gateway started (`openclaw gateway run`)
16
16
 
17
- ### Quick Start
17
+ ### Quick Start (npm)
18
18
 
19
19
  ```bash
20
- # Clone the repo
21
- git clone https://github.com/openclaw/clawport.git
22
- cd clawport
20
+ # Install globally
21
+ npm install -g clawport-ui
23
22
 
24
- # Install dependencies
23
+ # Auto-detect your OpenClaw config
24
+ clawport setup
25
+
26
+ # Start the dev server
27
+ clawport dev
28
+ ```
29
+
30
+ ### Quick Start (from source)
31
+
32
+ ```bash
33
+ git clone https://github.com/JohnRiceML/clawport-ui.git
34
+ cd clawport-ui
25
35
  npm install
26
36
 
27
37
  # Auto-detect your OpenClaw config and write .env.local
@@ -257,6 +267,27 @@ npx next build # Production build
257
267
 
258
268
  ---
259
269
 
270
+ ## npm
271
+
272
+ ```bash
273
+ npm install -g clawport-ui
274
+ clawport help
275
+ ```
276
+
277
+ Published as [`clawport-ui`](https://www.npmjs.com/package/clawport-ui) on npm.
278
+
279
+ ### CLI Commands
280
+
281
+ | Command | Description |
282
+ |---------|-------------|
283
+ | `clawport dev` | Start the development server |
284
+ | `clawport start` | Build and start the production server |
285
+ | `clawport setup` | Auto-detect OpenClaw config and write `.env.local` |
286
+ | `clawport status` | Check gateway reachability and current config |
287
+ | `clawport help` | Show usage |
288
+
289
+ ---
290
+
260
291
  ## License
261
292
 
262
293
  MIT
package/SETUP.md CHANGED
@@ -15,8 +15,12 @@ This guide walks you through getting ClawPort running against your own OpenClaw
15
15
  ## 1. Install ClawPort
16
16
 
17
17
  ```bash
18
- git clone https://github.com/openclaw/clawport.git
19
- cd clawport
18
+ # Install globally from npm
19
+ npm install -g clawport-ui
20
+
21
+ # Or clone the repo
22
+ git clone https://github.com/JohnRiceML/clawport-ui.git
23
+ cd clawport-ui
20
24
  npm install
21
25
  ```
22
26
 
@@ -27,6 +31,10 @@ npm install
27
31
  The fastest way is the auto-setup script:
28
32
 
29
33
  ```bash
34
+ # If installed globally via npm
35
+ clawport setup
36
+
37
+ # Or if running from source
30
38
  npm run setup
31
39
  ```
32
40
 
@@ -119,6 +127,10 @@ Leave this running while you use ClawPort. If the gateway isn't running, chat an
119
127
  ## 4. Run ClawPort
120
128
 
121
129
  ```bash
130
+ # If installed globally via npm
131
+ clawport dev
132
+
133
+ # Or if running from source
122
134
  npm run dev
123
135
  ```
124
136
 
@@ -246,6 +258,10 @@ Your `agents.json` should be an array of agent objects. Here's the minimal requi
246
258
  ## 6. Production Build
247
259
 
248
260
  ```bash
261
+ # If installed globally via npm
262
+ clawport start
263
+
264
+ # Or if running from source
249
265
  npx next build
250
266
  npm start
251
267
  ```
package/app/docs/page.tsx CHANGED
@@ -9,6 +9,7 @@ import { CronSystemSection } from "@/components/docs/CronSystemSection";
9
9
  import { ThemingSection } from "@/components/docs/ThemingSection";
10
10
  import { ComponentsSection } from "@/components/docs/ComponentsSection";
11
11
  import { TroubleshootingSection } from "@/components/docs/TroubleshootingSection";
12
+ import { BestPracticesSection } from "@/components/docs/BestPracticesSection";
12
13
 
13
14
  /* ─── Section Definitions ──────────────────────────────────────── */
14
15
 
@@ -42,6 +43,13 @@ const SECTIONS: DocSectionDef[] = [
42
43
  description: "Registry, hierarchy, customization",
43
44
  component: AgentsSection,
44
45
  },
46
+ {
47
+ id: "best-practices",
48
+ label: "Best Practices",
49
+ emoji: "\u{1F3AF}",
50
+ description: "Hierarchy, memory, tools, naming",
51
+ component: BestPracticesSection,
52
+ },
45
53
  {
46
54
  id: "api-reference",
47
55
  label: "API Reference",
package/app/page.tsx CHANGED
@@ -12,7 +12,7 @@ import { GridView } from "@/components/GridView"
12
12
  import { FeedView } from "@/components/FeedView"
13
13
 
14
14
  const OrgMap = dynamic(
15
- () => import("@/components/ManorMap").then((m) => ({ default: m.OrgMap })),
15
+ () => import("@/components/OrgMap").then((m) => ({ default: m.OrgMap })),
16
16
  {
17
17
  ssr: false,
18
18
  loading: () => (
@@ -0,0 +1,149 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { fileURLToPath } from 'node:url'
4
+ import { dirname, resolve } from 'node:path'
5
+ import { spawn } from 'node:child_process'
6
+ import { existsSync, readFileSync } from 'node:fs'
7
+ import { execSync } from 'node:child_process'
8
+
9
+ // ---------------------------------------------------------------------------
10
+ // Resolve package root (where app/, lib/, etc. live)
11
+ // ---------------------------------------------------------------------------
12
+
13
+ const __filename = fileURLToPath(import.meta.url)
14
+ const PKG_ROOT = resolve(dirname(__filename), '..')
15
+
16
+ // ---------------------------------------------------------------------------
17
+ // Helpers
18
+ // ---------------------------------------------------------------------------
19
+
20
+ const green = (s) => `\x1b[32m${s}\x1b[0m`
21
+ const yellow = (s) => `\x1b[33m${s}\x1b[0m`
22
+ const red = (s) => `\x1b[31m${s}\x1b[0m`
23
+ const dim = (s) => `\x1b[2m${s}\x1b[0m`
24
+ const bold = (s) => `\x1b[1m${s}\x1b[0m`
25
+
26
+ function run(cmd, args = []) {
27
+ const child = spawn(cmd, args, {
28
+ cwd: PKG_ROOT,
29
+ stdio: 'inherit',
30
+ shell: true,
31
+ })
32
+ child.on('close', (code) => process.exit(code ?? 0))
33
+ }
34
+
35
+ // ---------------------------------------------------------------------------
36
+ // Commands
37
+ // ---------------------------------------------------------------------------
38
+
39
+ function showHelp() {
40
+ console.log(`
41
+ ${bold('ClawPort')} -- AI Agent Dashboard
42
+
43
+ ${bold('Usage:')} clawport <command>
44
+
45
+ ${bold('Commands:')}
46
+ ${green('dev')} Start the development server (next dev)
47
+ ${green('start')} Build and start the production server
48
+ ${green('setup')} Run the setup wizard (auto-detect OpenClaw config)
49
+ ${green('status')} Check gateway reachability and current config
50
+ ${green('help')} Show this help message
51
+
52
+ ${bold('Examples:')}
53
+ ${dim('$ clawport setup # Configure your OpenClaw connection')}
54
+ ${dim('$ clawport dev # Start dev server on localhost:3000')}
55
+ ${dim('$ clawport status # Check if gateway is reachable')}
56
+
57
+ ${dim(`Package root: ${PKG_ROOT}`)}
58
+ `)
59
+ }
60
+
61
+ function cmdDev() {
62
+ console.log(`\n ${bold('Starting ClawPort dev server...')}\n`)
63
+ run('npx', ['next', 'dev'])
64
+ }
65
+
66
+ function cmdStart() {
67
+ console.log(`\n ${bold('Building and starting ClawPort...')}\n`)
68
+ run('npx', ['next', 'build', '&&', 'npx', 'next', 'start'])
69
+ }
70
+
71
+ function cmdSetup() {
72
+ console.log()
73
+ run('node', [resolve(PKG_ROOT, 'scripts/setup.mjs'), `--cwd=${PKG_ROOT}`])
74
+ }
75
+
76
+ function cmdStatus() {
77
+ console.log()
78
+ console.log(bold(' ClawPort Status'))
79
+ console.log()
80
+
81
+ // Check gateway
82
+ let gatewayUp = false
83
+ try {
84
+ const result = execSync(
85
+ 'curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:18789/ 2>/dev/null',
86
+ { encoding: 'utf-8', timeout: 5000 }
87
+ ).trim()
88
+ gatewayUp = result && result !== '000'
89
+ } catch {
90
+ // gateway not reachable
91
+ }
92
+
93
+ if (gatewayUp) {
94
+ console.log(` ${green('+')} Gateway reachable at ${dim('localhost:18789')}`)
95
+ } else {
96
+ console.log(` ${red('x')} Gateway not responding at ${dim('localhost:18789')}`)
97
+ console.log(` ${dim('Start it with: openclaw gateway run')}`)
98
+ }
99
+
100
+ // Check .env.local
101
+ const envPath = resolve(PKG_ROOT, '.env.local')
102
+ console.log()
103
+ if (existsSync(envPath)) {
104
+ console.log(` ${green('+')} .env.local found`)
105
+ const content = readFileSync(envPath, 'utf-8')
106
+ const lines = content.split('\n').filter((l) => l && !l.startsWith('#'))
107
+ for (const line of lines) {
108
+ const [key, ...rest] = line.split('=')
109
+ const value = rest.join('=')
110
+ if (key === 'OPENCLAW_GATEWAY_TOKEN' && value) {
111
+ console.log(` ${dim(key)}=${dim(value.slice(0, 8) + '...' + value.slice(-4))}`)
112
+ } else if (key && value) {
113
+ console.log(` ${dim(key)}=${dim(value)}`)
114
+ }
115
+ }
116
+ } else {
117
+ console.log(` ${yellow('!')} No .env.local found`)
118
+ console.log(` ${dim('Run: clawport setup')}`)
119
+ }
120
+
121
+ console.log()
122
+ console.log(` ${dim(`Package root: ${PKG_ROOT}`)}`)
123
+ console.log()
124
+ }
125
+
126
+ // ---------------------------------------------------------------------------
127
+ // Main
128
+ // ---------------------------------------------------------------------------
129
+
130
+ const command = process.argv[2]
131
+
132
+ switch (command) {
133
+ case 'dev':
134
+ cmdDev()
135
+ break
136
+ case 'start':
137
+ cmdStart()
138
+ break
139
+ case 'setup':
140
+ cmdSetup()
141
+ break
142
+ case 'status':
143
+ cmdStatus()
144
+ break
145
+ case 'help':
146
+ default:
147
+ showHelp()
148
+ break
149
+ }
@@ -0,0 +1,612 @@
1
+ import {
2
+ Heading,
3
+ SubHeading,
4
+ Paragraph,
5
+ CodeBlock,
6
+ InlineCode,
7
+ Table,
8
+ BulletList,
9
+ NumberedList,
10
+ Callout,
11
+ InfoCard,
12
+ } from "./DocSection";
13
+
14
+ export function BestPracticesSection() {
15
+ return (
16
+ <>
17
+ <Heading>Best Practices</Heading>
18
+ <Paragraph>
19
+ This guide covers the patterns and conventions behind a production agent
20
+ team. Every example uses real agents from the bundled registry so you can
21
+ see exactly how hierarchy, memory, tools, and crons come together.
22
+ </Paragraph>
23
+
24
+ {/* ─── Hierarchy ──────────────────────────────────────── */}
25
+
26
+ <SubHeading>Hierarchy Design</SubHeading>
27
+ <Paragraph>
28
+ A well-structured agent team follows a clear chain of command. The
29
+ pattern is: one orchestrator at the top, team leads in the middle, and
30
+ specialist leaf agents at the bottom. Each level has a distinct
31
+ responsibility.
32
+ </Paragraph>
33
+
34
+ <InfoCard title="The Three Tiers">
35
+ <Table
36
+ headers={["Tier", "Role", "Example"]}
37
+ rows={[
38
+ [
39
+ "Orchestrator",
40
+ "Top-level coordinator. Holds team memory, routes work, delivers briefings.",
41
+ <><strong key="j">Jarvis</strong> -- the root node. reportsTo: null.</>,
42
+ ],
43
+ [
44
+ "Team Lead",
45
+ "Owns a domain. Manages a sub-team and runs pipelines end-to-end.",
46
+ <>
47
+ <strong key="v">VERA</strong> (Strategy),{" "}
48
+ <strong key="l">LUMEN</strong> (SEO),{" "}
49
+ <strong key="h">HERALD</strong> (LinkedIn)
50
+ </>,
51
+ ],
52
+ [
53
+ "Specialist",
54
+ "Does one thing well. Reports up, never manages others.",
55
+ <>
56
+ <strong key="t">TRACE</strong> (Market Research),{" "}
57
+ <strong key="q">QUILL</strong> (LinkedIn Writer),{" "}
58
+ <strong key="s">SCOUT</strong> (Content Scout)
59
+ </>,
60
+ ],
61
+ ]}
62
+ />
63
+ </InfoCard>
64
+
65
+ <Paragraph>
66
+ The bundled registry ships 22 agents organized into five teams:
67
+ </Paragraph>
68
+
69
+ <CodeBlock title="Team Structure">
70
+ {`Jarvis (Orchestrator)
71
+ |
72
+ +-- VERA (Strategy)
73
+ | +-- Robin (Field Intel)
74
+ | +-- TRACE (Market Research)
75
+ | +-- PROOF (Validation Design)
76
+ |
77
+ +-- LUMEN (SEO)
78
+ | +-- SCOUT (Content Scout)
79
+ | +-- ANALYST (SEO Analyst)
80
+ | +-- STRATEGIST (Content Strategy)
81
+ | +-- WRITER (Content Writer)
82
+ | +-- AUDITOR (Quality Gate)
83
+ |
84
+ +-- HERALD (LinkedIn)
85
+ | +-- QUILL (LinkedIn Writer)
86
+ | +-- MAVEN (LinkedIn Strategist)
87
+ |
88
+ +-- Pulse (Trend Radar) -- standalone
89
+ +-- ECHO (Community Voice) -- standalone
90
+ +-- SAGE (ICP Expert) -- standalone
91
+ +-- KAZE (Flight Monitor) -- standalone
92
+ +-- SPARK (Tech Discovery) -- standalone
93
+ +-- SCRIBE (Memory Architect)-- standalone`}
94
+ </CodeBlock>
95
+
96
+ <Callout type="tip">
97
+ Standalone agents (no direct reports) report directly to the
98
+ orchestrator. Keep this list short -- if you have more than 8-10 direct
99
+ reports on the root node, it's time to group them under a team lead.
100
+ </Callout>
101
+
102
+ <SubHeading>Hierarchy Rules</SubHeading>
103
+ <NumberedList
104
+ items={[
105
+ <>
106
+ <strong>One root.</strong> Exactly one agent has{" "}
107
+ <InlineCode>{"\"reportsTo\": null"}</InlineCode>. This is your
108
+ orchestrator (Jarvis).
109
+ </>,
110
+ <>
111
+ <strong>Team leads own pipelines.</strong> LUMEN owns the full SEO
112
+ pipeline (SCOUT to AUDITOR). HERALD owns the LinkedIn pipeline
113
+ (QUILL + MAVEN). Each lead is responsible for end-to-end delivery.
114
+ </>,
115
+ <>
116
+ <strong>Leaf agents are specialists.</strong> They do one thing and
117
+ report up. TRACE does market research. QUILL writes posts. AUDITOR
118
+ runs the quality gate. No scope creep.
119
+ </>,
120
+ <>
121
+ <strong>Max depth of 3.</strong> Jarvis to Robin to TRACE is
122
+ three levels. Going deeper adds latency and coordination overhead
123
+ with little benefit.
124
+ </>,
125
+ <>
126
+ <strong>Keep directReports consistent.</strong> If agent B has{" "}
127
+ <InlineCode>{"\"reportsTo\": \"A\""}</InlineCode>, then agent A's
128
+ directReports array must include B's id. The Org Map renders from
129
+ these relationships.
130
+ </>,
131
+ ]}
132
+ />
133
+
134
+ {/* ─── SOUL.md ────────────────────────────────────────── */}
135
+
136
+ <SubHeading>SOUL.md -- Agent Character Documents</SubHeading>
137
+ <Paragraph>
138
+ Every agent has a SOUL.md file that defines its personality, expertise,
139
+ and operating constraints. This is not a system prompt -- it's a
140
+ character document. The agent reads it to understand who it is.
141
+ </Paragraph>
142
+
143
+ <CodeBlock title="Recommended SOUL.md Structure">
144
+ {`# AGENT_NAME -- Role Title
145
+
146
+ ## Identity
147
+ Who the agent is. Personality traits. Communication style.
148
+ First-person voice: "I am VERA, the Chief Strategy Officer."
149
+
150
+ ## Expertise
151
+ What domains this agent knows deeply.
152
+ What it should be consulted on vs. what it defers.
153
+
154
+ ## Operating Rules
155
+ Hard constraints. What it must always/never do.
156
+ Output format requirements.
157
+
158
+ ## Relationships
159
+ Who it reports to. Who reports to it.
160
+ How it collaborates with peer agents.
161
+
162
+ ## Memory
163
+ What it remembers between sessions.
164
+ Where its persistent knowledge lives.`}
165
+ </CodeBlock>
166
+
167
+ <BulletList
168
+ items={[
169
+ <>
170
+ <strong>Be specific about personality.</strong> HERALD is described
171
+ as brash and direct. SAGE is contemplative and precise. Distinct
172
+ voices prevent all agents from sounding the same.
173
+ </>,
174
+ <>
175
+ <strong>Define what the agent does NOT do.</strong> SCRIBE (Memory
176
+ Architect) is a "silent worker" -- it never initiates conversation.
177
+ SAGE (ICP Expert) is read-only -- it never writes to external
178
+ systems.
179
+ </>,
180
+ <>
181
+ <strong>Include output format examples.</strong> If the agent
182
+ produces Market Briefs, show the exact format. TRACE returns
183
+ structured TAM/competitor/pricing data, not prose.
184
+ </>,
185
+ <>
186
+ <strong>Keep it under 500 lines.</strong> Long SOUL files dilute
187
+ the agent's focus. If you need more detail, link to reference docs.
188
+ </>,
189
+ ]}
190
+ />
191
+
192
+ <Callout type="note">
193
+ SOUL.md files live in your OpenClaw workspace at the path defined by
194
+ each agent's <InlineCode>soulPath</InlineCode> field. ClawPort reads
195
+ and displays them on the agent detail page.
196
+ </Callout>
197
+
198
+ {/* ─── Naming ─────────────────────────────────────────── */}
199
+
200
+ <SubHeading>Naming Conventions</SubHeading>
201
+ <Paragraph>
202
+ Agent naming follows a simple pattern that signals the agent's scope
203
+ at a glance:
204
+ </Paragraph>
205
+
206
+ <Table
207
+ headers={["Pattern", "When to Use", "Examples"]}
208
+ rows={[
209
+ [
210
+ "UPPERCASE",
211
+ "Agents that are part of a pipeline or team. Feels like a callsign.",
212
+ "VERA, LUMEN, HERALD, SCOUT, QUILL, ECHO, SAGE",
213
+ ],
214
+ [
215
+ "Title Case",
216
+ "Standalone agents with more personality. The orchestrator or personal-feeling agents.",
217
+ "Jarvis, Robin, Pulse",
218
+ ],
219
+ ]}
220
+ />
221
+
222
+ <Paragraph>
223
+ Ids are always lowercase slugs:{" "}
224
+ <InlineCode>vera</InlineCode>,{" "}
225
+ <InlineCode>lumen</InlineCode>,{" "}
226
+ <InlineCode>herald</InlineCode>. The display name in the{" "}
227
+ <InlineCode>name</InlineCode> field is what users see in the UI.
228
+ </Paragraph>
229
+
230
+ {/* ─── Tools ──────────────────────────────────────────── */}
231
+
232
+ <SubHeading>Tool Assignment</SubHeading>
233
+ <Paragraph>
234
+ Follow the principle of least privilege. Each agent gets only the tools
235
+ it needs for its job -- nothing more.
236
+ </Paragraph>
237
+
238
+ <Table
239
+ headers={["Tool", "Purpose", "Who Gets It"]}
240
+ rows={[
241
+ [
242
+ <InlineCode key="r">read</InlineCode>,
243
+ "Read files from workspace",
244
+ "Almost everyone. The base capability.",
245
+ ],
246
+ [
247
+ <InlineCode key="w">write</InlineCode>,
248
+ "Write/create files",
249
+ "Agents that produce artifacts (WRITER, ANALYST, STRATEGIST)",
250
+ ],
251
+ [
252
+ <InlineCode key="e">exec</InlineCode>,
253
+ "Run shell commands",
254
+ "Orchestrator + leads who run pipelines (Jarvis, LUMEN, HERALD)",
255
+ ],
256
+ [
257
+ <InlineCode key="ws">web_search</InlineCode>,
258
+ "Search the web",
259
+ "Research agents (TRACE, Robin, SCOUT, Pulse, SPARK)",
260
+ ],
261
+ [
262
+ <InlineCode key="wf">web_fetch</InlineCode>,
263
+ "Fetch a specific URL",
264
+ "Agents that scrape or monitor (ECHO, KAZE, Robin)",
265
+ ],
266
+ [
267
+ <InlineCode key="m">message</InlineCode>,
268
+ "Send messages to other agents",
269
+ "Agents that coordinate (Jarvis, Robin, Pulse, HERALD)",
270
+ ],
271
+ [
272
+ <InlineCode key="ss">sessions_spawn</InlineCode>,
273
+ "Spawn sub-agent sessions",
274
+ "Only orchestrator + team leads (Jarvis, VERA)",
275
+ ],
276
+ [
277
+ <InlineCode key="ms">memory_search</InlineCode>,
278
+ "Search across team memory",
279
+ "Orchestrator only (Jarvis)",
280
+ ],
281
+ [
282
+ <InlineCode key="tt">tts</InlineCode>,
283
+ "Text-to-speech",
284
+ "Orchestrator only (Jarvis)",
285
+ ],
286
+ ]}
287
+ />
288
+
289
+ <Callout type="warning">
290
+ Giving <InlineCode>exec</InlineCode> to a leaf agent is almost always
291
+ a mistake. If a specialist needs to run a command, it should ask its
292
+ team lead to do it. This keeps the blast radius small.
293
+ </Callout>
294
+
295
+ <InfoCard title="Tool Assignment Examples">
296
+ <CodeBlock>
297
+ {`// SAGE -- read-only knowledge agent
298
+ "tools": ["read"]
299
+
300
+ // SCOUT -- web researcher
301
+ "tools": ["web_search", "web_fetch", "read"]
302
+
303
+ // WRITER -- content producer
304
+ "tools": ["read", "write"]
305
+
306
+ // HERALD -- team lead running a pipeline
307
+ "tools": ["web_search", "web_fetch", "read", "write", "message", "exec"]
308
+
309
+ // Jarvis -- orchestrator with full access
310
+ "tools": ["exec", "read", "write", "edit", "web_search", "tts", "message", "sessions_spawn", "memory_search"]`}
311
+ </CodeBlock>
312
+ </InfoCard>
313
+
314
+ {/* ─── Memory ─────────────────────────────────────────── */}
315
+
316
+ <SubHeading>Memory Architecture</SubHeading>
317
+ <Paragraph>
318
+ Agent memory uses a three-tier system. Each tier serves a different
319
+ purpose, and together they give agents both short-term recall and
320
+ long-term knowledge.
321
+ </Paragraph>
322
+
323
+ <InfoCard title="The Three Memory Tiers">
324
+ <Table
325
+ headers={["Tier", "What", "Lifespan", "Who Manages"]}
326
+ rows={[
327
+ [
328
+ "1. Daily Logs",
329
+ "Raw output from each agent session. Unedited, timestamped.",
330
+ "7-14 days (then compressed or archived)",
331
+ "Each agent writes its own",
332
+ ],
333
+ [
334
+ "2. MEMORY.md",
335
+ "Curated, compressed knowledge. The agent's persistent brain.",
336
+ "Indefinite (updated weekly)",
337
+ <>
338
+ <strong>SCRIBE</strong> runs weekly compression
339
+ </>,
340
+ ],
341
+ [
342
+ "3. Team Memory",
343
+ "Shared knowledge across agents. Market data, ICP profiles, strategy docs.",
344
+ "Indefinite",
345
+ "Team leads + orchestrator",
346
+ ],
347
+ ]}
348
+ />
349
+ </InfoCard>
350
+
351
+ <SubHeading>Tier 1: Daily Logs</SubHeading>
352
+ <Paragraph>
353
+ Every time an agent runs, it writes a log file. These are the raw
354
+ session transcripts -- what the agent did, what it found, what it
355
+ produced. Daily logs are high-volume and low-curation.
356
+ </Paragraph>
357
+ <CodeBlock title="Daily log path pattern">
358
+ {`$WORKSPACE_PATH/agents/<agent-id>/logs/YYYY-MM-DD.md`}
359
+ </CodeBlock>
360
+
361
+ <SubHeading>Tier 2: MEMORY.md</SubHeading>
362
+ <Paragraph>
363
+ Each agent has a MEMORY.md file that persists its key knowledge between
364
+ sessions. Unlike daily logs (which are raw), MEMORY.md is curated --
365
+ only the important patterns, decisions, and facts survive.
366
+ </Paragraph>
367
+ <CodeBlock title="MEMORY.md structure">
368
+ {`# Agent Name -- Memory
369
+
370
+ ## Key Patterns
371
+ - Pattern 1 confirmed across 3+ sessions
372
+ - Pattern 2 from last week's research
373
+
374
+ ## Active Context
375
+ - Current project status
376
+ - Open questions / blockers
377
+
378
+ ## Learned Preferences
379
+ - User prefers X over Y
380
+ - Always include Z in output`}
381
+ </CodeBlock>
382
+ <Paragraph>
383
+ <strong>SCRIBE</strong> (Memory Architect) runs weekly to compress daily
384
+ logs into each agent's MEMORY.md. SCRIBE reads the raw logs, extracts
385
+ durable insights, and updates the memory file -- discarding
386
+ session-specific noise. This keeps MEMORY.md concise and high-signal.
387
+ </Paragraph>
388
+
389
+ <SubHeading>Tier 3: Team Memory (Shared)</SubHeading>
390
+ <Paragraph>
391
+ Some knowledge needs to be shared across agents. Market intelligence,
392
+ ICP profiles, competitive analysis, and brand voice docs all live in a
393
+ shared team-memory directory. Any agent with{" "}
394
+ <InlineCode>read</InlineCode> access to the workspace can reference
395
+ these files.
396
+ </Paragraph>
397
+ <CodeBlock title="Team memory path">
398
+ {`$WORKSPACE_PATH/team-memory/
399
+ market-brief.md -- TRACE's latest research
400
+ icp-profile.md -- SAGE's ICP knowledge
401
+ competitor-map.md -- Robin's competitive intel
402
+ brand-voice.md -- Voice profile for content agents
403
+ content-calendar.md -- MAVEN's editorial calendar`}
404
+ </CodeBlock>
405
+
406
+ <Callout type="tip">
407
+ Team memory files are the glue between agents. When STRATEGIST needs
408
+ market context, it reads TRACE's market brief. When WRITER needs brand
409
+ voice, it reads the voice profile. No agent-to-agent API calls needed
410
+ -- just shared files.
411
+ </Callout>
412
+
413
+ {/* ─── Communication ──────────────────────────────────── */}
414
+
415
+ <SubHeading>Agent Communication</SubHeading>
416
+ <Paragraph>
417
+ Agents communicate through files, not direct API calls. This is
418
+ intentional -- file-based communication is debuggable, auditable, and
419
+ doesn't create tight coupling.
420
+ </Paragraph>
421
+
422
+ <NumberedList
423
+ items={[
424
+ <>
425
+ <strong>Upstream (reporting up):</strong> An agent writes its output
426
+ to a file. The team lead or orchestrator reads it on the next run.
427
+ Example: SCOUT writes topic suggestions, LUMEN reads them to
428
+ brief STRATEGIST.
429
+ </>,
430
+ <>
431
+ <strong>Downstream (delegating):</strong> A team lead writes a
432
+ brief file that the specialist reads. Example: HERALD writes an
433
+ angle brief, QUILL reads it and drafts the post.
434
+ </>,
435
+ <>
436
+ <strong>Cross-team (shared context):</strong> Agents read from
437
+ team-memory. Example: STRATEGIST reads SAGE's ICP profile and
438
+ ECHO's community voice data to pick the right content angle.
439
+ </>,
440
+ ]}
441
+ />
442
+
443
+ <Callout type="note">
444
+ The <InlineCode>message</InlineCode> tool exists for real-time
445
+ coordination (e.g., Pulse alerting LUMEN about a trending topic), but
446
+ the default communication channel is always files. Messages are for
447
+ urgency; files are for substance.
448
+ </Callout>
449
+
450
+ {/* ─── Crons ──────────────────────────────────────────── */}
451
+
452
+ <SubHeading>Cron Patterns</SubHeading>
453
+ <Paragraph>
454
+ Cron jobs are the heartbeat of an autonomous agent team. Each cron
455
+ follows the same philosophy: one fetch, one decision, one output.
456
+ </Paragraph>
457
+
458
+ <BulletList
459
+ items={[
460
+ <>
461
+ <strong>Assign crons to the right tier.</strong> Research crons go
462
+ on leaf agents (SCOUT, TRACE, ECHO). Pipeline crons go on team
463
+ leads (LUMEN, HERALD). Briefing crons go on the orchestrator
464
+ (Jarvis).
465
+ </>,
466
+ <>
467
+ <strong>Stagger schedules.</strong> Don't run all crons at the same
468
+ time. Space them out so upstream agents finish before downstream
469
+ agents read their output.
470
+ </>,
471
+ <>
472
+ <strong>Keep crons focused.</strong> Each cron does one thing.
473
+ "Scan subreddits" is a good cron. "Scan subreddits, analyze
474
+ sentiment, write a blog post, and publish" is four crons pretending
475
+ to be one.
476
+ </>,
477
+ <>
478
+ <strong>Error isolation.</strong> If a cron fails, it should only
479
+ affect its own output. Other agents reading stale data is better
480
+ than a cascade failure.
481
+ </>,
482
+ ]}
483
+ />
484
+
485
+ <Table
486
+ headers={["Cron", "Agent", "Schedule", "Pattern"]}
487
+ rows={[
488
+ [
489
+ "Community scan",
490
+ <strong key="e">ECHO</strong>,
491
+ "Weekly",
492
+ "Fetch subreddit posts, extract customer language, write to team-memory",
493
+ ],
494
+ [
495
+ "Trend radar",
496
+ <strong key="p">Pulse</strong>,
497
+ "Every other day",
498
+ "Scan trending signals, write hot topics file, message LUMEN if urgent",
499
+ ],
500
+ [
501
+ "Flight monitor",
502
+ <strong key="k">KAZE</strong>,
503
+ "Daily",
504
+ "Check flight prices, message Jarvis if deal found under threshold",
505
+ ],
506
+ [
507
+ "Memory compression",
508
+ <strong key="s">SCRIBE</strong>,
509
+ "Weekly",
510
+ "Read daily logs, compress into MEMORY.md, archive old logs",
511
+ ],
512
+ [
513
+ "Content pipeline",
514
+ <strong key="l">LUMEN</strong>,
515
+ "Weekly",
516
+ "Orchestrate SCOUT -> ANALYST -> STRATEGIST -> WRITER -> AUDITOR",
517
+ ],
518
+ ]}
519
+ />
520
+
521
+ {/* ─── Voice ──────────────────────────────────────────── */}
522
+
523
+ <SubHeading>Voice System</SubHeading>
524
+ <Paragraph>
525
+ Agents that interact directly with the operator can have an ElevenLabs
526
+ voice ID assigned. This enables text-to-speech on their responses in
527
+ the chat interface. Not every agent needs a voice -- only those the
528
+ operator talks to regularly.
529
+ </Paragraph>
530
+
531
+ <BulletList
532
+ items={[
533
+ <>
534
+ <strong>Give voices to conversational agents.</strong> Jarvis
535
+ (orchestrator), VERA (strategy advisor), Pulse (trend alerts) --
536
+ agents you chat with benefit from voice.
537
+ </>,
538
+ <>
539
+ <strong>Skip voices for pipeline workers.</strong> SCOUT, ANALYST,
540
+ WRITER, AUDITOR run in pipelines and rarely need to speak. Don't
541
+ waste voice slots on them.
542
+ </>,
543
+ <>
544
+ Set <InlineCode>voiceId</InlineCode> to{" "}
545
+ <InlineCode>null</InlineCode> for agents without voice. The UI
546
+ hides the TTS button when voiceId is null.
547
+ </>,
548
+ ]}
549
+ />
550
+
551
+ {/* ─── Design Principles ──────────────────────────────── */}
552
+
553
+ <SubHeading>Design Principles</SubHeading>
554
+
555
+ <InfoCard title="1. Agents are characters, not functions">
556
+ <Paragraph>
557
+ Each agent has a name, a personality, and a role title. They're not
558
+ interchangeable worker threads -- they're team members with distinct
559
+ expertise. VERA thinks strategically. ECHO listens to communities.
560
+ KAZE watches flights. This makes the team legible and memorable.
561
+ </Paragraph>
562
+ </InfoCard>
563
+
564
+ <InfoCard title="2. Least privilege, always">
565
+ <Paragraph>
566
+ An agent should have exactly the tools it needs and nothing more. SAGE
567
+ is read-only because it's a knowledge base, not an actor. SCRIBE has{" "}
568
+ <InlineCode>exec</InlineCode> because it needs to run file operations
569
+ during memory compression. If you're unsure whether an agent needs a
570
+ tool, start without it. You can always add it later.
571
+ </Paragraph>
572
+ </InfoCard>
573
+
574
+ <InfoCard title="3. Files over messages">
575
+ <Paragraph>
576
+ Prefer file-based communication over real-time messages. Files are
577
+ inspectable, diffable, and persist across sessions. Messages are for
578
+ urgent signals only (e.g., Pulse alerting about a breaking trend).
579
+ Everything else goes through shared files in team-memory.
580
+ </Paragraph>
581
+ </InfoCard>
582
+
583
+ <InfoCard title="4. One agent, one job">
584
+ <Paragraph>
585
+ Resist the urge to make Swiss Army knife agents. TRACE does market
586
+ research -- it doesn't also write blog posts. QUILL writes LinkedIn
587
+ posts -- it doesn't also analyze metrics. When an agent's description
588
+ needs the word "and" more than once, split it into two agents.
589
+ </Paragraph>
590
+ </InfoCard>
591
+
592
+ <InfoCard title="5. Depth of 3, max">
593
+ <Paragraph>
594
+ Jarvis to Robin to TRACE is three levels. Going deeper adds latency
595
+ and makes the chain of command confusing. If you need more
596
+ specialization, add lateral agents (more direct reports) instead of
597
+ deeper nesting.
598
+ </Paragraph>
599
+ </InfoCard>
600
+
601
+ <InfoCard title="6. Let SCRIBE handle memory">
602
+ <Paragraph>
603
+ Don't make every agent manage its own memory compression. SCRIBE
604
+ exists specifically to read daily logs, extract patterns, and update
605
+ MEMORY.md files. This single responsibility keeps memory consistent
606
+ and prevents agents from spending cycles on housekeeping instead of
607
+ their actual job.
608
+ </Paragraph>
609
+ </InfoCard>
610
+ </>
611
+ );
612
+ }
@@ -41,7 +41,27 @@ export function GettingStartedSection() {
41
41
  ]}
42
42
  />
43
43
 
44
- <SubHeading>Quick Start</SubHeading>
44
+ <SubHeading>Quick Start (npm)</SubHeading>
45
+ <CodeBlock title="terminal">
46
+ {`# Install globally
47
+ npm install -g clawport-ui
48
+
49
+ # Run the setup wizard (auto-detects your OpenClaw config)
50
+ clawport setup
51
+
52
+ # Start the dev server
53
+ clawport dev`}
54
+ </CodeBlock>
55
+ <Callout type="warning">
56
+ If you get <InlineCode>EACCES: permission denied</InlineCode> or{" "}
57
+ <InlineCode>EEXIST</InlineCode> errors during install, your npm cache
58
+ has broken permissions (usually from a previous{" "}
59
+ <InlineCode>sudo npm install</InlineCode>). Fix it with:{" "}
60
+ <InlineCode>sudo chown -R $(whoami) ~/.npm</InlineCode> then retry.
61
+ See the Troubleshooting section for full details.
62
+ </Callout>
63
+
64
+ <SubHeading>Quick Start (from source)</SubHeading>
45
65
  <CodeBlock title="terminal">
46
66
  {`# Clone the repo
47
67
  git clone https://github.com/openclaw/clawport.git
@@ -17,6 +17,71 @@ export function TroubleshootingSection() {
17
17
  Common issues and their solutions when running ClawPort.
18
18
  </Paragraph>
19
19
 
20
+ {/* ── npm install permission errors ──────────────────────── */}
21
+ <SubHeading>
22
+ EACCES / permission denied during npm install -g
23
+ </SubHeading>
24
+ <Paragraph>
25
+ If you see errors like <InlineCode>EACCES: permission denied</InlineCode>,{" "}
26
+ <InlineCode>EEXIST</InlineCode>, or{" "}
27
+ <InlineCode>Invalid response body while trying to fetch</InlineCode> when
28
+ running <InlineCode>npm install -g clawport-ui</InlineCode>, your npm
29
+ cache directory has broken permissions. This usually happens if{" "}
30
+ <InlineCode>npm install -g</InlineCode> was previously run with{" "}
31
+ <InlineCode>sudo</InlineCode>.
32
+ </Paragraph>
33
+ <Paragraph>
34
+ Fix it in three steps:
35
+ </Paragraph>
36
+ <NumberedList
37
+ items={[
38
+ <>
39
+ <strong style={{ color: "var(--text-primary)" }}>
40
+ Fix cache permissions
41
+ </strong>
42
+ </>,
43
+ <>
44
+ <strong style={{ color: "var(--text-primary)" }}>
45
+ Fix global node_modules permissions
46
+ </strong>
47
+ </>,
48
+ <>
49
+ <strong style={{ color: "var(--text-primary)" }}>
50
+ Retry the install
51
+ </strong>
52
+ </>,
53
+ ]}
54
+ />
55
+ <CodeBlock title="terminal">
56
+ {`# 1. Fix npm cache ownership
57
+ sudo chown -R $(whoami) ~/.npm
58
+
59
+ # 2. Fix global node_modules ownership (find your prefix first)
60
+ npm prefix -g
61
+ # Then fix permissions on that path, e.g.:
62
+ sudo chown -R $(whoami) /usr/local/lib/node_modules
63
+ sudo chown -R $(whoami) /usr/local/bin
64
+
65
+ # 3. Retry without sudo
66
+ npm install -g clawport-ui`}
67
+ </CodeBlock>
68
+ <Paragraph>
69
+ If that still fails, clear the cache entirely and retry:
70
+ </Paragraph>
71
+ <CodeBlock title="terminal">
72
+ {`npm cache clean --force
73
+ npm install -g clawport-ui`}
74
+ </CodeBlock>
75
+ <Callout type="warning">
76
+ Never use <InlineCode>sudo npm install -g</InlineCode> -- it creates
77
+ root-owned files in your user's npm cache and global directories, which
78
+ causes permission errors on every future install. If your setup requires
79
+ sudo for global installs, consider using{" "}
80
+ <InlineCode>nvm</InlineCode> (Node Version Manager) instead, which
81
+ installs Node and global packages in your home directory with no
82
+ permission issues.
83
+ </Callout>
84
+
20
85
  {/* ── Issue 1 ────────────────────────────────────────────── */}
21
86
  <SubHeading>
22
87
  "Missing required environment variable: WORKSPACE_PATH"
package/lib/agents.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "reportsTo": null,
7
7
  "directReports": ["vera", "lumen", "herald", "pulse", "echo", "sage", "kaze", "spark", "scribe"],
8
8
  "soulPath": "SOUL.md",
9
- "voiceId": "agL69Vji082CshT65Tcy",
9
+ "voiceId": null,
10
10
  "color": "#f5c518",
11
11
  "emoji": "\ud83e\udd16",
12
12
  "tools": ["exec", "read", "write", "edit", "web_search", "tts", "message", "sessions_spawn", "memory_search"],
@@ -20,7 +20,7 @@
20
20
  "reportsTo": "jarvis",
21
21
  "directReports": ["robin"],
22
22
  "soulPath": "agents/vera/SOUL.md",
23
- "voiceId": "EAHourGM2PqzHHl0Ywjp",
23
+ "voiceId": null,
24
24
  "color": "#a855f7",
25
25
  "emoji": "\u265f\ufe0f",
26
26
  "tools": ["web_search", "web_fetch", "read", "write", "sessions_spawn"],
@@ -34,7 +34,7 @@
34
34
  "reportsTo": "vera",
35
35
  "directReports": ["trace", "proof"],
36
36
  "soulPath": "agents/robin/SOUL.md",
37
- "voiceId": "IRHApOXLvnW57QJPQH2P",
37
+ "voiceId": null,
38
38
  "color": "#3b82f6",
39
39
  "emoji": "\ud83e\udd85",
40
40
  "tools": ["web_search", "web_fetch", "read", "write", "message"],
@@ -76,7 +76,7 @@
76
76
  "reportsTo": "jarvis",
77
77
  "directReports": ["scout", "analyst", "strategist", "writer", "auditor"],
78
78
  "soulPath": "agents/seo-team/SOUL.md",
79
- "voiceId": "EVy5l1wEi54nXdQwAJJf",
79
+ "voiceId": null,
80
80
  "color": "#22c55e",
81
81
  "emoji": "\ud83d\udd26",
82
82
  "tools": ["web_search", "web_fetch", "read", "write", "exec"],
@@ -202,7 +202,7 @@
202
202
  "reportsTo": "jarvis",
203
203
  "directReports": [],
204
204
  "soulPath": "agents/pulse/SOUL.md",
205
- "voiceId": "eadgjmk4R4uojdsheG9t",
205
+ "voiceId": null,
206
206
  "color": "#eab308",
207
207
  "emoji": "\ud83c\udf0a",
208
208
  "tools": ["web_search", "web_fetch", "read", "write", "message"],
@@ -258,7 +258,7 @@
258
258
  "reportsTo": "jarvis",
259
259
  "directReports": [],
260
260
  "soulPath": "agents/spark/SOUL.md",
261
- "voiceId": "xNtG3W2oqJs0cJZuTyBc",
261
+ "voiceId": null,
262
262
  "color": "#f59e0b",
263
263
  "emoji": "\u26a1",
264
264
  "tools": ["web_fetch", "web_search", "message"],
package/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "clawport-ui",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Open-source dashboard for managing, monitoring, and chatting with your OpenClaw AI agents.",
5
5
  "homepage": "https://clawport.dev",
6
6
  "repository": {
7
7
  "type": "git",
8
- "url": "https://github.com/openclaw/clawport.git"
8
+ "url": "https://github.com/JohnRiceML/clawport-ui.git"
9
9
  },
10
10
  "bugs": {
11
- "url": "https://github.com/openclaw/clawport/issues"
11
+ "url": "https://github.com/JohnRiceML/clawport-ui/issues"
12
12
  },
13
13
  "keywords": [
14
14
  "openclaw",
@@ -19,12 +19,16 @@
19
19
  "next.js"
20
20
  ],
21
21
  "license": "MIT",
22
+ "bin": {
23
+ "clawport": "./bin/clawport.mjs"
24
+ },
22
25
  "scripts": {
23
26
  "dev": "next dev",
24
27
  "build": "next build",
25
28
  "start": "next start",
26
29
  "test": "vitest run",
27
- "setup": "node scripts/setup.mjs"
30
+ "setup": "node scripts/setup.mjs",
31
+ "prepublishOnly": "npx tsc --noEmit && vitest run"
28
32
  },
29
33
  "dependencies": {
30
34
  "@xyflow/react": "^12.10.1",
package/scripts/setup.mjs CHANGED
@@ -155,8 +155,12 @@ async function main() {
155
155
  }
156
156
  }
157
157
 
158
+ // Support --cwd flag for CLI usage (clawport setup writes .env.local into the package dir)
159
+ const cwdFlag = process.argv.find((a) => a.startsWith('--cwd='))
160
+ const targetDir = cwdFlag ? cwdFlag.split('=')[1] : process.cwd()
161
+
158
162
  // Check if .env.local already exists
159
- const envPath = resolve(process.cwd(), '.env.local')
163
+ const envPath = resolve(targetDir, '.env.local')
160
164
  if (existsSync(envPath)) {
161
165
  const overwrite = await ask(` ${yellow('?')} .env.local already exists. Overwrite? (y/N) `)
162
166
  if (overwrite.toLowerCase() !== 'y') {
File without changes