@hanzo/build 0.2.52 → 0.2.54
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 +103 -49
- package/lib/api/billing.d.ts +39 -0
- package/lib/api/billing.js +41 -0
- package/lib/api/coding.d.ts +4 -1
- package/lib/api/coding.js +2 -0
- package/lib/api/environment.d.ts +12 -0
- package/lib/api/environment.js +39 -1
- package/lib/api/github.d.ts +24 -4
- package/lib/api/github.js +60 -16
- package/lib/api/limits.d.ts +69 -0
- package/lib/api/limits.js +86 -0
- package/lib/api/links.d.ts +42 -0
- package/lib/api/links.js +65 -0
- package/lib/api/pref.d.ts +5 -3
- package/lib/api/pref.js +0 -3
- package/lib/api/turn.d.ts +10 -1
- package/lib/api/turn.js +16 -4
- package/lib/api/work.d.ts +75 -38
- package/lib/api/work.js +132 -44
- package/lib/builder.d.ts +0 -10
- package/lib/builder.js +12 -52
- package/lib/choice.d.ts +21 -0
- package/lib/choice.js +40 -1
- package/lib/customize/agents.d.ts +1 -1
- package/lib/customize/agents.js +21 -19
- package/lib/customize/connectors.d.ts +1 -1
- package/lib/customize/connectors.js +80 -31
- package/lib/customize/index.d.ts +2 -0
- package/lib/customize/index.js +23 -19
- package/lib/customize/load.d.ts +9 -0
- package/lib/customize/load.js +22 -0
- package/lib/customize/plugins.d.ts +1 -1
- package/lib/customize/plugins.js +21 -19
- package/lib/customize/say.d.ts +1 -0
- package/lib/customize/say.js +38 -0
- package/lib/customize/skills.d.ts +1 -1
- package/lib/customize/skills.js +23 -17
- package/lib/customize/ui.d.ts +28 -11
- package/lib/customize/ui.js +29 -21
- package/lib/data.d.ts +13 -0
- package/lib/data.js +70 -0
- package/lib/desk.d.ts +6 -1
- package/lib/desk.js +43 -19
- package/lib/environment.d.ts +11 -3
- package/lib/environment.js +53 -13
- package/lib/foot.js +10 -6
- package/lib/forge.js +139 -71
- package/lib/index.d.ts +28 -2
- package/lib/index.js +26 -2
- package/lib/landing.d.ts +0 -10
- package/lib/landing.js +70 -38
- package/lib/merge.d.ts +223 -0
- package/lib/merge.js +380 -0
- package/lib/meter.d.ts +31 -0
- package/lib/meter.js +45 -0
- package/lib/mind.d.ts +60 -0
- package/lib/mind.js +187 -0
- package/lib/nav.d.ts +11 -0
- package/lib/nav.js +75 -0
- package/lib/panel.d.ts +46 -0
- package/lib/panel.js +116 -0
- package/lib/pick.d.ts +8 -0
- package/lib/pick.js +18 -1
- package/lib/plan.d.ts +78 -0
- package/lib/plan.js +133 -0
- package/lib/project.js +16 -6
- package/lib/prompt.d.ts +75 -0
- package/lib/prompt.js +125 -0
- package/lib/prose.js +14 -10
- package/lib/reply.d.ts +36 -0
- package/lib/reply.js +124 -0
- package/lib/route.d.ts +16 -0
- package/lib/route.js +40 -0
- package/lib/run.js +87 -52
- package/lib/section.d.ts +1 -1
- package/lib/section.js +7 -11
- package/lib/settings/billing.js +16 -9
- package/lib/settings/code.js +15 -12
- package/lib/settings/credits.d.ts +9 -0
- package/lib/settings/credits.js +110 -0
- package/lib/settings/plan.d.ts +17 -0
- package/lib/settings/plan.js +108 -0
- package/lib/settings/usage.js +11 -119
- package/lib/shelf.js +3 -3
- package/lib/standing.d.ts +44 -0
- package/lib/standing.js +64 -0
- package/lib/sync.js +22 -8
- package/lib/tabs.d.ts +53 -0
- package/lib/tabs.js +197 -0
- package/lib/tools.d.ts +2 -9
- package/lib/tools.js +20 -25
- package/lib/transcript.d.ts +10 -1
- package/lib/transcript.js +25 -10
- package/lib/voice.d.ts +2 -13
- package/lib/voice.js +7 -73
- package/package.json +20 -3
package/README.md
CHANGED
|
@@ -65,6 +65,15 @@ under the mount (`path`) and how to move (`go`), where to link out
|
|
|
65
65
|
(`theme`, `chooseTheme`), which follows the person's saved choice. Peers:
|
|
66
66
|
`@hanzo/ui`, `@hanzo/gui`, `@hanzogui/lucide-icons-2`, `react`.
|
|
67
67
|
|
|
68
|
+
`path` is the builder's own grammar (`route`, `path`). A host that shows real
|
|
69
|
+
paths writes it with `href` and reads it back with `parse`: '' New,
|
|
70
|
+
`/run/<id>`, `/projects/<org>/<repo>` a repository, `/projects/<slug>` a site,
|
|
71
|
+
`/machines` and `/environments` in the rail's own words, and every other place
|
|
72
|
+
at its name (`/projects`, `/issues`, `/customize/connectors`, `/settings/usage`).
|
|
73
|
+
`PLACES` lists every address that names no record, for a host that writes a page
|
|
74
|
+
per address ahead of time. `@hanzo/build/route` is that module alone, with no
|
|
75
|
+
React, for server code and for pages that must not carry the builder.
|
|
76
|
+
|
|
68
77
|
### In a host that has its own rail
|
|
69
78
|
|
|
70
79
|
The Hanzo app already has a left column, so it mounts `<Builder host={host}
|
|
@@ -74,7 +83,7 @@ rail={false} />` in its pane and lists the builder in its own rail:
|
|
|
74
83
|
import { Builder, DevSection } from '@hanzo/build'
|
|
75
84
|
|
|
76
85
|
<Sidebar> {/* the host's rail, @hanzo/ui/chat */}
|
|
77
|
-
<DevSection host={host} /> {/*
|
|
86
|
+
<DevSection host={host} /> {/* every place, grouped (nav), then the runs */}
|
|
78
87
|
</Sidebar>
|
|
79
88
|
<Builder host={host} rail={false} />
|
|
80
89
|
```
|
|
@@ -85,11 +94,24 @@ pane tokens: `--pane-fill`, `--pane-round`, `--pane-edge`, `--pane-blur`,
|
|
|
85
94
|
`--pane-gap`, and `--shadow-sheet-2` for the drop. A host retunes the tokens;
|
|
86
95
|
it writes no rule against the builder's slots.
|
|
87
96
|
|
|
88
|
-
`DevSection` is rows of `@hanzo/ui/chat`'s Sidebar; `
|
|
89
|
-
|
|
90
|
-
|
|
97
|
+
`DevSection` is rows of `@hanzo/ui/chat`'s Sidebar; `nav(host, go)` is the one
|
|
98
|
+
list of places every rail draws, in groups (Work, Make, Run, Setup) and with
|
|
99
|
+
nothing behind a More; `useSessions(host)` is the runs — the org's coding runs,
|
|
100
|
+
kept live by the org's feed — for a host that draws the rows itself. `administers(token, org)` reads the org-admin bit off a
|
|
91
101
|
hanzo.id token for `Host.admin`. One left column, never two.
|
|
92
102
|
|
|
103
|
+
## The model, the composer, the panel
|
|
104
|
+
|
|
105
|
+
One of each, shared with Chat (@hanzo/rooms imports them):
|
|
106
|
+
|
|
107
|
+
- `useMind` — the model and effort: `GET /v1/models` read once per platform,
|
|
108
|
+
and the choice kept in this browser (`hanzo.mind`, Enso and Medium until
|
|
109
|
+
changed). `Tune` is the chip that changes it; Settings → Code writes the same
|
|
110
|
+
choice. `@hanzo/build/mind` serves the store alone, without the builder.
|
|
111
|
+
- `prompt` / `Prompt` — the composer, as wide as the text above it (`measure`).
|
|
112
|
+
- `Reply` — copy, Listen and Open under an answer.
|
|
113
|
+
- `Panel` over `useDeck` — the side panel and its kept tabs.
|
|
114
|
+
|
|
93
115
|
## Addresses
|
|
94
116
|
|
|
95
117
|
| path | screen |
|
|
@@ -98,10 +120,10 @@ hanzo.id token for `Host.admin`. One left column, never two.
|
|
|
98
120
|
| `sess_<32 hex>` | one run, live |
|
|
99
121
|
| `-/automations` | repeating work, read from `/v1/auto/flows` |
|
|
100
122
|
| `-/customize` · `-/customize/connectors` · `/plugins` · `/agents` | Customize: skills, connectors, plugins, agents |
|
|
101
|
-
| `-/mcp` | Connectors →
|
|
123
|
+
| `-/mcp` | Connectors → Browse with the fleet's native MCP servers listed |
|
|
102
124
|
| `-/projects` | the org's projects: its repositories on the forge |
|
|
103
125
|
| `-/sync` | link repositories from GitHub onto the forge |
|
|
104
|
-
| `-/issues` | the forge's
|
|
126
|
+
| `-/issues` | every project's issues, merged: the forge's and the task index's |
|
|
105
127
|
| `-/artifacts` | what the org has built |
|
|
106
128
|
| `-/templates` | the public starters |
|
|
107
129
|
| `-/plans` | the plans this brand sells, and the move to another |
|
|
@@ -114,13 +136,29 @@ one address of two segments, so the forms cannot collide.
|
|
|
114
136
|
|
|
115
137
|
## What is on the screen
|
|
116
138
|
|
|
139
|
+
**Issues.** Every project's issues and pull requests, the forge's and the task
|
|
140
|
+
index's merged (merge.ts): the same issue on two boards is one row, with every
|
|
141
|
+
label and assignee either carried. A column of projects — every board, and every
|
|
142
|
+
repository an issue is filed under — each with what is open on it; Open and
|
|
143
|
+
Closed with their counts; a search; Label, Assignee, Kind, Source and Sort.
|
|
144
|
+
Pressing an issue opens New on the issue's own repository, where the issue
|
|
145
|
+
lives (a GitHub issue on GitHub, a forge issue on the forge), filled with its
|
|
146
|
+
title, number, link and body, and the run's pull request closes it; an issue no
|
|
147
|
+
project answers to (a Linear team's key, a board with no repository) asks which
|
|
148
|
+
project it is for. A board's key is never taken for a repository.
|
|
149
|
+
|
|
117
150
|
**The rail** (this page, or `rail` left on). At the top, the mark. Signed in to an organization,
|
|
118
151
|
that spot is the organization switcher: the org, and the projects under it.
|
|
119
|
-
New,
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
152
|
+
New, then every place in view (nav.tsx) — Work: Projects, Issues; Make:
|
|
153
|
+
Artifacts, Templates, Automations; Run: Machines, Environments; Setup:
|
|
154
|
+
Customize, Docs — then the org's coding runs newest first with a live status
|
|
155
|
+
dot. Nothing waits behind a More. At the foot, a card offering Hanzo in Slack
|
|
156
|
+
(dismissed once, gone in this browser) and the account, whose menu holds the
|
|
157
|
+
email, the plan under it
|
|
158
|
+
(`Meter`: Max with 20x beside it and the session, day and month as shares;
|
|
159
|
+
Free's allowance left today; the balance only with no plan), Settings, Usage,
|
|
160
|
+
Billing, View all plans, Get help (the docs, in a new tab) and Log out. No money
|
|
161
|
+
sits beside a plan: credits live in Billing. Collapse is an explicit
|
|
124
162
|
toggle kept in this browser. A host with its own rail draws `DevSection` there
|
|
125
163
|
instead.
|
|
126
164
|
|
|
@@ -136,35 +174,44 @@ drain, claim key (shown once) and removal. API keys: your secret and publishable
|
|
|
136
174
|
key, a new one shown once, rotated or revoked.
|
|
137
175
|
|
|
138
176
|
**Customize.** What the agent brings to a run, a tab each — Skills, Connectors,
|
|
139
|
-
Plugins, Agents — and in each,
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
177
|
+
Plugins, Agents — and in each, Browse (what there is to add, then what Hanzo
|
|
178
|
+
builds in) first and always where the tab opens, then Yours (what the org has,
|
|
179
|
+
counted on its button); one search and one Add. An empty Yours names the next
|
|
180
|
+
step as buttons. A read that fails is said in plain words with Try again, and one
|
|
181
|
+
that takes over fifteen seconds gives up and says so; only a 400, 409 or 422
|
|
182
|
+
carries the platform's own sentence (a failed build, a name taken). Skills and
|
|
183
|
+
connectors ride into every run in the org, so they are an org admin's to add,
|
|
184
|
+
switch and remove, and a member reads them and is told so; plugins and agents
|
|
185
|
+
are any member's.
|
|
186
|
+
|
|
187
|
+
- Skills: Browse is the brand's catalogue (`/.well-known/agent-skills/`) to read
|
|
188
|
+
and add; Yours is the org's own SKILL.md skills, written, revised and deleted
|
|
189
|
+
here, and the catalogue's it added. Adding is switching `skill_<name>` on, and
|
|
190
|
+
a switch per skill turns it off again.
|
|
191
|
+
- Connectors: Browse is the shelf (featured first; a listing that ships only a
|
|
192
|
+
package says so and has no Add), then the fleet's native servers, which every
|
|
193
|
+
run can call and nothing adds — listed by `POST /v1/mcp` only when asked for,
|
|
194
|
+
since that list starts every subsystem it names. Yours is the MCP servers the
|
|
195
|
+
org added — by URL or off the shelf, a secret sealed in KMS — each with one
|
|
196
|
+
switch on its card for all its tools and one per tool inside. Adding one
|
|
197
|
+
switches its tools on.
|
|
152
198
|
- Plugins: TypeScript connectors built on the platform, from source or from a
|
|
153
|
-
description of an API; a failed build says why.
|
|
154
|
-
deployment mounts.
|
|
155
|
-
- Agents: the
|
|
156
|
-
|
|
157
|
-
|
|
199
|
+
description of an API; a failed build says why. Browse offers building one and
|
|
200
|
+
lists what the deployment mounts.
|
|
201
|
+
- Agents: Browse is the platform's presets whose tool calls run on the platform,
|
|
202
|
+
each a Use that opens a new agent written from it; Yours is the org's own —
|
|
203
|
+
model, instructions, tools, budget — created, edited (only what changed is
|
|
204
|
+
sent) and deleted.
|
|
158
205
|
|
|
159
206
|
**New.** "What's up next?", and at the foot the composer: where the run runs
|
|
160
207
|
(Cloud is the platform's sandbox with the codebase's environment; the org's
|
|
161
208
|
machines follow under remote control, each linked with `hanzo link`), the
|
|
162
209
|
codebase and the branch — the forge's repositories, filtered as you type, read
|
|
163
210
|
again with Refresh list, and a way to Sync for a GitHub repository that is not
|
|
164
|
-
there yet — then the ask
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
that choice already made.
|
|
211
|
+
there yet — then the ask, in the composer Chat draws too (`prompt`): the paperclip
|
|
212
|
+
and Build or Plan at its start; the model and effort (`Tune`), dictation and
|
|
213
|
+
send at its end. A codebase can be added to a project. Opening a codebase or an
|
|
214
|
+
issue from its own screen lands here with that choice already made.
|
|
168
215
|
|
|
169
216
|
**A run.** The transcript as it streams, drawn by what each part is: what the
|
|
170
217
|
agent says as markdown, each command it runs as a card that opens onto its
|
|
@@ -174,17 +221,14 @@ request once it pushes one. Once it has finished, a follow-up starts a new run
|
|
|
174
221
|
from the branch it pushed — the same codebase, place and mode — and opens it; a
|
|
175
222
|
paused sandbox run goes on the same way. A plan run ends with its plan and
|
|
176
223
|
Approve and build. Rename it, share a project run's story publicly, and find any
|
|
177
|
-
run by status in Find. Beside it:
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
- Files: the working tree live from the sandbox, or the run's branch; and
|
|
186
|
-
Artifacts, what it produced.
|
|
187
|
-
- Subscriptions.
|
|
224
|
+
run by status in Find. Beside it, the side panel (`Panel`, the one Chat opens):
|
|
225
|
+
Preview (what the sandbox serves, or where the run is published), Artifacts,
|
|
226
|
+
Files, Diff (Diff, Review, Commits) and Terminal (a shell in the working tree,
|
|
227
|
+
reattached by the run's name, and the agent's log); `+` opens Desktop (the
|
|
228
|
+
sandbox's screen), Environment and any page. Tabs are dragged to reorder (or
|
|
229
|
+
moved with Ctrl/⌘+Shift+←/→), shut with their cross, and kept as left; the
|
|
230
|
+
header's Panel button and ⌘. / Ctrl+. open and shut it, and a phone opens it as
|
|
231
|
+
a sheet. An answer's Open shows what it wrote there, and a publish opens Preview.
|
|
188
232
|
|
|
189
233
|
The desktop and the shell are the sandbox's, so they close when the run stops.
|
|
190
234
|
The setup bar says how long setup runs here have taken, once there are three.
|
|
@@ -222,7 +266,8 @@ picker and open-in-tab; Share and Publish; the console dock under it.
|
|
|
222
266
|
| `POST /v1/sandbox/read` | the run's working tree, live |
|
|
223
267
|
| `GET /v1/provider/github/repos` · `POST /v1/provider/github/repos/import` | granted repositories, and bringing them onto the forge |
|
|
224
268
|
| `GET /v1/git/repos` · `GET /v1/git/repos/{name}` | the codebase chip, and its branches |
|
|
225
|
-
| `GET /v1/
|
|
269
|
+
| `GET /v1/sync` | the repositories linked from GitHub, each with its forge copy and when it last synced |
|
|
270
|
+
| `GET /v1/task/projects` · `GET /v1/task/board` · `GET /v1/task/projects/{key}/issues` | boards, and every issue and pull request: the forge's and the task index's |
|
|
226
271
|
| `GET /v1/provider/github/repos` · `…/{owner}/{repo}/branches` | kept for a host that still asks GitHub |
|
|
227
272
|
| `POST /v1/provider/github/user/connect` | connect a person's GitHub |
|
|
228
273
|
| `GET /v1/projects` · `PATCH`/`DELETE /v1/projects/{slug}` · `POST /v1/projects/fork` · `GET /v1/templates` | artifacts, templates |
|
|
@@ -245,14 +290,17 @@ picker and open-in-tab; Share and Publish; the console dock under it.
|
|
|
245
290
|
| `GET /v1/billing/plans` · `…/subscriptions` · `POST …/subscribe/card` · `…/subscriptions/{id}/cancel`·`/reactivate` | Plans, and the plan in Billing |
|
|
246
291
|
| `GET`/`POST`/`DELETE /v1/billing/methods` · `GET /v1/billing/settings` | saved cards; a card is added from the processor's own field |
|
|
247
292
|
| `GET /v1/billing/invoices` · `…/invoices/{id}/pdf` | invoices |
|
|
248
|
-
| `GET /v1/
|
|
293
|
+
| `GET`/`PUT /v1/ai/limits` · `GET /v1/billing/tier` · `GET /v1/allowance` | the plan's windows as shares, and credits past the allowance (Usage, the menu's `Meter`) |
|
|
294
|
+
| `GET /v1/billing/balance` · `…/credit-balance` · `…/credits` · `…/usage/rollup` · `GET`/`PUT …/recharge` · `POST …/topup` · `GET /v1/usage/summary` | Credits, in Billing: prepaid, granted, top-up, auto-reload, spend |
|
|
249
295
|
| `GET`/`POST`/`PATCH`/`DELETE /v1/billing/alerts` | the monthly limit (org admin) |
|
|
250
296
|
| `GET /v1/iam/memberships?org=` · `GET`/`POST`/`DELETE /v1/iam/invitations` | Members |
|
|
251
297
|
| `GET /v1/provider/{slack,github}` · `POST …/connect`·`/disconnect` · `GET /v1/provider/slack/channels` · `GET /v1/provider/github/installations` | Integrations |
|
|
252
298
|
| `GET`/`POST /v1/webhook` · `DELETE /v1/webhook/{id}` · `POST …/test` · `GET …/deliveries` | Notifications |
|
|
253
299
|
|
|
254
|
-
`mode`, `model` and `effort` are sent with a run as asked
|
|
255
|
-
|
|
300
|
+
`mode`, `model` and `effort` are sent with a run as asked — Enso as
|
|
301
|
+
`enso-auto`, never left out — and `issue`, the number a run started from an
|
|
302
|
+
issue closes; the platform honours them where it does and nothing here
|
|
303
|
+
simulates them.
|
|
256
304
|
|
|
257
305
|
## Layout
|
|
258
306
|
|
|
@@ -261,11 +309,16 @@ src/
|
|
|
261
309
|
index.ts the library surface
|
|
262
310
|
builder.tsx the rail and the pane the address names
|
|
263
311
|
landing.tsx New
|
|
264
|
-
forge.tsx
|
|
312
|
+
forge.tsx Automations, Projects, Issues
|
|
313
|
+
merge.ts what is the same project and the same issue, which repository an issue is for
|
|
265
314
|
run.tsx one run
|
|
266
315
|
transcript.tsx a run's transcript, as cards
|
|
267
316
|
prose.tsx markdown, drawn as text (markdown.ts reads it)
|
|
268
317
|
desk.tsx the pane beside a run
|
|
318
|
+
mind.ts the model and effort, one choice with Chat
|
|
319
|
+
prompt.tsx the composer, and Tune, the model and effort chip
|
|
320
|
+
reply.tsx the row under an answer
|
|
321
|
+
panel.tsx the side panel; tabs.ts its kept tabs
|
|
269
322
|
pane.ts how a pane is cut, from the --pane-* tokens
|
|
270
323
|
door.tsx a run's desktop or shell, framed
|
|
271
324
|
git.tsx what a run pushed
|
|
@@ -273,6 +326,7 @@ src/
|
|
|
273
326
|
environment.tsx a codebase's environment
|
|
274
327
|
project.tsx a project's workspace
|
|
275
328
|
shelf.tsx Artifacts and Templates
|
|
329
|
+
nav.tsx the places, once, for every rail
|
|
276
330
|
customize/ Customize: the shell, then one file per tab
|
|
277
331
|
publish.tsx Add to project / Publish
|
|
278
332
|
find.tsx finding a run, by status, paged
|
package/lib/api/billing.d.ts
CHANGED
|
@@ -15,6 +15,10 @@
|
|
|
15
15
|
* GET /v1/billing/invoices/{id}/pdf the invoice as a PDF
|
|
16
16
|
* GET /v1/billing/balance prepaid balance, whole cents
|
|
17
17
|
* GET /v1/billing/credit-balance granted credit, per currency
|
|
18
|
+
* GET /v1/billing/credits {grants}: every grant, spent and lapsed included
|
|
19
|
+
* GET /v1/billing/tier the rung served and its tier class
|
|
20
|
+
* GET /v1/billing/recharge the auto-reload rule
|
|
21
|
+
* PUT /v1/billing/recharge arm it (a card on file) or disarm it
|
|
18
22
|
* POST /v1/billing/topup charge a saved card into the balance
|
|
19
23
|
* GET /v1/billing/usage/rollup the plan's month: included spend and request windows
|
|
20
24
|
* GET /v1/usage/summary?range=month this month's spend, by category
|
|
@@ -167,6 +171,41 @@ export declare function pdf(t: Target, id: string): Promise<Blob>;
|
|
|
167
171
|
export declare function balance(t: Target): Promise<number>;
|
|
168
172
|
/** Granted credit the org can spend, in US cents. */
|
|
169
173
|
export declare function credit(t: Target): Promise<number>;
|
|
174
|
+
/** One grant of credit, spent, lapsed and voided included: the ledger, not the spendable figure. */
|
|
175
|
+
export interface Grant {
|
|
176
|
+
id: string;
|
|
177
|
+
name: string;
|
|
178
|
+
amount: number;
|
|
179
|
+
remaining: number;
|
|
180
|
+
currency: string;
|
|
181
|
+
/** RFC 3339, or '' for one that does not lapse. */
|
|
182
|
+
expires: string;
|
|
183
|
+
active: boolean;
|
|
184
|
+
}
|
|
185
|
+
export declare function grants(t: Target): Promise<Grant[]>;
|
|
186
|
+
/** The rung an organization is served as (`max-20x`, '' with none) and the tier class it is served under (`pro`). */
|
|
187
|
+
export interface Tier {
|
|
188
|
+
plan: string;
|
|
189
|
+
tier: string;
|
|
190
|
+
}
|
|
191
|
+
export declare function tier(t: Target): Promise<Tier>;
|
|
192
|
+
/** Auto-reload: top the balance up by `amount` whenever it falls below `threshold`, charging the card on file. */
|
|
193
|
+
export interface Recharge {
|
|
194
|
+
enabled: boolean;
|
|
195
|
+
threshold: number;
|
|
196
|
+
amount: number;
|
|
197
|
+
currency: string;
|
|
198
|
+
/** RFC 3339 of the last reload, or ''. */
|
|
199
|
+
last: string;
|
|
200
|
+
}
|
|
201
|
+
/** The rule as stored; one never set reads as off. */
|
|
202
|
+
export declare function recharge(t: Target): Promise<Recharge>;
|
|
203
|
+
/** Arm or disarm the rule. Turning it on needs a card on file, and the platform says so when there is none. */
|
|
204
|
+
export declare function arm(t: Target, rule: {
|
|
205
|
+
enabled: boolean;
|
|
206
|
+
threshold: number;
|
|
207
|
+
amount: number;
|
|
208
|
+
}): Promise<Recharge>;
|
|
170
209
|
/** Charge a saved card and add the amount to the balance; answers the balance after. */
|
|
171
210
|
export declare function topup(t: Target, amount: number, card: string): Promise<number>;
|
|
172
211
|
export interface Window {
|
package/lib/api/billing.js
CHANGED
|
@@ -15,6 +15,10 @@
|
|
|
15
15
|
* GET /v1/billing/invoices/{id}/pdf the invoice as a PDF
|
|
16
16
|
* GET /v1/billing/balance prepaid balance, whole cents
|
|
17
17
|
* GET /v1/billing/credit-balance granted credit, per currency
|
|
18
|
+
* GET /v1/billing/credits {grants}: every grant, spent and lapsed included
|
|
19
|
+
* GET /v1/billing/tier the rung served and its tier class
|
|
20
|
+
* GET /v1/billing/recharge the auto-reload rule
|
|
21
|
+
* PUT /v1/billing/recharge arm it (a card on file) or disarm it
|
|
18
22
|
* POST /v1/billing/topup charge a saved card into the balance
|
|
19
23
|
* GET /v1/billing/usage/rollup the plan's month: included spend and request windows
|
|
20
24
|
* GET /v1/usage/summary?range=month this month's spend, by category
|
|
@@ -255,6 +259,43 @@ export async function credit(t) {
|
|
|
255
259
|
.filter((b) => (str(b.currency) || 'usd').toLowerCase() === 'usd')
|
|
256
260
|
.reduce((sum, b) => sum + num(b.available), 0);
|
|
257
261
|
}
|
|
262
|
+
export async function grants(t) {
|
|
263
|
+
const raw = obj(await call(t, 'GET', '/v1/billing/credits'));
|
|
264
|
+
return arr(raw.grants)
|
|
265
|
+
.map(obj)
|
|
266
|
+
.map((g) => ({
|
|
267
|
+
id: str(g.id),
|
|
268
|
+
name: str(g.name),
|
|
269
|
+
amount: num(g.amountCents),
|
|
270
|
+
remaining: num(g.remainingCents),
|
|
271
|
+
currency: str(g.currency) || 'usd',
|
|
272
|
+
expires: str(g.expiresAt),
|
|
273
|
+
active: g.active === true && g.voided !== true,
|
|
274
|
+
}))
|
|
275
|
+
.filter((g) => g.id);
|
|
276
|
+
}
|
|
277
|
+
export async function tier(t) {
|
|
278
|
+
const r = obj(await call(t, 'GET', '/v1/billing/tier'));
|
|
279
|
+
return { plan: str(r.plan), tier: str(obj(r.tier).name) };
|
|
280
|
+
}
|
|
281
|
+
function recharged(raw) {
|
|
282
|
+
const r = obj(raw);
|
|
283
|
+
return {
|
|
284
|
+
enabled: r.enabled === true,
|
|
285
|
+
threshold: num(r.thresholdCents),
|
|
286
|
+
amount: num(r.amountCents),
|
|
287
|
+
currency: str(r.currency) || 'usd',
|
|
288
|
+
last: str(r.lastRechargedAt),
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
/** The rule as stored; one never set reads as off. */
|
|
292
|
+
export async function recharge(t) {
|
|
293
|
+
return recharged(await call(t, 'GET', '/v1/billing/recharge'));
|
|
294
|
+
}
|
|
295
|
+
/** Arm or disarm the rule. Turning it on needs a card on file, and the platform says so when there is none. */
|
|
296
|
+
export async function arm(t, rule) {
|
|
297
|
+
return recharged(await call(t, 'PUT', '/v1/billing/recharge', { enabled: rule.enabled, thresholdCents: rule.threshold, amountCents: rule.amount, currency: 'usd' }));
|
|
298
|
+
}
|
|
258
299
|
/** Charge a saved card and add the amount to the balance; answers the balance after. */
|
|
259
300
|
export async function topup(t, amount, card) {
|
|
260
301
|
if (!Number.isInteger(amount) || amount <= 0)
|
package/lib/api/coding.d.ts
CHANGED
|
@@ -50,8 +50,11 @@ export interface Ask {
|
|
|
50
50
|
/** An earlier run's session to continue from, on the branch it pushed. */
|
|
51
51
|
after?: string;
|
|
52
52
|
mode?: Mode;
|
|
53
|
+
/** The model the agent thinks with, by the id GET /v1/models lists; Enso is sent as itself. */
|
|
53
54
|
model?: string;
|
|
54
55
|
effort?: string;
|
|
56
|
+
/** The number of the issue on `repo` this run resolves: its pull request says `Closes #<n>`. */
|
|
57
|
+
issue?: number;
|
|
55
58
|
}
|
|
56
59
|
export interface Run {
|
|
57
60
|
session: string;
|
|
@@ -65,7 +68,7 @@ export interface Run {
|
|
|
65
68
|
* A run in the sandbox asks for one with a desktop, so its Desktop tab has a
|
|
66
69
|
* screen to show; a machine is whatever it is.
|
|
67
70
|
*/
|
|
68
|
-
export declare function body(ask: Ask): Record<string, string | boolean>;
|
|
71
|
+
export declare function body(ask: Ask): Record<string, string | number | boolean>;
|
|
69
72
|
export declare function start(t: Target, ask: Ask): Promise<Run>;
|
|
70
73
|
/** A run a follow-up continues, as its record states it. */
|
|
71
74
|
export interface Earlier {
|
package/lib/api/coding.js
CHANGED
package/lib/api/environment.d.ts
CHANGED
|
@@ -37,6 +37,18 @@ export interface Environment {
|
|
|
37
37
|
updated: string;
|
|
38
38
|
}
|
|
39
39
|
export declare function environment(raw: unknown, repo?: string): Environment;
|
|
40
|
+
/**
|
|
41
|
+
* Whether a codebase still waits to be set up: nothing proposed and nothing ever
|
|
42
|
+
* saved. Skip & save keeps an empty environment, which the platform answers as
|
|
43
|
+
* state `none` with the time it was saved (apps/environment `view`), so the
|
|
44
|
+
* time is what tells a choice made from one never made.
|
|
45
|
+
*/
|
|
46
|
+
export declare const unset: (e: Environment) => boolean;
|
|
47
|
+
/**
|
|
48
|
+
* What a refused save or setup run says to the person who pressed it: what is
|
|
49
|
+
* wrong and what to do, in the reader's words rather than the platform's.
|
|
50
|
+
*/
|
|
51
|
+
export declare function plain(e: unknown, repo: string, act: 'save' | 'start' | 'run'): string;
|
|
40
52
|
export declare function environments(t: Target): Promise<Environment[]>;
|
|
41
53
|
export declare function read(t: Target, repo: string): Promise<Environment>;
|
|
42
54
|
export declare function save(t: Target, repo: string, scripts: {
|
package/lib/api/environment.js
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* here as `proposal` until someone saves it. Secrets are names only; their values
|
|
15
15
|
* are sealed in KMS and reach the run's environment, never this record.
|
|
16
16
|
*/
|
|
17
|
-
import { call, seg } from './call.js';
|
|
17
|
+
import { call, Refusal, seg } from './call.js';
|
|
18
18
|
const str = (v) => (typeof v === 'string' ? v : '');
|
|
19
19
|
const obj = (v) => (v && typeof v === 'object' ? v : {});
|
|
20
20
|
const names = (v) => (Array.isArray(v) ? v.filter((n) => typeof n === 'string' && n !== '') : []);
|
|
@@ -34,6 +34,44 @@ export function environment(raw, repo = '') {
|
|
|
34
34
|
updated: str(o.updatedAt),
|
|
35
35
|
};
|
|
36
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* Whether a codebase still waits to be set up: nothing proposed and nothing ever
|
|
39
|
+
* saved. Skip & save keeps an empty environment, which the platform answers as
|
|
40
|
+
* state `none` with the time it was saved (apps/environment `view`), so the
|
|
41
|
+
* time is what tells a choice made from one never made.
|
|
42
|
+
*/
|
|
43
|
+
export const unset = (e) => e.state === 'none' && !e.updated;
|
|
44
|
+
/**
|
|
45
|
+
* What a refused save or setup run says to the person who pressed it: what is
|
|
46
|
+
* wrong and what to do, in the reader's words rather than the platform's.
|
|
47
|
+
*/
|
|
48
|
+
export function plain(e, repo, act) {
|
|
49
|
+
// This page's own refusals (a secret's name, an empty value) are already a reader's words.
|
|
50
|
+
if (e instanceof Error && !(e instanceof Refusal) && e.name === 'Error' && e.message)
|
|
51
|
+
return e.message;
|
|
52
|
+
if (e instanceof Refusal) {
|
|
53
|
+
const why = e.message;
|
|
54
|
+
if (e.status === 401)
|
|
55
|
+
return 'Your session ended. Sign in again, then try again.';
|
|
56
|
+
if (e.status === 403 && act === 'save')
|
|
57
|
+
return 'Only an organization admin saves an environment. Start the agent instead; an admin reviews what it proposes.';
|
|
58
|
+
if (e.status === 402)
|
|
59
|
+
return 'This run needs a plan with runs left. See Plans to change it.';
|
|
60
|
+
if (e.status === 403)
|
|
61
|
+
return `This account cannot start a run on ${repo}. Ask an organization admin for access.`;
|
|
62
|
+
if (e.status === 429)
|
|
63
|
+
return 'Too many runs are going right now. Try again in a minute.';
|
|
64
|
+
if (e.status >= 500)
|
|
65
|
+
return act === 'save' ? 'The environment store is not answering right now. Try again shortly.' : 'The code workspace is not answering right now. Try again shortly.';
|
|
66
|
+
if (/no repository named|not one of this organization|is not a repository/.test(why))
|
|
67
|
+
return `${repo} is not a repository this organization has on the forge. Choose one of its repositories.`;
|
|
68
|
+
if (/no account on the forge|verify .* first|no forge identity/.test(why))
|
|
69
|
+
return 'Your forge account is not ready yet: sign in to the forge once, then try again.';
|
|
70
|
+
}
|
|
71
|
+
if (act === 'save')
|
|
72
|
+
return `The environment for ${repo} could not be saved. Try again.`;
|
|
73
|
+
return act === 'start' ? `The setup run on ${repo} could not start. Try again.` : `The run on ${repo} could not start. Try again.`;
|
|
74
|
+
}
|
|
37
75
|
export async function environments(t) {
|
|
38
76
|
const r = await call(t, 'GET', '/v1/environment');
|
|
39
77
|
return (Array.isArray(r?.data) ? r.data : []).map((e) => environment(e)).filter((e) => e.repo);
|
package/lib/api/github.d.ts
CHANGED
|
@@ -32,6 +32,8 @@ export interface Repo {
|
|
|
32
32
|
pushed_at: string;
|
|
33
33
|
/** The App installation that grants access, or 0 for the person's own grant. */
|
|
34
34
|
installation_id: number;
|
|
35
|
+
/** The name it takes on the forge once brought there: `owner_name`, folded. */
|
|
36
|
+
codebase: string;
|
|
35
37
|
}
|
|
36
38
|
export interface Repos {
|
|
37
39
|
repos: Repo[];
|
|
@@ -106,9 +108,11 @@ export interface Grant {
|
|
|
106
108
|
fullName: string;
|
|
107
109
|
private: boolean;
|
|
108
110
|
branch: string;
|
|
109
|
-
/**
|
|
111
|
+
/** The name it takes on the forge once brought there. */
|
|
112
|
+
codebase: string;
|
|
113
|
+
/** On the forge: linked and landed, or held there under its codebase name. */
|
|
110
114
|
imported: boolean;
|
|
111
|
-
/** `synced`, `conflict`, or '' while it
|
|
115
|
+
/** `synced`, `conflict`, `pending`, `paused`, or '' while it is not linked. */
|
|
112
116
|
status: string;
|
|
113
117
|
}
|
|
114
118
|
export interface Grants {
|
|
@@ -122,13 +126,29 @@ export interface Account {
|
|
|
122
126
|
/** Named as unread and carrying no repositories. */
|
|
123
127
|
blocked: boolean;
|
|
124
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* One row of GET /v1/provider/github/repos (apps/provider github_index.go
|
|
131
|
+
* repoView): `owner`, `name`, `full_name`, `private`, `default_branch`,
|
|
132
|
+
* `pushed_at`, `installation_id`, `codebase`. Whether it is on the forge is not
|
|
133
|
+
* in the row — `codebase` is the name it would take, not a sign it has — so
|
|
134
|
+
* `imported` is decided by `grants` from the links and the forge.
|
|
135
|
+
*/
|
|
125
136
|
export declare function grant(raw: unknown): Grant | null;
|
|
126
137
|
/** Accounts the grant names, plus any account that could not be read. */
|
|
127
138
|
export declare function accounts(g: Grants): Account[];
|
|
128
|
-
/**
|
|
139
|
+
/**
|
|
140
|
+
* Every repository the GitHub connection grants, every page, with whether the
|
|
141
|
+
* forge already has it: a link that has landed (GET /v1/sync, its `native`
|
|
142
|
+
* state), or a forge repository under its codebase name (GET /v1/git/repos).
|
|
143
|
+
*/
|
|
129
144
|
export declare function grants(t: Target, signal?: AbortSignal): Promise<Grants>;
|
|
145
|
+
/** What an import queued: how many, and the name each takes on the forge, by `owner/name`. */
|
|
146
|
+
export interface Queued {
|
|
147
|
+
queued: number;
|
|
148
|
+
codebases: Record<string, string>;
|
|
149
|
+
}
|
|
130
150
|
/** Queue a mirror of the named repositories onto the forge. The names are `owner/name`. */
|
|
131
|
-
export declare function bring(t: Target, repos: string[]): Promise<
|
|
151
|
+
export declare function bring(t: Target, repos: string[]): Promise<Queued>;
|
|
132
152
|
/** What one issue sync did. */
|
|
133
153
|
export interface Synced {
|
|
134
154
|
repos: number;
|