@jc_stack/ez-agents 0.1.0-beta.27 → 0.1.0-beta.28
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/.env.example +9 -0
- package/AGENTS.md +25 -1
- package/CHANGELOG.md +23 -0
- package/CONTRIBUTING.md +28 -0
- package/Dockerfile +1 -0
- package/README.md +79 -8
- package/bin/ezenciel-agents-application +2 -0
- package/bin/ezenciel-agents-application.mjs +16 -0
- package/compose.yaml +8 -0
- package/docker/entrypoint.sh +20 -2
- package/docker/healthcheck.mjs +1 -1
- package/docker/run.ts +3 -3
- package/docker/smoke.mjs +41 -2
- package/docs/application-channel.md +366 -0
- package/docs/docker-runtime.md +20 -0
- package/docs/managed-applications.md +68 -0
- package/docs/plugin-catalog.md +1 -0
- package/docs/plugin-connection.md +76 -0
- package/docs/plugins.md +40 -4
- package/docs/upgrades.md +11 -1
- package/package.json +7 -2
- package/src/application-channel.ts +308 -0
- package/src/application-cli.ts +41 -0
- package/src/application-client.mjs +87 -0
- package/src/application-origin.ts +15 -0
- package/src/codex-session.ts +5 -3
- package/src/config.ts +20 -2
- package/src/control-state.ts +256 -15
- package/src/conversation-menu.ts +89 -0
- package/src/delivery-context.d.mts +5 -0
- package/src/delivery-context.mjs +25 -0
- package/src/event-sources.ts +2 -2
- package/src/execution-authority.ts +2 -0
- package/src/executor.ts +10 -4
- package/src/host-executor.ts +7 -1
- package/src/identity.ts +11 -3
- package/src/index.ts +149 -54
- package/src/menu.ts +26 -9
- package/src/message-history.ts +52 -0
- package/src/message.ts +48 -7
- package/src/owner.ts +7 -1
- package/src/plugins/connection-artifacts.mjs +31 -0
- package/src/plugins/connection.mjs +124 -0
- package/src/plugins/manager.mjs +63 -18
- package/src/plugins/native-tasks.d.mts +4 -0
- package/src/plugins/native-tasks.mjs +66 -0
- package/src/plugins/workspace-lease.d.mts +3 -0
- package/src/plugins/workspace-lease.mjs +44 -0
- package/src/runs.ts +67 -9
- package/src/schedule-cli.ts +11 -6
- package/src/scheduler.ts +17 -7
- package/src/updates/control.mjs +4 -0
- package/src/web-launcher.ts +19 -0
- package/templates/agent-guidance.md +58 -2
- package/templates/deployments.md +24 -0
- package/test/application-channel.test.ts +283 -0
- package/test/application-client.test.mjs +84 -0
- package/test/application-controls.test.ts +224 -0
- package/test/application-only.test.ts +100 -0
- package/test/channel-delivery.test.ts +63 -0
- package/test/channel-owner.test.ts +161 -0
- package/test/codex-session.test.ts +8 -5
- package/test/config.test.ts +15 -0
- package/test/connection-artifacts.test.mjs +32 -0
- package/test/conversation-menu.test.ts +67 -0
- package/test/conversations.test.ts +84 -0
- package/test/executor.test.ts +56 -0
- package/test/host-executor.test.ts +28 -0
- package/test/intake-relay.test.ts +126 -5
- package/test/message-history.test.ts +127 -0
- package/test/native-tasks.test.ts +36 -0
- package/test/plugin-connection.test.mjs +124 -0
- package/test/plugin-manager.test.mjs +34 -0
- package/test/runtime-identity.test.mjs +18 -0
- package/test/updates.test.mjs +39 -0
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
# Application input to the standard agent
|
|
2
|
+
|
|
3
|
+
An installed application can submit work to the ordinary Ez agent. Ez uses its
|
|
4
|
+
existing run queue, native executor, session store, cancellation and message
|
|
5
|
+
outbox. The application supplies domain tools and keeps its UI/content API; it
|
|
6
|
+
can remove its own model runner, continuation loop and engine authentication.
|
|
7
|
+
This is separate from the older outbound channel-backend integration.
|
|
8
|
+
|
|
9
|
+
## Shared runtime controls
|
|
10
|
+
|
|
11
|
+
Register with `--share-owner` (the existing `--share-telegram` spelling is an
|
|
12
|
+
alias) to grant access to the runtime's active conversation and standard AI
|
|
13
|
+
settings. This explicit grant works with or without a Telegram bot. It grants
|
|
14
|
+
control of the same active state Telegram uses when enabled; it is not a
|
|
15
|
+
scope-only permission. Ordinary application bindings cannot read or change it.
|
|
16
|
+
|
|
17
|
+
`GET /v1/control` returns the existing Ez AI presets, installed native model
|
|
18
|
+
catalog, active control-session ID and conversations visible through `/chats`.
|
|
19
|
+
Native engine session IDs and private application scopes are omitted. The token
|
|
20
|
+
stays in the authenticated application backend, never in browser code.
|
|
21
|
+
|
|
22
|
+
`POST /v1/control` accepts one action and the `expectedSession` returned by the
|
|
23
|
+
last read (null before a conversation exists):
|
|
24
|
+
|
|
25
|
+
| Action | Additional fields | Existing Ez operation |
|
|
26
|
+
| --- | --- | --- |
|
|
27
|
+
| `new` | None | `/new`, using the default AI |
|
|
28
|
+
| `switch` | `sessionId` from the visible conversation list | `/chats` selection |
|
|
29
|
+
| `select` | `presetId` from `ai.presets` | Select a saved AI |
|
|
30
|
+
| `model` | `cli`, optional `model` and `effort`, from `models` | Save/select the same native choice as `/ai` |
|
|
31
|
+
|
|
32
|
+
Engine changes start a fresh conversation through the same selection operation
|
|
33
|
+
as Telegram. A changed active conversation rejects a stale mutation; refresh
|
|
34
|
+
controls before another attempt. Model changes within one conversation retain
|
|
35
|
+
the ordinary last-selection-wins behavior. Already-admitted runs keep their
|
|
36
|
+
captured conversation and AI. Uncertain control responses require a fresh read,
|
|
37
|
+
not blind repetition of `/new`.
|
|
38
|
+
|
|
39
|
+
For private application conversations, `GET /v1/scope-control?scope=<encoded-scope>` returns
|
|
40
|
+
the same catalog and the current scope's public control ID and preset. The scope
|
|
41
|
+
is the application's original admission scope, resolved under its authenticated
|
|
42
|
+
binding. `POST` accepts `new`, `select` and `model` with that scope's
|
|
43
|
+
`expectedSession`. It does not require shared-control permission. Shared scopes
|
|
44
|
+
must use `/v1/control` instead.
|
|
45
|
+
|
|
46
|
+
A scope reset uses the configured default AI. A client change starts a fresh
|
|
47
|
+
private conversation; a model change within the same client retains it. Retired
|
|
48
|
+
private conversations stay hidden from `/chats`; admitted work can finish in its
|
|
49
|
+
original native session. Neither operation changes the shared active selection.
|
|
50
|
+
Control mutations are never marked retryable by the public client: read back
|
|
51
|
+
after uncertainty before deciding on another change.
|
|
52
|
+
|
|
53
|
+
Current HTTP gaps: rename/archive, scheduling
|
|
54
|
+
administration and shared-chat stop-all are not exposed here. Per-run application
|
|
55
|
+
cancellation remains available. The native agent can use the standard scheduler
|
|
56
|
+
from an application turn; its replies retain that channel binding.
|
|
57
|
+
|
|
58
|
+
## Install and authorize
|
|
59
|
+
|
|
60
|
+
An installation has one owner, independent of its channels. As the installing
|
|
61
|
+
administrator, outside an agent turn, generate a random 32-byte base64url token
|
|
62
|
+
into a private file and register the first channel with a verified opaque owner ID:
|
|
63
|
+
|
|
64
|
+
```sh
|
|
65
|
+
ezenciel-agents-application --owner-id verified-account --id web --token-file /private/web-token --share-owner
|
|
66
|
+
ezenciel-agents-application --id phone --token-file /private/phone-token --share-owner
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The application backend receives that token through its secret store. Core stores
|
|
70
|
+
only its SHA-256 digest, bound to the installation owner. Channel IDs are arbitrary
|
|
71
|
+
labels, not a predefined provider list. The trusted adapter verifies its provider's
|
|
72
|
+
identity (for example Privy); a browser-supplied owner ID is never authentication.
|
|
73
|
+
For an existing Telegram owner, omit `--owner-id`: the new channel attaches to that
|
|
74
|
+
same owner. `GET /v1/registration` returns the owner ID and binding ID.
|
|
75
|
+
Revoke a channel with `--id web --revoke`. Rotate with `--id web --token-file
|
|
76
|
+
/private/new-token --rotate`: the binding ID, retries and native sessions remain
|
|
77
|
+
unchanged. Revoking the installation owner invalidates every channel.
|
|
78
|
+
Revocation blocks admission, results and delivery and stops an active app run on
|
|
79
|
+
the existing queue tick. `--list` exposes IDs, never tokens or hashes.
|
|
80
|
+
|
|
81
|
+
This grant lets a **trusted application backend act for the paired owner**. It is
|
|
82
|
+
not a multi-tenant filesystem sandbox. The application authenticates its users,
|
|
83
|
+
derives their allowed scope, and enforces domain tool permissions. Independent
|
|
84
|
+
owners or untrusted applications need separate agents/workspaces. Scoped sessions
|
|
85
|
+
separate conversation history; they share the ordinary agent's filesystem and
|
|
86
|
+
tool authority. Do not give this bearer token to browser JavaScript or models.
|
|
87
|
+
|
|
88
|
+
Enable the optional listener in the relay environment:
|
|
89
|
+
|
|
90
|
+
```dotenv
|
|
91
|
+
EZ_APPLICATION_PORT=8787
|
|
92
|
+
EZ_APPLICATION_HOST=0.0.0.0
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
The default bind address is loopback. In Docker, put the relay and backend on a
|
|
96
|
+
private shared network and use `http://<relay-service>:8787`; do not publish a host
|
|
97
|
+
port. Cross-host use requires HTTPS or an authenticated private tunnel. There is
|
|
98
|
+
no listener unless a port is configured. This mode cannot be combined with the
|
|
99
|
+
older channel-backend URL. Install core normally: its bin manifest makes the
|
|
100
|
+
application administration command available through the standard tools setup.
|
|
101
|
+
|
|
102
|
+
## Request and result
|
|
103
|
+
|
|
104
|
+
All endpoints require `Authorization: Bearer <token>`.
|
|
105
|
+
|
|
106
|
+
```text
|
|
107
|
+
POST /v1/runs
|
|
108
|
+
{"requestId":"job-123","scope":"principal:program","text":"Prepare our next lesson","context":{"reference":"lesson-1"}}
|
|
109
|
+
|
|
110
|
+
GET /v1/runs/<id>
|
|
111
|
+
GET /v1/runs
|
|
112
|
+
GET /v1/registration
|
|
113
|
+
POST /v1/runs/<id>/cancel
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Submission returns HTTP 202; reads/cancellation return 200. Each response is:
|
|
117
|
+
|
|
118
|
+
```json
|
|
119
|
+
{"id":"r_app_...","scope":"principal:program","status":"queued","messages":[]}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Status is `queued`, `running`, `completed`, `failed` or `cancelled`. Messages are
|
|
123
|
+
`{id,text}` records sent by the native agent through the existing message CLI.
|
|
124
|
+
The backend polls and renders them; no raw native JSONL or Telegram messages are
|
|
125
|
+
exposed. A delivery receipt means durable availability in the application inbox,
|
|
126
|
+
not that a human read it. Failure adds a generic `error`; detailed logs remain
|
|
127
|
+
local to core. Cancellation uses the existing child termination boundary and may
|
|
128
|
+
return `running` until the process exits.
|
|
129
|
+
|
|
130
|
+
`requestId` and `scope` accept 1–200 ASCII letters, digits, `_:.-`. Text is at most
|
|
131
|
+
16,000 characters. Context is an optional JSON object (48 KiB); the complete HTTP
|
|
132
|
+
body is bounded to 64 KiB. Unknown input fields are rejected. Use a stable job ID:
|
|
133
|
+
retries with the same ID, scope and text return the original run and original
|
|
134
|
+
context, even if the caller supplies refreshed context. Changed scope/text is a
|
|
135
|
+
409 conflict. Persist the submitted context/capability for recovery, or poll the
|
|
136
|
+
original run; retries never grant replacement authority to an admitted run.
|
|
137
|
+
|
|
138
|
+
Context is opaque domain-tool data, not prompt text or an environment override.
|
|
139
|
+
The existing `ezenciel-agents-schedule context` exposes it as
|
|
140
|
+
`run.application.context` only to the current native run. Domain tools and their
|
|
141
|
+
filesystem mounts are installed using ordinary Ez plugin/runtime setup. No API
|
|
142
|
+
field selects a native session, working directory, process environment or owner.
|
|
143
|
+
This first version transports text only, without file delivery, reactions or
|
|
144
|
+
approval UI.
|
|
145
|
+
|
|
146
|
+
## Conversation continuity and migration
|
|
147
|
+
|
|
148
|
+
Each application binding plus scope gets an existing core session. Its first run
|
|
149
|
+
captures the selected engine/preset; later runs resume that same native session.
|
|
150
|
+
Application sessions are excluded from the Telegram session selector. Engines
|
|
151
|
+
that only resume an implicit latest session (`agy`) cannot serve isolated scopes.
|
|
152
|
+
|
|
153
|
+
Before cutting over an existing application, stop its old runner, copy its native
|
|
154
|
+
transcripts into the ordinary engine's private state, and import each authoritative
|
|
155
|
+
scope pointer as the administrator:
|
|
156
|
+
|
|
157
|
+
```sh
|
|
158
|
+
ezenciel-agents-application --id myapp --import-scope principal:program \
|
|
159
|
+
--native-session NATIVE_SESSION_ID --cli codex
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Do this before submitting work for that scope. Import does not copy transcripts,
|
|
163
|
+
change the model preset, or merge histories. Verify the next real native turn
|
|
164
|
+
recalls the intended history and the app renders its reply before removing the
|
|
165
|
+
old deployment. Keep exactly one executor owner throughout the cutover.
|
|
166
|
+
For an owner-chat channel registered with `--share-owner`, add `--share-owner`
|
|
167
|
+
to the import command to select that imported conversation as the owner's current
|
|
168
|
+
chat. Without it, the import remains scoped and does not switch owner chat.
|
|
169
|
+
|
|
170
|
+
## Reviewed deployment migration
|
|
171
|
+
|
|
172
|
+
The first upgrade adding the two optional application listener environment lines
|
|
173
|
+
changes `compose.yaml`. The existing updater deliberately rejects that runtime
|
|
174
|
+
shape change with “Runtime deployment changed; a separately reviewed migration is
|
|
175
|
+
required.” Keep this guard. Installation requires a separately reviewed deployment
|
|
176
|
+
migration before subsequent ordinary updates can use the new baseline.
|
|
177
|
+
|
|
178
|
+
The operator verifies the immutable archive's SHA-256, extracts it into a new
|
|
179
|
+
versioned package directory, copies `docker/pnpm-lock.yaml` to `pnpm-lock.yaml`,
|
|
180
|
+
and installs frozen dependencies **inside that package root**. Verify the new
|
|
181
|
+
application CLI and root-local `tsx` resolve. Build its runtime image without
|
|
182
|
+
stopping or changing the existing agent. Then the authorized deployment owner
|
|
183
|
+
switches the saved package/image binding using the standard host/update setup,
|
|
184
|
+
preserving the agent's existing workspace, control, native engine state, owner
|
|
185
|
+
pairing and plugin registry. Do not copy another agent's state or disable the
|
|
186
|
+
updater's deployment compatibility check.
|
|
187
|
+
|
|
188
|
+
For Docker applications, a deployment-owned overlay can attach the ordinary relay
|
|
189
|
+
to an explicitly created private network shared with the application backend:
|
|
190
|
+
|
|
191
|
+
```yaml
|
|
192
|
+
services:
|
|
193
|
+
relay:
|
|
194
|
+
environment:
|
|
195
|
+
EZ_APPLICATION_PORT: "8787"
|
|
196
|
+
EZ_APPLICATION_HOST: "0.0.0.0"
|
|
197
|
+
networks:
|
|
198
|
+
default: {}
|
|
199
|
+
application:
|
|
200
|
+
aliases: [standard-agent]
|
|
201
|
+
networks:
|
|
202
|
+
application:
|
|
203
|
+
external: true
|
|
204
|
+
name: ${EZ_APPLICATION_NETWORK:?Set the deployment-owned application network}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Create that network once through normal Docker administration; attach the backend
|
|
208
|
+
to the same external network in its own deployment overlay. Preserve the default
|
|
209
|
+
network. The backend connects to `http://standard-agent:8787`; no `ports` entry or
|
|
210
|
+
host listener is required. Keep the overlay outside the package, owned by the
|
|
211
|
+
deployment, and include it in that deployment's saved Compose invocation. This is
|
|
212
|
+
an explicit network configuration, not a second runtime or automatic discovery
|
|
213
|
+
service. Read back the loaded package/image and verify a real authenticated app
|
|
214
|
+
request after switching; preparation and image build alone are not rollout.
|
|
215
|
+
|
|
216
|
+
## Shared backend client and private principals
|
|
217
|
+
|
|
218
|
+
Node backends can import `applicationBinding`, `applicationCall`, and
|
|
219
|
+
`runApplication` from `@jc_stack/ez-agents/application-client`. This is a small
|
|
220
|
+
HTTP client; core remains the sole owner of agent execution. Pin the package
|
|
221
|
+
revision in the application's lockfile. Do not copy this client into each app.
|
|
222
|
+
|
|
223
|
+
`applicationBinding(file, principalId)` reads a backend-private registry:
|
|
224
|
+
|
|
225
|
+
```json
|
|
226
|
+
{"version":1,"bindings":[
|
|
227
|
+
{"principalId":"verified-person-one","url":"http://person-one-agent:8787","tokenFile":"/run/secrets/person-one"},
|
|
228
|
+
{"principalId":"verified-person-two","url":"http://person-two-agent:8787","tokenFile":"/run/secrets/person-two"}
|
|
229
|
+
]}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Resolve identity in the app before lookup. Unknown and revoked principals fail
|
|
233
|
+
closed. Set `revoked:true` to remove a mapping from new lookup and revoke its
|
|
234
|
+
core application grant to stop admitted work. Do not use a default owner's
|
|
235
|
+
connection. Each endpoint must be a separate ordinary Ez deployment with private
|
|
236
|
+
workspace, native CLI state, OS/container access and tools. The client rejects
|
|
237
|
+
reused endpoint origins, but cannot prove that two DNS aliases name different
|
|
238
|
+
containers. Provision isolation explicitly; this registry does not create it.
|
|
239
|
+
The backend's registry and service credentials must not be mounted in an agent.
|
|
240
|
+
|
|
241
|
+
The app keeps its existing user and coach/tutor grants. A delegated principal
|
|
242
|
+
must be distinct from the learner's personal principal, and every domain tool
|
|
243
|
+
must recheck the current grant. A coach can edit permitted learner records
|
|
244
|
+
without inheriting the learner's private agent conversation. No new role system
|
|
245
|
+
is required in Ez.
|
|
246
|
+
|
|
247
|
+
Use `runApplication({requestId,scope,text,context}, connection)`. It returns the
|
|
248
|
+
completed snapshot plus `reply`, the last nonempty message. An interrupted or
|
|
249
|
+
invalid HTTP response reports a retryable transport error; the caller reconnects
|
|
250
|
+
using the same persisted job ID and authority. The client does not resubmit by
|
|
251
|
+
itself. `applicationCall('/v1/runs/<id>/cancel', {}, connection)` uses normal
|
|
252
|
+
core cancellation. Aborting a local poll does not cancel admitted work.
|
|
253
|
+
|
|
254
|
+
Snapshots also expose `sessionId`, `nativeSessionId` when known, and `cli`.
|
|
255
|
+
An optional `expectedNativeSessionId` on submission is an assertion, never a
|
|
256
|
+
session selector. It rejects a missing or different imported history before
|
|
257
|
+
execution. Import old histories administratively before cutover. An optional
|
|
258
|
+
`ai:{cli,model,effort}` uses the existing preset/effort contract; a scope keeps its
|
|
259
|
+
CLI, while model/effort can change for later turns. Use distinct scopes for
|
|
260
|
+
separate CLI histories. A retry cannot change an admitted turn's AI choice.
|
|
261
|
+
|
|
262
|
+
## One owner across channels
|
|
263
|
+
|
|
264
|
+
Register owner-chat channels with `--share-owner` and submit `followOwner:true`.
|
|
265
|
+
Web, phone and Telegram then use the same selected native conversation and AI.
|
|
266
|
+
This works without Telegram and requires no transcript replay or new runner.
|
|
267
|
+
Scoped application conversations remain separate when the flag is omitted.
|
|
268
|
+
Owner identity does not automatically merge histories or grant learner access.
|
|
269
|
+
|
|
270
|
+
To link Telegram, enable its ordinary bot configuration, send a real DM, then
|
|
271
|
+
approve the observed pending identity using `ezenciel-agents-owner approve ID`.
|
|
272
|
+
`ezenciel-agents-owner unlink-telegram` removes that channel without removing the
|
|
273
|
+
owner, application bindings or native sessions. Relinking does not authorize old
|
|
274
|
+
Telegram deliveries. Linking other providers requires an authenticated adapter;
|
|
275
|
+
registering the label `phone` does not install a phone service.
|
|
276
|
+
|
|
277
|
+
The legacy `--share-telegram`, `--share-active` and `followTelegram:true` spellings remain supported.
|
|
278
|
+
|
|
279
|
+
### Existing scoped Telegram sharing
|
|
280
|
+
|
|
281
|
+
For an application using the ordinary agent's Telegram channel, the administrator
|
|
282
|
+
may register its grant with `--share-telegram`. An ordinary application turn can
|
|
283
|
+
then send `activateTelegram:true`: its scoped session becomes the owner's current
|
|
284
|
+
Telegram conversation. Both inputs resume the same native history. Shared scopes
|
|
285
|
+
appear in the existing `/chats` selector. Omit activation for temporary selection,
|
|
286
|
+
extraction, and delegated work; those must not switch the personal conversation.
|
|
287
|
+
Without the administrator's flag, application requests cannot switch Telegram.
|
|
288
|
+
|
|
289
|
+
For a main chat that should follow the owner's current Telegram conversation,
|
|
290
|
+
submit `followTelegram:true` under the same administrator-approved sharing grant.
|
|
291
|
+
This uses the normal selected conversation and AI at admission, including after
|
|
292
|
+
`/new`, `/chats`, or `/ai`. Do not also send `activateTelegram`, `ai`, or a native
|
|
293
|
+
session assertion. Retries remain pinned to their originally admitted run even
|
|
294
|
+
if the owner has since switched conversations. Keep exercise/detail scopes on
|
|
295
|
+
the ordinary scoped path by omitting this flag.
|
|
296
|
+
|
|
297
|
+
This shares native context, not an application's transcript database. Existing
|
|
298
|
+
Telegram-to-backend integrations are a legacy limitation. Drain/reconcile their
|
|
299
|
+
actual admitted runs before moving Telegram onto ordinary Ez transport and app
|
|
300
|
+
admission onto this path. Do not introduce an application execution queue or
|
|
301
|
+
route a channel-backend job into its own occupied execution queue.
|
|
302
|
+
|
|
303
|
+
For backends holding a data lock across a native turn, `reconnect:true` keeps
|
|
304
|
+
retrying transient transport failures with the same admitted request/GET until
|
|
305
|
+
core reports the outcome. It never changes a job or capability. Do not apply a
|
|
306
|
+
wall-clock abort that releases the data lock while remote execution continues.
|
|
307
|
+
Persist a restart barrier before admission if backend restart could otherwise
|
|
308
|
+
allow conflicting domain writes. Core remains the execution owner.
|
|
309
|
+
|
|
310
|
+
A rejected submission includes `admitted:false` only when core can verify that
|
|
311
|
+
no run exists for that binding/request ID. An existing conflicting run produces
|
|
312
|
+
`admitted:true` and `runId`. Authentication or unreadable state may leave admission
|
|
313
|
+
unknown. Backends may release a pending data barrier on explicit non-admission;
|
|
314
|
+
a generic HTTP error or revoked credential alone is not proof of termination.
|
|
315
|
+
|
|
316
|
+
## Application-only deployment (no Telegram bot)
|
|
317
|
+
|
|
318
|
+
For a private per-user native runtime, set `EZ_TELEGRAM_ENABLED=false` and
|
|
319
|
+
`EZ_APPLICATION_PORT` (plus `EZ_APPLICATION_HOST` when other containers connect).
|
|
320
|
+
No bot token is required or used. This mode runs the existing native executor,
|
|
321
|
+
application queue and application outbox without creating a Telegram client,
|
|
322
|
+
starting Telegram sources/polling, or registering bot commands. Default deployments
|
|
323
|
+
still enable Telegram and require its token.
|
|
324
|
+
|
|
325
|
+
The installing administrator can initialize empty control authority and register
|
|
326
|
+
an application in one local command:
|
|
327
|
+
|
|
328
|
+
```sh
|
|
329
|
+
ezenciel-agents-application --id web --token-file /run/private/application-token --owner-id VERIFIED_ACCOUNT_ID --share-owner
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
No Telegram ID is required or fabricated. Account identity remains server-resolved
|
|
333
|
+
by the app and bound to its isolated runtime. Registration is unavailable inside
|
|
334
|
+
agent turns and cannot replace an existing owner or adopt orphaned session state.
|
|
335
|
+
Existing owners require no bootstrap. Tokens remain private; normal binding and
|
|
336
|
+
run authorization checks still apply. The old numeric `--owner` option is retained
|
|
337
|
+
only for compatibility, not recommended for new installations.
|
|
338
|
+
|
|
339
|
+
Each learner/coach principal requires its own workspace, CLI state and isolated
|
|
340
|
+
runtime. No separate bot is required. A channel is an authenticated route to its
|
|
341
|
+
existing owner, not a new owner, scheduler or native execution engine.
|
|
342
|
+
|
|
343
|
+
The standard scheduler, task controls and native delegation remain available.
|
|
344
|
+
Schedules created during an application turn retain its binding and reply scope;
|
|
345
|
+
scheduled replies use the normal outbox and appear in `GET /v1/runs` (100 channel
|
|
346
|
+
runs per page), with their `originRunId`. Follow `nextCursor` through
|
|
347
|
+
`GET /v1/runs?before=RUN_ID` until null to catch up after a disconnect; receipts
|
|
348
|
+
from older origins must not be limited to the UI's current page. The backend projects these receipts into
|
|
349
|
+
its UI; it does not schedule or execute work. Revoked channels cannot launch or
|
|
350
|
+
receive scheduled work. Token rotation retains delivery. Telegram-specific intake
|
|
351
|
+
and delivery require Telegram; pending Telegram work is never rerouted to web.
|
|
352
|
+
|
|
353
|
+
When a private container supplies the isolation boundary and
|
|
354
|
+
Codex cannot create its nested sandbox, its installing administrator may set
|
|
355
|
+
`EZ_CODEX_SANDBOX=external` together with `EZ_EXECUTOR_TRANSPORT=local`.
|
|
356
|
+
Local owner-authorized Codex app and Telegram turns use
|
|
357
|
+
`--sandbox danger-full-access`. Native scheduled owner sessions use Codex's
|
|
358
|
+
`externalSandbox` turn policy, with network access supplied by the container.
|
|
359
|
+
The default remains `workspace-write`.
|
|
360
|
+
Keep the container's private mounts, non-root UID, dropped capabilities and
|
|
361
|
+
no-new-privileges policy; the agent can access everything mounted into it.
|
|
362
|
+
Use standard root-start relay privilege separation when Telegram/provider
|
|
363
|
+
secrets are present; do not put those secrets in a same-UID process environment
|
|
364
|
+
or readable mount. This setting is rejected for host/backend execution and
|
|
365
|
+
restricted delegated tasks, and cannot be selected by an application request.
|
|
366
|
+
It is not forwarded to the host executor.
|
package/docs/docker-runtime.md
CHANGED
|
@@ -4,6 +4,11 @@ Docker Compose owns each relay and executable plugin. The CLI the user installs
|
|
|
4
4
|
Ez from stays on the host, with its existing authentication. All agents in that
|
|
5
5
|
installation use that CLI; there is no second CLI installation or agent-specific
|
|
6
6
|
CLI login. The relay image contains Node, relay dependencies and ffmpeg.
|
|
7
|
+
The runtime image exposes Ez commands through the wrappers in `/app/bin`, including
|
|
8
|
+
`ezenciel-agents-application`; application images do not need to link Ez themselves.
|
|
9
|
+
The image also installs package-manifest commands in `/usr/local/bin`, so native
|
|
10
|
+
engine login shells can resolve them after resetting PATH. Command installation
|
|
11
|
+
belongs to Ez packaging, not an application image or an engine-specific prompt.
|
|
7
12
|
|
|
8
13
|
## Agent binding
|
|
9
14
|
|
|
@@ -46,6 +51,21 @@ between jobs after adding a registry binding.
|
|
|
46
51
|
|
|
47
52
|
## Operate and verify
|
|
48
53
|
|
|
54
|
+
Root-started containers default to executor UID/GID `1000:1000` and relay real
|
|
55
|
+
UID `1001`. To preserve an existing private workspace's ownership, set
|
|
56
|
+
`EZ_RUNTIME_UID`, `EZ_RUNTIME_GID` and, if necessary, `EZ_RELAY_UID` in the
|
|
57
|
+
deployment environment. IDs must be positive decimal integers; the relay real
|
|
58
|
+
UID must differ from the executor UID. The entrypoint retains its secret file
|
|
59
|
+
descriptor and privilege separation, then runs the executor with the configured
|
|
60
|
+
UID. It changes ownership only on the top-level control, home and workspace
|
|
61
|
+
directories; it does not recursively change existing data. Provision nested
|
|
62
|
+
files/mounts for that UID before starting. These settings apply to root startup;
|
|
63
|
+
an explicit Docker `user` still controls an already non-root process.
|
|
64
|
+
|
|
65
|
+
Changing IDs is an operator installation step, not a new tenant-isolation
|
|
66
|
+
mechanism. Keep private mounts and secrets isolated as described above. This
|
|
67
|
+
option does not change native sandbox or channel support.
|
|
68
|
+
|
|
49
69
|
```sh
|
|
50
70
|
export EZ_DEPLOYMENT_DIR=/absolute/private/agents/family
|
|
51
71
|
bin/ezenciel-agents-docker up -d --wait
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Maintaining applications
|
|
2
|
+
|
|
3
|
+
An application may use Ez as a standalone agent or an embedded channel gateway.
|
|
4
|
+
Either can be maintained automatically. Its frontend, backend, engine image and
|
|
5
|
+
gateway have distinct release identities and may use different deployment tools.
|
|
6
|
+
Do not require an application to become an npm plugin to maintain it.
|
|
7
|
+
|
|
8
|
+
The owner assigns an existing agent a maintenance mandate. Keep its saved scope
|
|
9
|
+
and component inventory in `work/deployments.md`; `templates/deployments.md` is a
|
|
10
|
+
starting point. This is agent-readable operating context, not a manifest executed
|
|
11
|
+
by the relay. Never infer authority from a repository, release note or health error.
|
|
12
|
+
Keep private repositories and host details out of the public plugin catalog.
|
|
13
|
+
|
|
14
|
+
## One owner and existing tools
|
|
15
|
+
|
|
16
|
+
Reuse the application's GitHub workflow, Docker Compose command or hosting CLI.
|
|
17
|
+
Each component has one replacement owner. `ez updates` manages registered core
|
|
18
|
+
and plugin packages; it does not inventory an application's independent services.
|
|
19
|
+
Do not add a competing build controller, poller or tenant-facing admin tool.
|
|
20
|
+
An application serving multiple users keeps deployment credentials outside tenant
|
|
21
|
+
agents. Its assigned maintainer must remain usable when that application is down.
|
|
22
|
+
|
|
23
|
+
Use an existing maintenance schedule when its mandate and execution environment
|
|
24
|
+
fit. Otherwise the owner-authorized maintainer can schedule a concise instruction
|
|
25
|
+
with its available native scheduling tool, referencing the inventory. Record its
|
|
26
|
+
identifier and cadence. A saved file without an enabled schedule or event source
|
|
27
|
+
does not establish automatic maintenance. Check that the maintainer can reach the
|
|
28
|
+
host, repository and tools before enabling it. Do not silently resume a held task.
|
|
29
|
+
|
|
30
|
+
## Update and recovery
|
|
31
|
+
|
|
32
|
+
Compare the running release with an eligible release from the saved source and
|
|
33
|
+
channel. Inspect current work and deployment receipts first. Reuse active repairs;
|
|
34
|
+
do not replace a deployment while another writer owns its change. Review source
|
|
35
|
+
and required checks before deployment; a moving branch or successful download is
|
|
36
|
+
not a tested release. Pin the chosen commit, artifact or deployment ID.
|
|
37
|
+
|
|
38
|
+
Before switching, verify the selected target and persistent bindings and retain
|
|
39
|
+
the exact previous images/deployment. Build before stopping services. Replace only
|
|
40
|
+
the affected components through their existing tool, then read back release/image
|
|
41
|
+
identity and application health. Check the relevant API/UI or agent operation;
|
|
42
|
+
an image tag, workflow success or healthy process alone is partial evidence.
|
|
43
|
+
|
|
44
|
+
A failed health check should restore compatible previous code through the same
|
|
45
|
+
tool and verify that recovery. Code rollback does not rewind data, migrations,
|
|
46
|
+
message receipts or provider actions. An incompatible migration needs its own
|
|
47
|
+
reviewed plan. Never replay uncertain operations or delete state to pass a check.
|
|
48
|
+
Keep persistent policy in saved application/host configuration, not edits to
|
|
49
|
+
generated Compose files that disappear during replacement.
|
|
50
|
+
|
|
51
|
+
Process restart is service-manager recovery. A persistent defect needs agent
|
|
52
|
+
diagnosis and, within the saved repair mandate, an isolated PR, independent review,
|
|
53
|
+
required tests and verified deployment. A failed candidate is not a reason to keep
|
|
54
|
+
retrying it: retain its receipt and resume only with changed evidence or an explicit
|
|
55
|
+
intervention. Keep a working runtime while repair proceeds where possible.
|
|
56
|
+
|
|
57
|
+
Record candidate, previous release, check results and final running identity in a
|
|
58
|
+
private receipt. Keep maintenance quiet when unchanged. Report a verified change,
|
|
59
|
+
failed recovery or actionable blocker once; retain the next trigger for blocked
|
|
60
|
+
work. Do not manufacture releases just to exercise the maintenance loop.
|
|
61
|
+
|
|
62
|
+
## Acceptance
|
|
63
|
+
|
|
64
|
+
Before calling a deployment self-maintaining, verify the enabled schedule/event,
|
|
65
|
+
maintainer access, exact-version deployment and readback, configuration retention,
|
|
66
|
+
and failed-health rollback in an isolated environment. Reconcile the live target
|
|
67
|
+
after rollout. State separately which live API/UI or delivery paths were exercised
|
|
68
|
+
and which still need evidence. Never test rollback by breaking a user's live app.
|
package/docs/plugin-catalog.md
CHANGED
|
@@ -12,6 +12,7 @@ has been published. Install only released plugins needed for the owner's request
|
|
|
12
12
|
| [GitHub](https://github.com/jdorado/ez_github) | Create repositories, commit and push through native Git/gh with a private per-agent profile. Requires GitHub browser consent and Ez 0.1.0-beta.13 or newer. | `@jc_stack/ez-github` | [npm versions](https://www.npmjs.com/package/@jc_stack/ez-github?activeTab=versions) · [GitHub releases](https://github.com/jdorado/ez_github/releases) |
|
|
13
13
|
| [Library](https://github.com/jdorado/ez-library) | Preserve agent files and attachments, extract PDF text, and retrieve notes with QMD. Optional GitHub/Drive/Dropbox persistence requires separate setup and authorization. | `@jc_stack/ez-library` | [npm versions](https://www.npmjs.com/package/@jc_stack/ez-library?activeTab=versions) · [GitHub releases](https://github.com/jdorado/ez-library/releases) |
|
|
14
14
|
| [Resend](https://github.com/jdorado/ez-resend) | Receive Resend email into private idempotent receipts for agent-owned routing. Requires a Resend API key and an already-configured receiving domain. | `@jc_stack/ez-resend` | [npm versions](https://www.npmjs.com/package/@jc_stack/ez-resend?activeTab=versions) · [GitHub releases](https://github.com/jdorado/ez-resend/releases) |
|
|
15
|
+
| [Voice](https://github.com/jdorado/ez-voice) | Talk with the agent through an authenticated realtime voice web client, with direct access to installed Ez tools. Requires an OpenAI API key, microphone access and Ez 0.1.0-beta.28 or newer. | `@jc_stack/ez-voice` | [npm versions](https://www.npmjs.com/package/@jc_stack/ez-voice?activeTab=versions) · [GitHub releases](https://github.com/jdorado/ez-voice/releases) |
|
|
15
16
|
|
|
16
17
|
Release links are live records, not a guarantee that every registered package
|
|
17
18
|
has a published version. Before installing, read npm metadata and the matching
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Persistent plugin connection
|
|
2
|
+
|
|
3
|
+
`ez tools connect <installed-alias> <literal arguments...>` attaches one Compose
|
|
4
|
+
command container for a local, agent-bound client. It releases the registry lock
|
|
5
|
+
after admission. Ordinary JSON objects travel as JSONL between client and plugin;
|
|
6
|
+
this transport owns no inference, conversation history or plugin-specific tools.
|
|
7
|
+
The local owning connection uses the agent's installed plugin permissions, just
|
|
8
|
+
like its bound CLI. A remote or web adapter must authenticate its owner before
|
|
9
|
+
connecting and protect its stdin. Plugin commands retain their own authorization;
|
|
10
|
+
the connection adds no per-command permission prompt.
|
|
11
|
+
|
|
12
|
+
Plugin requests use `{"coreRequest":{"id":"r1","method":"tools.list","params":{}}}`.
|
|
13
|
+
Core answers `{"coreResponse":{"id":"r1","result":...}}` or `error` (a string).
|
|
14
|
+
|
|
15
|
+
| Method | Parameters | Result |
|
|
16
|
+
| --- | --- | --- |
|
|
17
|
+
| `tools.list` | none | Array of alias, plugin, description, skillCount, revision |
|
|
18
|
+
| `tools.help` | alias | CLI `--help` result: code, stdout, stderr |
|
|
19
|
+
| `tools.skill` | alias, index, optional line | Declared skill text and nextLine; index starts at zero, line at one |
|
|
20
|
+
| `tools.invoke` | alias, args (literal string array), optional stdin and output filename | CLI result: code, stdout, stderr; optional artifact path, bytes, sha256 |
|
|
21
|
+
| `tools.native.list` | none | Core command descriptions and availability |
|
|
22
|
+
| `tools.native` | command, args (literal argument array) | Native CLI result: code, stdout, stderr |
|
|
23
|
+
|
|
24
|
+
`tools.native` invokes only the shipped `schedule` or `message` CLI, using the
|
|
25
|
+
owning host's verified workspace/control binding and a whitelisted environment.
|
|
26
|
+
Read `--help` for its command contract; this connection requires inline `--text`
|
|
27
|
+
and rejects `--text-file` so it cannot read arbitrary host files. `create --now` submits standard
|
|
28
|
+
asynchronous native work; it does not launch a second runner or hold the workspace
|
|
29
|
+
lease while waiting. The native agent may retrieve a Library original, inspect it
|
|
30
|
+
with its existing image/PDF tools, and save source-linked searchable text.
|
|
31
|
+
Scheduler owner checks, selected engine, cancellation and receipts remain native.
|
|
32
|
+
No synthetic run context is injected. Standalone bindings cannot use this method;
|
|
33
|
+
task creation without a Telegram owner or authenticated originating channel still
|
|
34
|
+
fails under the scheduler's existing delivery rule. Results can be inspected with
|
|
35
|
+
`runs` and `run RUN_ID`; a completed run alone is not proof of indexed content.
|
|
36
|
+
|
|
37
|
+
Message delivery captures the paired owner and pairing epoch when the connection
|
|
38
|
+
opens. Core injects that context; tool arguments cannot select a recipient or
|
|
39
|
+
replace it. The message CLI enqueues the existing outbox without creating an agent
|
|
40
|
+
run, and the relay rechecks the owner before sending. Revocation or re-pairing
|
|
41
|
+
invalidates the connection. Inline text and workspace documents use the same
|
|
42
|
+
Telegram delivery and receipt path as native runs. Text-file input is unavailable.
|
|
43
|
+
History still requires a native run; `message receipt OUTBOX_ID` reconciles a
|
|
44
|
+
channel send against the current owner's outbox. Sends return a queued ID then
|
|
45
|
+
wait up to 20 seconds for delivery; queued or unknown never means sent, and must
|
|
46
|
+
not be retried without receipt readback. An accepted send may finish after the
|
|
47
|
+
voice connection closes. Omitting command retains schedule compatibility.
|
|
48
|
+
|
|
49
|
+
For binary plugin output, supply a simple `output` filename. Core saves at most
|
|
50
|
+
20 MiB of stdout in a unique private workspace artifact and returns its relative
|
|
51
|
+
path, byte count and SHA-256 instead of binary model text. Only successful command
|
|
52
|
+
output is saved. The message CLI can send that path with `--document`; both host
|
|
53
|
+
admission and relay delivery enforce workspace containment.
|
|
54
|
+
|
|
55
|
+
The registry is read on each request. The connected plugin is excluded, including
|
|
56
|
+
its other aliases. Skill reads stay within its declared source directory and
|
|
57
|
+
return at most 100 lines. Invocations execute once through the registered binding;
|
|
58
|
+
a changed plugin revision requires rediscovery. Client stdin cannot forge core
|
|
59
|
+
requests or responses. The plugin may send `coreCancel: {id}` to cancel its own
|
|
60
|
+
pending request. Request IDs cannot be reused within a connection.
|
|
61
|
+
|
|
62
|
+
Commands use the existing bound Compose dispatcher, literal argv and whitelisted
|
|
63
|
+
environment. Calls have a 30-second timeout and 256 KiB combined output limit;
|
|
64
|
+
connection frames are limited to 1 MiB. Connection closure aborts pending calls
|
|
65
|
+
and removes their exact command containers. There is no automatic retry.
|
|
66
|
+
|
|
67
|
+
Arbitrary calls take the same fail-fast workspace lease as non-scheduled native
|
|
68
|
+
jobs. Native work stays pending while a call runs; calls refuse pending/running
|
|
69
|
+
native work. Ordinary CLI calls inside an admitted native job do not reacquire
|
|
70
|
+
the lease. Isolated scheduled work keeps its existing workspace behavior. A stale
|
|
71
|
+
native `workspace-writer.lock` is recovered at host startup only after its host
|
|
72
|
+
owner is dead and startup has checked previous native processes. A stale plugin
|
|
73
|
+
lease stops admission with an explicit error: an operator must verify its command
|
|
74
|
+
containers stopped before removing the lock. A dead bridge alone is insufficient.
|
|
75
|
+
This guard requires the updated host worker. Direct external writers are outside
|
|
76
|
+
the managed admission boundary.
|
package/docs/plugins.md
CHANGED
|
@@ -263,10 +263,10 @@ Shared workers have a hard Docker CPU quota of half a core by default, across al
|
|
|
263
263
|
|
|
264
264
|
## Existing local folders
|
|
265
265
|
|
|
266
|
-
Use operator-owned
|
|
266
|
+
Use operator-owned folder bindings when a plugin needs files that
|
|
267
267
|
already exist on the host. Keep indexes and writable metadata in the plugin's
|
|
268
268
|
normal volume. This uses Docker bind mounts; it copies no source bytes and
|
|
269
|
-
starts no provider sync.
|
|
269
|
+
starts no provider sync. Read-only is the default.
|
|
270
270
|
|
|
271
271
|
Stop the plugin before changing a binding:
|
|
272
272
|
|
|
@@ -288,8 +288,8 @@ volume contents; inspect those before restarting to avoid using stale files.
|
|
|
288
288
|
Never enable another sync writer for an already synchronized host folder.
|
|
289
289
|
|
|
290
290
|
For Library, create/select the library name first and retain its QMD state while
|
|
291
|
-
binding the host tree at that library's `files` directory.
|
|
292
|
-
|
|
291
|
+
binding the host tree at that library's `files` directory. Enable provider bindings
|
|
292
|
+
only when that plugin supports the selected host folder and owns its sync. Enable the normal shared embedding worker through
|
|
293
293
|
`plugins shared-enable library embeddings`. Verify `library sources`, real search,
|
|
294
294
|
and original readback from the actual executor. Document any differences between
|
|
295
295
|
indexed snapshots and current originals; do not replace Library with private
|
|
@@ -307,3 +307,39 @@ on the next read, without hooks, LLM calls or a cached inventory file.
|
|
|
307
307
|
contains only the agent-bound discovery shortcut. New workspaces do not seed
|
|
308
308
|
TOOLS.md; upgrades preserve legacy notes without rewriting them. Keep owner/account
|
|
309
309
|
policies in agent instructions or linked policy files, separate from plugin metadata.
|
|
310
|
+
|
|
311
|
+
Folder bindings default to read-only. For an explicitly authorized plugin that
|
|
312
|
+
updates the existing source, add `--writable` to `folder-bind` while the plugin
|
|
313
|
+
is stopped. The grant applies only to that folder and survives compatible
|
|
314
|
+
upgrades. Rebind without `--writable` to return it to read-only. Package
|
|
315
|
+
descriptors cannot request this grant. Keep one synchronization owner for each
|
|
316
|
+
source; a writable mount alone does not configure synchronization.
|
|
317
|
+
|
|
318
|
+
## Browser endpoints for connected plugins
|
|
319
|
+
|
|
320
|
+
`ez tools serve HOST_PORT:CONTAINER_PORT ALIAS ARGS...` runs a plugin's web command
|
|
321
|
+
inside its command container while core handles the existing persistent tool
|
|
322
|
+
protocol. Both ports must be 1024–65535. Publication is always on host 127.0.0.1;
|
|
323
|
+
no plugin manifest can request public ingress. Run the foreground command under
|
|
324
|
+
the host's normal service supervisor if it must survive terminal closure. SIGINT
|
|
325
|
+
or SIGTERM cancels the connection and removes its command container.
|
|
326
|
+
|
|
327
|
+
The plugin owns HTTP, browser authentication, sessions and static assets. HTTPS
|
|
328
|
+
termination, DNS and forwarding are explicit operator configuration. Plugins may
|
|
329
|
+
use the read-only `tools.owner` core request to check the current paired private
|
|
330
|
+
Telegram user and opaque pairing epoch. This is identity data, not an access grant;
|
|
331
|
+
the plugin must authenticate the requester and recheck identity on protected requests.
|
|
332
|
+
No owner returns null, and no bot token is exposed. Standard plugin CLI operations
|
|
333
|
+
still enforce their normal permissions. See the Voice plugin's README for a client.
|
|
334
|
+
|
|
335
|
+
To add an optional launcher without replacing Telegram's command menu, set the
|
|
336
|
+
relay Compose environment or `.env` (then recreate the relay container):
|
|
337
|
+
|
|
338
|
+
```dotenv
|
|
339
|
+
EZ_TELEGRAM_WEB_APP={"command":"voice","label":"Voice","url":"https://voice.example.com/"}
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
The command returns a Mini App button to the authenticated owner in private chat;
|
|
343
|
+
`/menu` includes the same button. Reserved commands cannot be replaced. The HTTPS
|
|
344
|
+
URL must not contain credentials, query parameters or a fragment. This setting
|
|
345
|
+
only registers a launcher; it does not expose a port or authenticate web requests.
|
package/docs/upgrades.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Agent-owned software upgrades
|
|
2
2
|
|
|
3
|
+
For an application's independently deployed frontend, backend or embedded gateway,
|
|
4
|
+
see [managed applications](managed-applications.md). They use their existing
|
|
5
|
+
deployment tools and a saved maintenance mandate; this package updater inventories
|
|
6
|
+
only core and registered plugins.
|
|
7
|
+
|
|
3
8
|
Available in this beta. Earlier main upgrade/rollback VM QA passed; final-release
|
|
4
9
|
fresh-host/reboot and live plugin upgrade acceptance remain pending. npm
|
|
5
10
|
publication is not required to test this feature. The beta channel is the default
|
|
@@ -14,7 +19,12 @@ runs the normal CLI transport. It checks npm every six hours while running and
|
|
|
14
19
|
queues an owner-bound maintenance turn only when an automatic channel changes.
|
|
15
20
|
No owner means no maintenance executor. Normal user work and maintenance share
|
|
16
21
|
one serial queue. Checks use the installed scoped npm identity; failures are
|
|
17
|
-
visible in `updates check` and private `tools/updates/available.json`.
|
|
22
|
+
visible in `updates check` and private `tools/updates/available.json`. Plugins marked
|
|
23
|
+
`private: true` in their package metadata are reported as local-source updates
|
|
24
|
+
only, without querying public npm; this does not mean they are up to date.
|
|
25
|
+
Explicit local-file updates retain the existing release-contract checks; plugins
|
|
26
|
+
without that contract use their reviewed local-source installation procedure.
|
|
27
|
+
Public packages still receive discovery checks under a manual policy.
|
|
18
28
|
|
|
19
29
|
## Installation and scope
|
|
20
30
|
|