@workser/cli 0.1.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/AGENTS.md ADDED
@@ -0,0 +1,177 @@
1
+ # Workser tools (for AI agents)
2
+
3
+ > This file is the portable instruction layer for agents **without** native Skills
4
+ > (Codex, Gemini CLI, Cursor, etc.). For Claude Code, the same content ships as a
5
+ > Skill at `skills/workser/SKILL.md`. Workser Orbit drops the right one per agent.
6
+
7
+ You have the `workser` CLI installed. Use it to **run** software on the user's
8
+ behalf — provision infrastructure, deploy, and manage live apps on Workser. The
9
+ agent thinks on the user's tokens; `workser` is how you act (DevOps + platform).
10
+
11
+ ## Use it for the "last mile"
12
+ Writing code → your normal tools. Putting it online, databases, env vars, domains,
13
+ deploy status, logs → `workser`.
14
+
15
+ ## What you can and can't do
16
+ You are scoped to **one project** — the one Orbit linked to this directory. Within it
17
+ you operate on the project's **own infrastructure**: provision and use its Neon
18
+ Postgres database (`db create`, read its connection string, browse tables / schema /
19
+ rows, run SQL), provision its bucket + auth, deploy, read/set env vars, manage files,
20
+ read logs. Sensitive actions are **gated**: the daemon may return
21
+ `error.code = "awaiting_approval"` (exit 5) and wait for the user to approve in Orbit
22
+ — ask them to approve, then retry.
23
+
24
+ What you **cannot** do is administer the project set or destroy config: creating or
25
+ switching which project is pinned, deleting env vars, or attaching a custom domain.
26
+ Those are **owner actions** — you get `error.code = "owner_only"` (exit 6). Don't
27
+ retry or look for a workaround; tell the user it's an owner action and continue with
28
+ what you *can* do.
29
+
30
+ ## Rules
31
+ - **Always add `--json`.** Output is `{"ok":true,"data":...}` or `{"ok":false,"error":{...}}`.
32
+ - Run `workser status --json` first to orient. The project is already selected for
33
+ you (Orbit pinned it); you don't pick or switch projects.
34
+ - `error.code = "owner_only"` (exit 6) → an owner-only action. Tell the user to do
35
+ it in Orbit; never try to bypass it.
36
+ - `error.code = "awaiting_approval"` (exit 5) → the user must approve in Orbit. Ask
37
+ them to approve, then retry. Never attempt to bypass approvals.
38
+ - You never handle credentials — Orbit owns auth.
39
+
40
+ ## Commands
41
+ ```
42
+ workser status | whoami # orient (read)
43
+ workser project show | list # your pinned project + the workspace
44
+ workser env set KEY=VALUE… | list | get KEY # env vars
45
+ workser db create # provision the Neon Postgres database
46
+ workser db url | list # DB connection string + status
47
+ workser db tables # list tables in the database
48
+ workser db schema <table> # a table's columns
49
+ workser db data <table> [-n N] [--offset N] # read rows
50
+ workser db query "<sql>" # run SQL (writes are approval-gated)
51
+ workser auth enable | status # provision + inspect auth
52
+ workser storage create [name] | list # provision + show the bucket
53
+ workser storage ls [prefix] # list objects in the bucket
54
+ workser storage put <local> <key> # upload a file into the bucket
55
+ workser storage get <key> [dest] # download (or print the object URL)
56
+ workser deploy [--prod] [--watch] | deploy status [id]
57
+ workser logs [-n N] [-f] | versions
58
+ workser domain list # custom domains (read)
59
+ workser open
60
+ workser agent list | run <role> "<task>" | main
61
+ workser workflow list | create <name> [--body <json>] | get <id>
62
+ workser workflow activate <id> | deactivate <id> | run <id> [--wait] [--body <json>]
63
+ workser workflow runs <id> # past executions of a workflow
64
+ workser workflow nodes [query] # search the node-type catalog
65
+ workser app list [--toolkit <slug>] # connectable + connected third-party apps
66
+ workser app connect <toolkit> | disconnect <connectionId>
67
+ workser app tools <toolkit> # a connected app's callable actions
68
+ workser app run <toolSlug> [--body <json>] # execute one action (e.g. GOOGLESHEETS_APPEND_ROW)
69
+
70
+ workser tool list # computer-use tools available to you now
71
+ workser tool run <name> [--body <json>] # filesystem/shell/screenshot/input/clipboard/browser
72
+
73
+ workser memory add "<content>" [--metadata <json>] # remember something across future conversations
74
+ workser memory search "<query>" [--limit N] # recall what you (or a cloud agent) learned before
75
+ workser memory forget <memoryId> # soft-delete an outdated/incorrect memory
76
+
77
+ workser artifact add <path> [--kind <k>] [-d <text>] # record a finished deliverable
78
+ workser artifact add --url <url> --kind app # record a deployed app
79
+ workser artifact run # which task you're attached to
80
+
81
+ workser ask "<question>" [--type <t>] [--option <o>] # ask the user, WAIT for the answer
82
+
83
+ # owner-only (will return owner_only / exit 6 — ask the user to do these in Orbit):
84
+ # project create, project use, env rm, domain set
85
+ ```
86
+
87
+ ## Memory (remember across conversations, not just this one)
88
+ Every conversation you run is otherwise a fresh start — no memory of what you or the
89
+ user decided last time. `workser memory add "<content>"` fixes that: it stores durable,
90
+ searchable memory for the CURRENT PROJECT, and it's the SAME memory space Workser's own
91
+ cloud agents write to for this project — add something here and a cloud agent (or your
92
+ own next conversation) can `workser memory search` and find it. Use it for things worth
93
+ remembering past this one conversation: user preferences, decisions made, important
94
+ context, requirements — not routine chatter. Before assuming you don't know something
95
+ about this project, `workser memory search "<topic>"` first; it may already be recorded.
96
+ `forget` soft-deletes a specific memory if it's wrong or outdated.
97
+
98
+ ## Record what you produced (deliverables)
99
+ Workser shows the user a **Deliverables** list on the task. If you don't say what you
100
+ made, it has to guess — it watches your file edits and treats any path it sees as a
101
+ deliverable, so scratch files and half-finished drafts show up next to the real output,
102
+ and things that aren't files at all (a folder of results, an app you deployed) can't
103
+ show up correctly. Fix that by declaring finished output:
104
+ ```
105
+ workser artifact add ./report.pdf -d "Q3 sales summary"
106
+ workser artifact add ./exports --kind folder -d "generated CSVs"
107
+ workser artifact add --url https://acme.workser.app --kind app -t "Storefront"
108
+ ```
109
+ Only register FINISHED output the user should get — not temp files, not intermediate
110
+ steps. `--kind` is inferred from the path when you omit it (directories are detected
111
+ automatically); pass it explicitly for `app` / `url`. `workser artifact run` shows which
112
+ task you're currently attached to.
113
+
114
+ To publish an app: `workser deploy` (preview) or `workser deploy --prod` (live), then
115
+ register the URL it returns as an `app` artifact so the user can open it from the task.
116
+
117
+ ## Ask the user something (and get an answer back)
118
+ When you're blocked — a missing value, an ambiguous requirement, permission for
119
+ something consequential — don't guess and don't just write the question into your
120
+ final message. Run:
121
+ ```
122
+ workser ask "Which email should order confirmations come from?"
123
+ workser ask "Which plan should I wire up?" --option Free --option Pro --option Team
124
+ workser ask "Delete the 1,240 archived rows?" --type approval
125
+ ```
126
+ This shows the user a real card in the conversation and **blocks until they answer**,
127
+ then prints their answer — so you ask, read the reply, and keep working in the same
128
+ turn. Types: `input` (default, free text), `choice` (with `--option`), `approval`
129
+ (permission), `confirmation` (check an assumption), `information` (FYI, no answer
130
+ needed). It times out (default 10 min) rather than hanging forever; if it does, carry
131
+ on and state clearly what you assumed.
132
+
133
+ **Never ask for a secret value this way** — the answer is stored and displayed. Ask
134
+ where a key should go, then have the user set it (`workser env set` writes it without
135
+ you ever seeing it).
136
+
137
+ ## Computer-use tools (your hands on this machine)
138
+ `workser tool list` shows what's available — filesystem (read/write/list/delete/move),
139
+ shell (run a command/Python/Node), screenshots and screen info, mouse/keyboard input,
140
+ clipboard, notifications, and basic browser control (open a URL, read the page, click/
141
+ fill/type, screenshot). This is the SAME engine Workser's cloud Computer Use agent uses
142
+ when it controls a user's machine remotely — you get it locally, gated by the same
143
+ safety policy (blocked paths like `~/.ssh`, blocked destructive commands, rate limits).
144
+ Sensitive actions (writing/deleting files, running a shell command, clicking/typing) may
145
+ return `awaiting_approval` (exit 5) — handle it the same as any other gated action: tell
146
+ the user to approve in Orbit, then retry. This is a curated subset, not full desktop
147
+ automation — check `workser tool list` rather than assuming a capability exists.
148
+
149
+ ## Workflow automation & app integrations
150
+ Beyond one-shot code, you can wire up **automations** that keep running after you're
151
+ done: `workser workflow create` builds an event-driven, multi-step automation (the
152
+ same engine Workser's own web Workflow tab uses) — nodes, connections, and triggers go
153
+ in `--body` as JSON; browse `workser workflow nodes` first to see what's available.
154
+ Before an automation can use a third-party app (Gmail, Slack, Stripe, Google Sheets,
155
+ ...), the user connects it once via `workser app connect <toolkit>` (this opens an
156
+ OAuth link — ask the user to complete it, then continue); after that, `workser app
157
+ run <toolSlug> --body '{"...":...}'` calls any of its actions directly, and a workflow
158
+ node can call the same toolkit. Use `workser app list` to see what's already
159
+ connected before assuming you need to ask the user to connect something new.
160
+
161
+ ## Delegate to roles
162
+ The user can configure **roles** — named specialists each backed by a local CLI agent
163
+ (e.g. `qa` → codex, `designer` → claude_code). Delegate a focused subtask with
164
+ `workser agent run <role> "<task>" --json`; the role runs as an **isolated local
165
+ subagent** (own context) and returns `{role, agent, output, exitCode}`. Run
166
+ `workser agent list --json` first to see the configured, runnable roles. Use this to
167
+ keep your own context lean and get a specialized second perspective; a non-zero
168
+ `exitCode` means the role's run failed — surface it.
169
+
170
+ ## Example
171
+ ```bash
172
+ workser status --json # orient: which project, last deploy
173
+ workser env set STRIPE_KEY=sk_live_… --json
174
+ # … you write the app code with your normal tools …
175
+ workser deploy --prod --watch --json # -> .data.url is the live URL
176
+ ```
177
+ Report results to the user in plain language, not raw JSON.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Workser
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 ADDED
@@ -0,0 +1,178 @@
1
+ # @workser/cli — `workser`
2
+
3
+ **The center of Workser Orbit.** `workser` is the command-line surface that lets a
4
+ local AI agent use Workser infrastructure natively — as the user's DevOps engineer.
5
+ The agent runs `workser deploy`, `workser env set`, `workser status`, etc. through
6
+ its own shell to ship and operate the app on Workser.
7
+
8
+ ## Install
9
+
10
+ ```bash
11
+ npm install -g @workser/cli
12
+ workser --version
13
+ ```
14
+
15
+ Node 20+. If you use **Workser Desktop**, it installs and updates this for you —
16
+ you only need the manual install to use `workser` on its own, alongside Claude
17
+ Code, Codex, Cursor or any other agent.
18
+
19
+ ### Using it standalone
20
+
21
+ Inside Workser Desktop the CLI talks to the local Orbit daemon, so every call
22
+ flows through the app's approval gates. On its own it talks to the Workser cloud
23
+ API instead:
24
+
25
+ ```bash
26
+ workser login # paste an API token, or pass --token
27
+ workser status # confirm the connection and the linked project
28
+ workser doctor # resolved endpoint, mode, token presence (masked)
29
+ ```
30
+
31
+ Point your agent at it by telling it the command exists. For Claude Code, the
32
+ package ships a skill at `skills/workser/SKILL.md`; for Codex, Gemini, Kimi and
33
+ others, `AGENTS.md` covers the same ground. Copy whichever your agent reads:
34
+
35
+ ```bash
36
+ # Claude Code (global)
37
+ mkdir -p ~/.claude/skills/workser
38
+ cp "$(npm root -g)/@workser/cli/skills/workser/SKILL.md" ~/.claude/skills/workser/
39
+
40
+ # Codex / Gemini / Kimi / opencode / Grok — merge into your project's AGENTS.md
41
+ cat "$(npm root -g)/@workser/cli/AGENTS.md" >> AGENTS.md
42
+ ```
43
+
44
+ Agents should always pass `--json`.
45
+
46
+
47
+
48
+ ### Scope: one project, operate within it
49
+
50
+ The CLI is the **agent-facing** surface, and it is deliberately small. It is bound
51
+ to the **single project** Orbit linked to the working directory. Within that project
52
+ the agent can **operate on the project's own infrastructure** — provision and use its
53
+ Neon Postgres database (create it, read its least-privilege connection string, browse
54
+ tables / schema / rows / run SQL), provision its bucket + auth, deploy, read/set env
55
+ vars, manage objects, read logs. The daemon **gates the sensitive actions** with an
56
+ approval prompt in the Orbit UI (`awaiting_approval`, exit 5), so the user stays in
57
+ the loop without the CLI having to refuse outright.
58
+
59
+ What stays **owner-only** (refuses with `error.code = "owner_only"`, exit 6, no
60
+ network call) is **administering the project set or destroying config**: creating or
61
+ switching which project is pinned, deleting env vars, and attaching custom domains.
62
+ This is the first of two gates — the daemon + core-api enforce the boundary
63
+ server-side too. See `src/capabilities.ts`.
64
+
65
+ It's designed to be the **token-lean** primary integration (vs. injecting MCP tool
66
+ schemas into the agent's context on every turn): a shell call costs almost nothing,
67
+ and the agent is taught *when* to use it via a Skill (Claude) or `AGENTS.md`
68
+ (other agents). MCP stays available, but only inside a scoped subagent — see the
69
+ platform plans in `workser-agents-platform/`.
70
+
71
+ ## How it connects
72
+
73
+ `workser` is a thin client of one endpoint contract, resolved in this order:
74
+
75
+ | Resolves | Precedence |
76
+ |---|---|
77
+ | **endpoint** | `--endpoint` → `$WORKSER_DAEMON_URL` → `~/.workser/session.json` → cloud default |
78
+ | **token** | `--token` → `$WORKSER_TOKEN` → session file |
79
+ | **project** | `--project` → `<cwd>/.workser/project.json` → session default |
80
+
81
+ - **Inside Workser Orbit (primary):** the app writes `~/.workser/session.json`
82
+ pointing at its **local daemon** (`http://127.0.0.1:<port>`). Calls flow through
83
+ the cockpit, which handles **auth (bridge JWT), approval gates, and live progress
84
+ in the UI**. This is how the user *sees* what the agent does.
85
+ - **Standalone / CI:** `workser login --token <t>` saves a session against the
86
+ **cloud API** (`https://api.workser.ai`). Same commands, no desktop app.
87
+
88
+ Both speak the same `/v1/...` contract (see `src/client.ts`).
89
+
90
+ ## Install (dev)
91
+
92
+ ```bash
93
+ npm install
94
+ npm run build
95
+ npm link # makes `workser` available globally for local testing
96
+ workser --help
97
+ ```
98
+
99
+ ### Packaging (single self-contained file)
100
+
101
+ `npm run build` produces **one** self-contained executable: `dist/index.js`. tsup
102
+ bundles every runtime dependency (`commander`, `picocolors`) inline, keeps the
103
+ `#!/usr/bin/env node` shebang, and inlines the version — so the file runs under the
104
+ system `node` from any directory, with **no `node_modules`** alongside it.
105
+
106
+ The Orbit desktop connector relies on this: it copies exactly that one file to
107
+ `~/.workser/bin/workser` (and `chmod +x`) to install the CLI on the agent's PATH
108
+ during onboarding — no `npm install`, no dependency tree to ship. The binary is also
109
+ published as `@workser/cli`.
110
+
111
+ ## Command surface
112
+
113
+ ```
114
+ workser status | whoami | login | logout
115
+ workser project show | list # the pinned project + workspace (read)
116
+ workser db create # provision Neon Postgres (idempotent)
117
+ workser db url | list # connection string + status
118
+ workser db tables | schema <t> | data <t> | query <sql> # browse the Neon database
119
+ workser auth enable | status # provision + inspect auth
120
+ workser env set KEY=VALUE… | get KEY | list # env vars
121
+ workser storage create [name] | list | ls [prefix] # bucket + its objects
122
+ workser storage put <local> <key> | get <key> [dest] # objects in the bucket
123
+ workser deploy [--prod] [--watch] | deploy status [id]
124
+ workser logs [-n N] [-f] | versions
125
+ workser domain list # custom domains (read)
126
+ workser open | verify | doctor
127
+ workser agent list | run <role> "<task>" | main
128
+
129
+ # owner-only — refuse with owner_only (exit 6), no network call:
130
+ workser project create · project use · env rm · domain set
131
+ ```
132
+
133
+ Global flags: `--json`, `-q/--quiet`, `-p/--project <id>`, `-C/--cwd <dir>`,
134
+ `--endpoint <url>`, `--token <token>`.
135
+
136
+ ## Design principles (the contract)
137
+
138
+ 1. **Agent-first output.** Every command supports `--json`, returning a single
139
+ stable line: `{"ok":true,"data":...}` or `{"ok":false,"error":{code,message,...}}`.
140
+ Human text output is terse and colorized.
141
+ 2. **Stable exit codes.** `0` ok · `1` generic · `3` unauthorized · `4` not connected
142
+ · `5` awaiting approval · `6` owner-only.
143
+ 3. **Least privilege by construction.** One project; the agent operates on *that*
144
+ project's own infra (sensitive actions daemon-gated). Administering the project
145
+ set or destroying config is owner-only (`owner_only`, exit 6); it refuses locally
146
+ and is also unreachable with the agent's scoped key server-side.
147
+ 4. **Approvals belong to the daemon.** Allowed-but-gated calls can return
148
+ `awaiting_approval`; the user approves in Orbit. The CLI never bypasses gates.
149
+ 5. **No credential handling.** Auth lives in Orbit / the session token; the agent
150
+ never sees raw keys.
151
+
152
+ ## Layout
153
+
154
+ ```
155
+ src/
156
+ index.ts # program + global flags, registers commands
157
+ run.ts # action() wrapper: builds context, funnels errors
158
+ context.ts # resolve endpoint/token/project (daemon vs cloud)
159
+ client.ts # the single fetch() entrypoint + /v1 contract docs
160
+ capabilities.ts # the owner-only boundary (what the agent may NOT do)
161
+ config.ts # ~/.workser/session.json + <cwd>/.workser/project.json
162
+ output.ts # ok()/fail()/line() — text & --json rendering
163
+ errors.ts # WorkserError (code + status)
164
+ commands/ # one file per command group
165
+ skills/workser/SKILL.md # Claude Code Skill (progressive disclosure)
166
+ AGENTS.md # portable instructions for non-Skill agents
167
+ ```
168
+
169
+ ## Status
170
+
171
+ v0.1. The `/v1/...` endpoints are the contract implemented by the Orbit local daemon
172
+ (which proxies `workser-core-api-service`'s `orbit` controller and wraps replies in
173
+ `{ok,data}`); commands are aligned to that contract — including the Neon Postgres
174
+ browser (`db tables|schema|data|query`) — and verified live against the running
175
+ daemon. The suite (`npm test`) exercises every command against an in-process daemon
176
+ stub: request shapes, provisioning, the Neon browser, the storage object flow, exit
177
+ codes, nested-error normalization, and the owner-only boundary. Next: enforce the same
178
+ owner-only boundary server-side on the agent's project-scoped key (the second gate).