@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 +177 -0
- package/LICENSE +21 -0
- package/README.md +178 -0
- package/dist/index.js +5110 -0
- package/package.json +61 -0
- package/skills/workser/SKILL.md +231 -0
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).
|