@tealbrick/avm 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/LICENSE +21 -0
- package/PROVENANCE.md +38 -0
- package/README.md +165 -0
- package/dist/_chunks/extension-CS1otfhf.mjs +232 -0
- package/dist/_chunks/src-BhUiVsTW.mjs +522 -0
- package/dist/client/administration.d.ts +3 -0
- package/dist/client/administration.js +145 -0
- package/dist/client/config.d.ts +1125 -0
- package/dist/client/config.js +257 -0
- package/dist/client/index.d.ts +126 -0
- package/dist/client/index.js +364 -0
- package/dist/extension/_manifest.json +11 -0
- package/dist/extension/extension.d.ts +626 -0
- package/dist/extension/extension.mjs +8 -0
- package/dist/extension/tools/action.d.ts +24 -0
- package/dist/extension/tools/action.mjs +46 -0
- package/dist/extension/tools/inspect.d.ts +50 -0
- package/dist/extension/tools/inspect.mjs +66 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.mjs +8 -0
- package/dist/tools/index.d.ts +4 -0
- package/dist/tools/index.mjs +9 -0
- package/package.json +70 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Tealbrick contributors
|
|
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/PROVENANCE.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Provenance and source contract
|
|
2
|
+
|
|
3
|
+
Implementation authored independently for Tealbrick, MIT. No Kybernesis package dependency or copied runtime source. Upstream was inspected; this is not a source-unexposed clean-room claim.
|
|
4
|
+
|
|
5
|
+
Source authority inspected 2026-09-08: `/Users/puma/work/active/kybernesis-avm`, HEAD `860fb32ef70813760c99631231424fbe0ddde3b1`; `agentvm/bin/avm.py` reports source AVM version 0.12.9. Working checkout may contain additional uncommitted changes; the cited source file, not installed npm CLI metadata, defines this host contract.
|
|
6
|
+
|
|
7
|
+
- `agentvm/bin/avm.py`: `parser()` and `add_identity_actions()` define host `--json`, `worker ls/status/create/start/stop/promote/destroy/exec`, runs/events, monitor, inventory, bundle and capability manifest. Client uses native worker commands rather than npm `agent spawn` aliases.
|
|
8
|
+
- Same file `main()` maps worker create to kind=worker, profile/mode/catalog/capabilities; exec passes normalized remainder argv. Success envelope is `{api_version:'agentvm/v1',result:...}`; error envelope contains `error.message`; exec returns guest returncode as CLI exit code.
|
|
9
|
+
- `agentvm/lib/agentvmd.py`: source of daemon policy/execution and run metadata. No unsupported daemon API has been invented and no root socket is exposed.
|
|
10
|
+
- Eve 0.49.0 installed docs `docs/extensions.md` plus `docs/guides/dynamic-capabilities.md` and public ToolContext declaration informed extension layout, builder-managed exports and abortSignal propagation. `eve extension init tealbrick-avm-scaffold-20260908` was run in disposable `/tmp` as the scaffold contract reference; package implementation is separately authored.
|
|
11
|
+
|
|
12
|
+
Environment boundary: no Puma-local AVM invocation, no SSH/live AVM invocation, no remote mutation, no credentials copied. Mock results do not establish deployed host compatibility. Upstream CLI may evolve without changing the envelope version, so consumers should pin and verify their host release independently.
|
|
13
|
+
|
|
14
|
+
## AVMM update — 2026-09-15
|
|
15
|
+
|
|
16
|
+
Current compatibility authority supersedes the historical checkout above:
|
|
17
|
+
[Martin-Atrin/avmm, codex/avmm-final](https://github.com/Martin-Atrin/avmm/tree/75078743b9bfc2ba268f1fdeea74f298983dfac4),
|
|
18
|
+
release `0.13.0-alpha.2`. Inspected in `/Users/puma/work/upstreams/avmm` at that exact
|
|
19
|
+
revision. `main` still reports 0.12.8 and is not the selected target.
|
|
20
|
+
|
|
21
|
+
- `agentvm/bin/avm.py`: current flags for resource pool, local workspaces/users,
|
|
22
|
+
ownership/shares, resident/wake/cool, provider-neutral ingress, event filters,
|
|
23
|
+
worker resize and all worker creation selections.
|
|
24
|
+
- `agentvm/bin/agentvm-remote-shell.py`: restricted paired SSH command grammar,
|
|
25
|
+
attestation requirement and `/usr/local/bin/avm` execution boundary.
|
|
26
|
+
- `agentvm/lib/agentvmd.py`: authoritative verified actor, share action allowlist,
|
|
27
|
+
auth selection restrictions, queue policy and resource field semantics.
|
|
28
|
+
- `packages/agentvm-cli/src/commands.mjs`, `remote.mjs`, `config.mjs`: operator
|
|
29
|
+
aliases, quoting contract and current single-connection configuration. Named
|
|
30
|
+
Teal Brick connection profiles are newly authored convenience configuration;
|
|
31
|
+
they are not attributed to an upstream multi-host profile API.
|
|
32
|
+
- `docs/releases/0.13.0-alpha.2.md`: upstream ingress acceptance history, distinct
|
|
33
|
+
from this package's tests and the blocked Neuu preflight.
|
|
34
|
+
|
|
35
|
+
No upstream runtime source was copied into this package. Tests construct mock
|
|
36
|
+
responses and execute no AVM process on Puma. The attempted SSH Neuu version probe
|
|
37
|
+
failed strict host-key verification before any remote command ran. No key was
|
|
38
|
+
replaced, runtime changed, credential copied or tenant operation executed.
|
package/README.md
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# @tealbrick/avm
|
|
2
|
+
|
|
3
|
+
Typed host-owned AVMM transport and opt-in Eve capabilities. Node 24+, Eve 0.55.0.
|
|
4
|
+
Tested source contract: **AVMM 0.13.0-alpha.2**, `codex/avmm-final` at
|
|
5
|
+
`75078743b9bfc2ba268f1fdeea74f298983dfac4`. The host executable remains
|
|
6
|
+
`/usr/local/bin/avm`; the JSON envelope remains `agentvm/v1`.
|
|
7
|
+
|
|
8
|
+
## Connection and identity profiles
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import avm from '@tealbrick/avm/eve';
|
|
12
|
+
export default avm({
|
|
13
|
+
selectedProfile: 'alice',
|
|
14
|
+
profiles: {
|
|
15
|
+
alice: {
|
|
16
|
+
mode: 'paired', target: 'agentvm-client@host.example',
|
|
17
|
+
identityFile: '/run/keys/alice',
|
|
18
|
+
},
|
|
19
|
+
bob: {
|
|
20
|
+
mode: 'paired', target: 'agentvm-client@host.example',
|
|
21
|
+
identityFile: '/run/keys/bob',
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The operator selects one profile. Model inputs cannot switch host, key, user,
|
|
28
|
+
workspace or policy. Named **connection profiles are a Teal Brick convenience**;
|
|
29
|
+
AVMM's **resource profiles** are `light`, `small`, `standard`, `browser`.
|
|
30
|
+
Neither is itself a tenant security boundary. AVMM verifies the paired SSH key's
|
|
31
|
+
host-managed attestation, local user/workspace binding, ownership and shares.
|
|
32
|
+
A workspace name in an administration request identifies the object to manage;
|
|
33
|
+
it does not authenticate the caller.
|
|
34
|
+
|
|
35
|
+
- `paired`: speaks AVMM's restricted SSH ForceCommand protocol. Requires `agentvm-client@host` and a bound
|
|
36
|
+
`identityFile`; rejects sudo and identity-token overrides. Uses only that key,
|
|
37
|
+
disables SSH agent fallback, skips SSH config (`-F /dev/null`), and therefore
|
|
38
|
+
requires an actual resolvable hostname/IP, not an SSH-only alias. Host keys must
|
|
39
|
+
already be trusted. No arbitrary remote Python or shell is required.
|
|
40
|
+
- `operator` (legacy default): constant remote Python subprocess, with argv sent
|
|
41
|
+
as JSON stdin; optional `sudo: true`. Uses the configured SSH account's authority.
|
|
42
|
+
This can be host administrator authority and is not a tenant sandbox.
|
|
43
|
+
Optional `identityTokenFile` references an existing root-managed **remote** file;
|
|
44
|
+
the package never reads or copies the token. `identityFile` is an SSH key path,
|
|
45
|
+
never the key contents.
|
|
46
|
+
|
|
47
|
+
Both execute AVM only on the remote host, preserve strict host-key checking,
|
|
48
|
+
disable forwarding, exclude ambient provider environment, and never load a local
|
|
49
|
+
AVM config or run local AVM. No pairing, credential creation or host installation
|
|
50
|
+
occurs. Backward-compatible single connection: `{target:'nucbox', sudo:true}`.
|
|
51
|
+
|
|
52
|
+
Harness-neutral consumers use `@tealbrick/avm/client`:
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
import {AvmClient, SshTransport, avmConfigSchema} from '@tealbrick/avm/client';
|
|
56
|
+
const config = avmConfigSchema.parse({
|
|
57
|
+
target: 'agentvm-client@host.example', mode: 'paired', identityFile: '/run/keys/alice',
|
|
58
|
+
});
|
|
59
|
+
const client = new AvmClient(new SshTransport(config), config);
|
|
60
|
+
const pool = await client.request({operation: 'poolStatus'});
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Reads
|
|
64
|
+
|
|
65
|
+
`doctor`, `inventory`, `workers`, `workerStatus`, `bundles`, `monitor`,
|
|
66
|
+
`capabilities`, `runs`, `runStatus`, `events`, `poolStatus`, `poolPressure`,
|
|
67
|
+
`poolQueue`, `poolPolicy`, `workspaces`, `workspace`, `users`, `user`, `owner`,
|
|
68
|
+
`shares`, `resident`, `ingress`. Events accept `worker`, `event`, `runId` and
|
|
69
|
+
bounded `limit`; ingress accepts an optional worker. The host can deny reads
|
|
70
|
+
according to the authenticated caller. Successful results are generic JSON,
|
|
71
|
+
not a promise of stable upstream result schemas or a replacement for consumer
|
|
72
|
+
authorization/output handling.
|
|
73
|
+
|
|
74
|
+
## Explicit action grants
|
|
75
|
+
|
|
76
|
+
No action tool exists without configured grants. Existing `lifecycle` and fixed
|
|
77
|
+
`commands` grants remain supported. Spawn selections now cover all current worker
|
|
78
|
+
create flags:
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
const policy = {
|
|
82
|
+
spawns: [{
|
|
83
|
+
worker: 'reviewer', profile: 'light', mode: 'durable',
|
|
84
|
+
harnesses: ['eve', 'codex'], bundles: ['base'],
|
|
85
|
+
mcps: ['approved-mcp'], plugins: ['approved-plugin'],
|
|
86
|
+
auth: ['codex=shared'], capabilities: ['browser:public'],
|
|
87
|
+
}],
|
|
88
|
+
administration: [{
|
|
89
|
+
name: 'wake-reviewer',
|
|
90
|
+
request: {operation: 'wake', worker: 'reviewer', idempotencyKey: 'task-123'},
|
|
91
|
+
}],
|
|
92
|
+
};
|
|
93
|
+
// Attach policy to the connection/profile. Caller chooses only the exact grant:
|
|
94
|
+
// client.request({operation:'configured', action:'wake-reviewer'});
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Catalog selections are names, not package installation or credentials.
|
|
98
|
+
Auth choices are `provider=none`, `provider=local`, and `codex=shared`.
|
|
99
|
+
AVMM currently rejects `scoped` and shared auth for other providers; this adapter
|
|
100
|
+
rejects those too. Provider secrets remain with AVMM's configured credential owner.
|
|
101
|
+
|
|
102
|
+
Named `administration` grants accept strictly validated requests:
|
|
103
|
+
|
|
104
|
+
| Operation | Configured fields / behavior |
|
|
105
|
+
|---|---|
|
|
106
|
+
| `resize` | worker, memoryTargetMiB |
|
|
107
|
+
| `workspacePut` / `workspaceDisable` | workspace; put: displayName, weight, concurrentHeavyWork, queuePolicy |
|
|
108
|
+
| `tenantSync` | workspace, displayName, principalId, issuer, subject, role, same queue policy fields |
|
|
109
|
+
| `userPut` | user, workspace, role |
|
|
110
|
+
| `ownerSet` | worker, workspace, optional user |
|
|
111
|
+
| `shareGrant` / `shareRevoke` | worker; grant: grantee `{kind:'workspace'|'user',id}`, allow; revoke: shareId |
|
|
112
|
+
| `poolPolicySet` | cpuPercent, memoryMaxBytes, memoryHighBytes, hostMemoryReserveBytes, launchReserveBytes |
|
|
113
|
+
| `residentSet` / `cool` | worker |
|
|
114
|
+
| `wake` | worker, required idempotencyKey, optional source/reason/externalEventId |
|
|
115
|
+
| `ingressPut` | provider, externalIdentity, worker, optional channelScope/metadataFile |
|
|
116
|
+
| `ingressRevoke` | identityId |
|
|
117
|
+
| `ingressWake` | provider, externalIdentity, eventId, optional channelScope/payloadFile/correlationId |
|
|
118
|
+
| `ingressComplete` | wakeId, optional error; record delivery only after actual delivery |
|
|
119
|
+
|
|
120
|
+
File fields reference trusted remote files; contents are not put into argv.
|
|
121
|
+
These grants are operator configuration, not browser/model input. They cannot
|
|
122
|
+
bypass daemon permissions. Share actions use AVMM's allowlist and exclude destroy
|
|
123
|
+
and ownership transfer. Owner changes, workspace disable, pool changes, cooling,
|
|
124
|
+
and disk destruction have real side effects; grant only the intended operation.
|
|
125
|
+
A fixed ingress/wake grant represents a specific event. A provider adapter needs
|
|
126
|
+
fresh trusted grants for subsequent events and remains responsible for delivery.
|
|
127
|
+
No retries are automatic. Cancellation stops SSH; remote work may continue.
|
|
128
|
+
Reconcile before retrying; wake event keys do not make all CLI commands idempotent.
|
|
129
|
+
|
|
130
|
+
## Eve and kit
|
|
131
|
+
|
|
132
|
+
Importing dependencies contributes nothing. An explicit mount contributes inspect;
|
|
133
|
+
a dynamic action is exposed only with grants. It rechecks current configuration
|
|
134
|
+
on each execution, including after profile switching or revocation.
|
|
135
|
+
|
|
136
|
+
The kit accepts the same configuration under `avm`. `tealbrick setup` can select
|
|
137
|
+
an existing named profile or configure paired/operator SSH. `tealbrick apply
|
|
138
|
+
config.json` supports full profiles and policies. Provider transport is unrelated
|
|
139
|
+
to AVMM's tenant authorization. No channels, hooks, miniapps or credential tools
|
|
140
|
+
are incidentally mounted.
|
|
141
|
+
|
|
142
|
+
## Evidence and remaining scope
|
|
143
|
+
|
|
144
|
+
The 2026-09-15 suite passes 95 package tests, including 22 AVM tests, plus isolated
|
|
145
|
+
kit tarball install, strict consumer type checking and Eve discovery/build.
|
|
146
|
+
Coverage includes denial, immutable grants, profile switching/revocation,
|
|
147
|
+
forced-command quoting, transport identity isolation, timeouts/output bounds,
|
|
148
|
+
legacy kit receipts, activation/deactivation and exact command construction.
|
|
149
|
+
All action/transport tests are disposable and mocked; no local AVM is executed.
|
|
150
|
+
|
|
151
|
+
Live Neuu verification was blocked by a changed SSH host key before connection.
|
|
152
|
+
No tenant isolation, VM creation, cold wake or message delivery was exercised live
|
|
153
|
+
by this package update. Earlier 0.12.9 doctor receipts are historical only.
|
|
154
|
+
|
|
155
|
+
This remains a bounded adapter, not the entire operator CLI. Host installation,
|
|
156
|
+
pairing, client-key enrollment, trusted VM management, interactive SSH, provider
|
|
157
|
+
login/leases, browser/LCM, role deployment and schedules remain operator-owned.
|
|
158
|
+
The package does not implement a Buzz/Telegram adapter or automatic Portal agent
|
|
159
|
+
registration. Packages are unpublished; neither npm release nor deployment is
|
|
160
|
+
implied by tests.
|
|
161
|
+
|
|
162
|
+
Deployment authority correction (2026-09-15): live AVMM/Eve/Teal Brick packages
|
|
163
|
+
belong exclusively on Nucbox, the Fedora N150. Neuu attempts above are historical
|
|
164
|
+
and were aimed at the wrong host. Nucbox is reachable and reports AVMM
|
|
165
|
+
0.13.0-alpha.2; its resident Aura still runs Eve 0.49.0. No live upgrade is implied.
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import { fileURLToPath as __eveFileURLToPath } from "node:url";
|
|
2
|
+
import { dirname as __eveDirname } from "node:path";
|
|
3
|
+
import { createRequire as __eveCreateRequire } from "node:module";
|
|
4
|
+
const __filename = __eveFileURLToPath(import.meta.url);
|
|
5
|
+
__eveDirname(__filename);
|
|
6
|
+
__eveCreateRequire(import.meta.url);
|
|
7
|
+
import { defineExtension } from "eve/extension";
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
const id = z.string().regex(/^[A-Za-z0-9][A-Za-z0-9_.-]{0,127}$/);
|
|
10
|
+
const workspace = z.string().regex(/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/);
|
|
11
|
+
const user = z.string().regex(/^[a-z][a-z0-9_-]{0,63}$/);
|
|
12
|
+
const nonnegative = z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER);
|
|
13
|
+
const publicValue = z.string().min(1).max(512).regex(/^[^\0\r\n]+$/);
|
|
14
|
+
const provider = z.string().regex(/^[a-z][a-z0-9._-]{0,63}$/);
|
|
15
|
+
const positive = z.number().int().positive().max(Number.MAX_SAFE_INTEGER);
|
|
16
|
+
const path = z.string().regex(/^\/[A-Za-z0-9_./ -]+$/).max(4096);
|
|
17
|
+
const queue = {
|
|
18
|
+
weight: positive.optional(),
|
|
19
|
+
concurrentHeavyWork: nonnegative.optional(),
|
|
20
|
+
queuePolicy: z.enum([
|
|
21
|
+
"fair",
|
|
22
|
+
"fifo",
|
|
23
|
+
"reject"
|
|
24
|
+
]).optional()
|
|
25
|
+
};
|
|
26
|
+
const administrationSchema = z.discriminatedUnion("operation", [
|
|
27
|
+
z.object({
|
|
28
|
+
operation: z.literal("tenantSync"),
|
|
29
|
+
workspace,
|
|
30
|
+
displayName: publicValue.optional(),
|
|
31
|
+
principalId: user.optional(),
|
|
32
|
+
issuer: z.url().optional(),
|
|
33
|
+
subject: publicValue.optional(),
|
|
34
|
+
role: z.enum([
|
|
35
|
+
"member",
|
|
36
|
+
"admin",
|
|
37
|
+
"operator"
|
|
38
|
+
]).default("member"),
|
|
39
|
+
...queue
|
|
40
|
+
}).strict(),
|
|
41
|
+
z.object({
|
|
42
|
+
operation: z.literal("ingressPut"),
|
|
43
|
+
provider,
|
|
44
|
+
externalIdentity: publicValue,
|
|
45
|
+
worker: id,
|
|
46
|
+
channelScope: publicValue.optional(),
|
|
47
|
+
metadataFile: path.optional()
|
|
48
|
+
}).strict(),
|
|
49
|
+
z.object({
|
|
50
|
+
operation: z.literal("ingressRevoke"),
|
|
51
|
+
identityId: id
|
|
52
|
+
}).strict(),
|
|
53
|
+
z.object({
|
|
54
|
+
operation: z.literal("ingressWake"),
|
|
55
|
+
provider,
|
|
56
|
+
externalIdentity: publicValue,
|
|
57
|
+
eventId: publicValue,
|
|
58
|
+
channelScope: publicValue.optional(),
|
|
59
|
+
payloadFile: path.optional(),
|
|
60
|
+
correlationId: publicValue.optional()
|
|
61
|
+
}).strict(),
|
|
62
|
+
z.object({
|
|
63
|
+
operation: z.literal("ingressComplete"),
|
|
64
|
+
wakeId: id,
|
|
65
|
+
error: publicValue.optional()
|
|
66
|
+
}).strict(),
|
|
67
|
+
z.object({
|
|
68
|
+
operation: z.literal("resize"),
|
|
69
|
+
worker: id,
|
|
70
|
+
memoryTargetMiB: positive
|
|
71
|
+
}).strict(),
|
|
72
|
+
z.object({
|
|
73
|
+
operation: z.literal("workspacePut"),
|
|
74
|
+
workspace,
|
|
75
|
+
displayName: z.string().min(1).max(256).regex(/^[^\0\r\n]+$/).optional(),
|
|
76
|
+
...queue
|
|
77
|
+
}).strict(),
|
|
78
|
+
z.object({
|
|
79
|
+
operation: z.literal("workspaceDisable"),
|
|
80
|
+
workspace
|
|
81
|
+
}).strict(),
|
|
82
|
+
z.object({
|
|
83
|
+
operation: z.literal("userPut"),
|
|
84
|
+
user,
|
|
85
|
+
workspace,
|
|
86
|
+
role: z.enum([
|
|
87
|
+
"member",
|
|
88
|
+
"admin",
|
|
89
|
+
"operator"
|
|
90
|
+
])
|
|
91
|
+
}).strict(),
|
|
92
|
+
z.object({
|
|
93
|
+
operation: z.literal("ownerSet"),
|
|
94
|
+
worker: id,
|
|
95
|
+
workspace,
|
|
96
|
+
user: user.optional()
|
|
97
|
+
}).strict(),
|
|
98
|
+
z.object({
|
|
99
|
+
operation: z.literal("shareGrant"),
|
|
100
|
+
worker: id,
|
|
101
|
+
grantee: z.discriminatedUnion("kind", [z.object({
|
|
102
|
+
kind: z.literal("workspace"),
|
|
103
|
+
id: workspace
|
|
104
|
+
}).strict(), z.object({
|
|
105
|
+
kind: z.literal("user"),
|
|
106
|
+
id: user
|
|
107
|
+
}).strict()]),
|
|
108
|
+
allow: z.array(z.enum([
|
|
109
|
+
"status",
|
|
110
|
+
"exec",
|
|
111
|
+
"start",
|
|
112
|
+
"stop",
|
|
113
|
+
"ssh",
|
|
114
|
+
"logs",
|
|
115
|
+
"events",
|
|
116
|
+
"runs",
|
|
117
|
+
"assignments",
|
|
118
|
+
"schedule",
|
|
119
|
+
"capabilities",
|
|
120
|
+
"auth",
|
|
121
|
+
"leases",
|
|
122
|
+
"resident",
|
|
123
|
+
"wake",
|
|
124
|
+
"cool",
|
|
125
|
+
"list",
|
|
126
|
+
"inventory",
|
|
127
|
+
"monitor",
|
|
128
|
+
"roles",
|
|
129
|
+
"ingress"
|
|
130
|
+
])).min(1)
|
|
131
|
+
}).strict(),
|
|
132
|
+
z.object({
|
|
133
|
+
operation: z.literal("shareRevoke"),
|
|
134
|
+
worker: id,
|
|
135
|
+
shareId: id
|
|
136
|
+
}).strict(),
|
|
137
|
+
z.object({
|
|
138
|
+
operation: z.literal("residentSet"),
|
|
139
|
+
worker: id
|
|
140
|
+
}).strict(),
|
|
141
|
+
z.object({
|
|
142
|
+
operation: z.literal("wake"),
|
|
143
|
+
worker: id,
|
|
144
|
+
reason: z.string().min(1).max(256).optional(),
|
|
145
|
+
source: z.enum([
|
|
146
|
+
"cli",
|
|
147
|
+
"schedule",
|
|
148
|
+
"control-plane",
|
|
149
|
+
"delegation"
|
|
150
|
+
]).default("cli"),
|
|
151
|
+
externalEventId: id.optional(),
|
|
152
|
+
idempotencyKey: id
|
|
153
|
+
}).strict(),
|
|
154
|
+
z.object({
|
|
155
|
+
operation: z.literal("cool"),
|
|
156
|
+
worker: id
|
|
157
|
+
}).strict(),
|
|
158
|
+
z.object({
|
|
159
|
+
operation: z.literal("poolPolicySet"),
|
|
160
|
+
cpuPercent: positive.optional(),
|
|
161
|
+
memoryMaxBytes: positive.optional(),
|
|
162
|
+
memoryHighBytes: positive.optional(),
|
|
163
|
+
hostMemoryReserveBytes: nonnegative.optional(),
|
|
164
|
+
launchReserveBytes: nonnegative.optional()
|
|
165
|
+
}).strict()
|
|
166
|
+
]);
|
|
167
|
+
const policySchema = z.object({
|
|
168
|
+
lifecycle: z.array(z.object({
|
|
169
|
+
worker: id,
|
|
170
|
+
operations: z.array(z.enum([
|
|
171
|
+
"start",
|
|
172
|
+
"stop",
|
|
173
|
+
"promote",
|
|
174
|
+
"destroy"
|
|
175
|
+
]))
|
|
176
|
+
}).strict()).default([]),
|
|
177
|
+
spawns: z.array(z.object({
|
|
178
|
+
worker: id,
|
|
179
|
+
profile: z.enum([
|
|
180
|
+
"light",
|
|
181
|
+
"small",
|
|
182
|
+
"standard",
|
|
183
|
+
"browser"
|
|
184
|
+
]),
|
|
185
|
+
mode: z.enum(["ephemeral", "durable"]),
|
|
186
|
+
harnesses: z.array(z.string()).optional(),
|
|
187
|
+
bundles: z.array(z.string()).optional(),
|
|
188
|
+
capabilities: z.array(z.string()).optional(),
|
|
189
|
+
mcps: z.array(z.string()).optional(),
|
|
190
|
+
plugins: z.array(z.string()).optional(),
|
|
191
|
+
auth: z.array(z.string().regex(/^[a-z][a-z0-9_-]*=(none|local)$|^codex=shared$/)).optional()
|
|
192
|
+
}).strict()).default([]),
|
|
193
|
+
commands: z.array(z.object({
|
|
194
|
+
worker: id,
|
|
195
|
+
command: id,
|
|
196
|
+
argv: z.array(z.string().max(8192).refine((v) => !v.includes("\0"))).min(1).max(100)
|
|
197
|
+
}).strict()).default([]),
|
|
198
|
+
administration: z.array(z.object({
|
|
199
|
+
name: id,
|
|
200
|
+
request: administrationSchema
|
|
201
|
+
}).strict()).default([])
|
|
202
|
+
}).strict();
|
|
203
|
+
const connectionSchema = z.object({
|
|
204
|
+
target: z.string().regex(/^(?:[A-Za-z0-9_][A-Za-z0-9_.-]*@)?[A-Za-z0-9][A-Za-z0-9.-]*$/),
|
|
205
|
+
mode: z.enum(["operator", "paired"]).default("operator"),
|
|
206
|
+
sudo: z.boolean().default(false),
|
|
207
|
+
identityFile: path.optional(),
|
|
208
|
+
identityTokenFile: path.optional(),
|
|
209
|
+
timeoutMs: z.number().int().min(1).max(3e5).default(3e4),
|
|
210
|
+
policy: policySchema.default({
|
|
211
|
+
lifecycle: [],
|
|
212
|
+
spawns: [],
|
|
213
|
+
commands: [],
|
|
214
|
+
administration: []
|
|
215
|
+
})
|
|
216
|
+
}).strict().refine((c) => c.mode !== "paired" || c.target.startsWith("agentvm-client@") && !c.sudo && !!c.identityFile && !c.identityTokenFile, { message: "Paired mode requires agentvm-client@host and its bound SSH identity file and disallows sudo or identity token overrides" });
|
|
217
|
+
const avmConfigSchema = z.union([connectionSchema, z.object({
|
|
218
|
+
selectedProfile: id,
|
|
219
|
+
profiles: z.record(id, connectionSchema)
|
|
220
|
+
}).strict().transform((c, ctx) => {
|
|
221
|
+
const selected = Object.hasOwn(c.profiles, c.selectedProfile) ? c.profiles[c.selectedProfile] : void 0;
|
|
222
|
+
if (!selected) {
|
|
223
|
+
ctx.addIssue({
|
|
224
|
+
code: "custom",
|
|
225
|
+
message: "Unknown AVM connection profile"
|
|
226
|
+
});
|
|
227
|
+
return z.NEVER;
|
|
228
|
+
}
|
|
229
|
+
return selected;
|
|
230
|
+
})]);
|
|
231
|
+
var extension_default = defineExtension({ config: avmConfigSchema });
|
|
232
|
+
export { administrationSchema as n, extension_default as t };
|