asylumwarden 0.0.0-stage → 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/README.md +53 -2
- package/adapters/opencode/index.js +282 -0
- package/bin/asylumwarden.mjs +5 -0
- package/package.json +37 -4
- package/schemas/config.schema.json +93 -0
- package/schemas/ledger.schema.json +21 -0
- package/schemas/manifest.schema.json +49 -0
- package/schemas/receipt.schema.json +102 -0
- package/schemas/registry.schema.json +43 -0
- package/src/cli/main.mjs +342 -0
- package/src/config/bootstrap.mjs +36 -0
- package/src/config/load.mjs +531 -0
- package/src/config/schemas.mjs +58 -0
- package/src/context.mjs +50 -0
- package/src/index.mjs +12 -0
- package/src/kernel/canon.mjs +59 -0
- package/src/kernel/errors.mjs +80 -0
- package/src/kernel/fsutil.mjs +147 -0
- package/src/kernel/glob.mjs +70 -0
- package/src/kernel/lock.mjs +104 -0
- package/src/kernel/schemalite.mjs +153 -0
- package/src/kernel/state.mjs +56 -0
- package/src/lease/lease.mjs +551 -0
- package/src/ledger/anchor.mjs +395 -0
- package/src/ledger/chain.mjs +468 -0
- package/src/manifest/manifest.mjs +199 -0
- package/src/manifest/plan.mjs +142 -0
- package/src/receipt/receipt.mjs +555 -0
- package/src/views/views.mjs +148 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 TachikomaGundam
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,54 @@
|
|
|
1
|
-
#
|
|
1
|
+
# AsylumWarden
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Status: core + CLI implemented (milestones M1–M2), adapter layer in
|
|
4
|
+
progress. The npm package `asylumwarden@0.0.0` is a name reservation; the
|
|
5
|
+
first functional release will be `0.1.0`.**
|
|
6
|
+
|
|
7
|
+
AsylumWarden is a local, file-first control plane for multi-seat AI work. It
|
|
8
|
+
keeps the plan, leases, receipts, and ledger on disk. It does not run a daemon,
|
|
9
|
+
require a database, or replace the host's sandbox.
|
|
10
|
+
|
|
11
|
+
- GitHub: <https://github.com/TachikomaGundam/AsylumWarden>
|
|
12
|
+
- npm: `asylumwarden` (0.0.0 name reservation; functional release `0.1.0`
|
|
13
|
+
follows the release gate in [`docs/RELEASING.md`](docs/RELEASING.md))
|
|
14
|
+
- License: MIT
|
|
15
|
+
|
|
16
|
+
## What it is
|
|
17
|
+
|
|
18
|
+
- A registry of work lines and their writable / read-only / forbidden surfaces.
|
|
19
|
+
- A DAG planner with cycle and dependency checks.
|
|
20
|
+
- Atomic claims with owner, epoch, TTL, and heartbeat.
|
|
21
|
+
- Receipt validation: commands, artifacts, read mentions, and path containment.
|
|
22
|
+
- An append-only, hash-chained ledger that is tamper-evident, not tamper-proof.
|
|
23
|
+
- A thin CLI and optional opencode adapter.
|
|
24
|
+
|
|
25
|
+
## What it is not
|
|
26
|
+
|
|
27
|
+
- Not a sandbox. Same-uid processes can still bypass declarations.
|
|
28
|
+
- Not a replacement for PCB's control plane or Abathur's gates.
|
|
29
|
+
- Not a required dependency of Abathur. It is an optional companion.
|
|
30
|
+
- Not a daemon, scheduler service, or task database.
|
|
31
|
+
|
|
32
|
+
## Design
|
|
33
|
+
|
|
34
|
+
The approved architecture is in
|
|
35
|
+
[`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md). Wire formats
|
|
36
|
+
and error codes have a single source: [`docs/CONTRACT.md`](docs/CONTRACT.md)
|
|
37
|
+
with machine-readable schemas in `schemas/`. Security limits are stated
|
|
38
|
+
plainly in [`docs/SECURITY.md`](docs/SECURITY.md). The PCB pilot boundary is
|
|
39
|
+
in [`docs/PILOT-PCB.md`](docs/PILOT-PCB.md). Release rules are in
|
|
40
|
+
[`docs/RELEASING.md`](docs/RELEASING.md).
|
|
41
|
+
|
|
42
|
+
## Boundary with Abathur
|
|
43
|
+
|
|
44
|
+
Abathur does not import AsylumWarden and does not install it. AsylumWarden may
|
|
45
|
+
read Abathur data, but the dependency is one-way:
|
|
46
|
+
|
|
47
|
+
```text
|
|
48
|
+
AsylumWarden ---reads/obeys---> versioned contract
|
|
49
|
+
Abathur ---does not depend on---> AsylumWarden
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## License
|
|
53
|
+
|
|
54
|
+
MIT. See [`LICENSE`](LICENSE).
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
// THIN ADAPTER (M3). No business rules here; all validation is core's (fail-closed).
|
|
2
|
+
// Every warden_* handler does exactly one thing: map tool args -> CLI argv, run the
|
|
3
|
+
// core in-process via runCli(), return { output, exit }. No retries, no state
|
|
4
|
+
// access, no defaults, no interpretation of the envelope.
|
|
5
|
+
//
|
|
6
|
+
// PCB pilot boundary (docs/PILOT-PCB.md): this adapter must NEVER be installed into
|
|
7
|
+
// PCB sessions. The PCB pilot is CLI-only and shadow-only; the plugin path is out
|
|
8
|
+
// of bounds for that line.
|
|
9
|
+
//
|
|
10
|
+
// Plugin shape: verified against a real installed plugin on this machine,
|
|
11
|
+
// opencode-wiki-historian@0.6.3 (dist/index.js + dist/tools.js), 2026-11-05:
|
|
12
|
+
//
|
|
13
|
+
// // dist/index.js (historian):
|
|
14
|
+
// async function server(input, options) { ... return { tool: buildTools(opts) }; }
|
|
15
|
+
// const plugin = { id: 'opencode-historian', server };
|
|
16
|
+
// export default plugin;
|
|
17
|
+
// // dist/tools/read.js (historian):
|
|
18
|
+
// import { tool } from '@opencode-ai/plugin';
|
|
19
|
+
// const s = tool.schema; // zod
|
|
20
|
+
// tool({ description, args: { key: s.string() }, execute: async (raw) => string })
|
|
21
|
+
//
|
|
22
|
+
// The real plugin builds each tool with the SDK's `tool()` helper and zod schemas.
|
|
23
|
+
// This adapter must not import any host SDK (AGENTS.md: adapters never create a
|
|
24
|
+
// path back into core; the zero-dep promise; task constraint), so tool definitions
|
|
25
|
+
// are the same plain objects the helper returns — { description, args, execute } —
|
|
26
|
+
// with `args` declared as JSON Schema instead of zod. If the host-side loader ever
|
|
27
|
+
// needs zod args, that wrapping belongs at install time, not in core and not here.
|
|
28
|
+
// Everything host-facing is duck-typed: no @opencode-ai/* import anywhere, static
|
|
29
|
+
// or dynamic. If the host shape is missing/unexpected we register nothing and log
|
|
30
|
+
// once — never throw at load.
|
|
31
|
+
//
|
|
32
|
+
// Core is imported through the public library entry only (src/index.mjs exports
|
|
33
|
+
// runCli); zero subprocess. Import direction: adapters -> core, never the reverse
|
|
34
|
+
// (enforced by tools/import-gate.mjs).
|
|
35
|
+
|
|
36
|
+
import { runCli } from "../../src/index.mjs";
|
|
37
|
+
|
|
38
|
+
// CLI surface per docs/CONTRACT.md §8. `command` = fixed leading argv tokens;
|
|
39
|
+
// positional/value/bool entries map 1:1 onto CLI flags (camelCase tool param ->
|
|
40
|
+
// kebab-case flag, e.g. stateHome -> --state-home). Required-ness is NOT checked
|
|
41
|
+
// here — core fails closed (USAGE, exit 1) on a missing --actor/--epoch/etc.
|
|
42
|
+
const TOOL_SPECS = [
|
|
43
|
+
{
|
|
44
|
+
tool: "warden_init",
|
|
45
|
+
command: ["init"],
|
|
46
|
+
description: "Initialize the state home (genesis ledger entry + anchor push). " +
|
|
47
|
+
"With bootstrapRegistry=true, create an absent registry file instead (needs registry, self, root).",
|
|
48
|
+
positional: [],
|
|
49
|
+
valueFlags: [
|
|
50
|
+
{ key: "config", flag: "config", desc: "Path to asylumwarden.json" },
|
|
51
|
+
{ key: "stateHome", flag: "state-home", desc: "State home override (test/shadow)" },
|
|
52
|
+
{ key: "registry", flag: "registry", desc: "Registry path (with bootstrapRegistry)" },
|
|
53
|
+
{ key: "self", flag: "self", desc: "Own line name (with bootstrapRegistry)" },
|
|
54
|
+
{ key: "root", flag: "root", desc: "Own writable root (with bootstrapRegistry)" },
|
|
55
|
+
],
|
|
56
|
+
boolFlags: [
|
|
57
|
+
{ key: "force", flag: "force", desc: "Overwrite an existing registry file" },
|
|
58
|
+
{ key: "bootstrapRegistry", flag: "bootstrap-registry", desc: "Bootstrap the registry file" },
|
|
59
|
+
],
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
tool: "warden_plan",
|
|
63
|
+
command: ["plan"],
|
|
64
|
+
description: "Validate a wave manifest and materialize the wave.",
|
|
65
|
+
positional: [{ key: "manifest", desc: "Path to wave.json" }],
|
|
66
|
+
valueFlags: [
|
|
67
|
+
{ key: "config", flag: "config", desc: "Path to asylumwarden.json" },
|
|
68
|
+
{ key: "stateHome", flag: "state-home", desc: "State home override" },
|
|
69
|
+
],
|
|
70
|
+
boolFlags: [{ key: "force", flag: "force", desc: "Force re-plan" }],
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
tool: "warden_ready",
|
|
74
|
+
command: ["ready"],
|
|
75
|
+
description: "List claimable cells of a wave (pending, dependencies done).",
|
|
76
|
+
positional: [{ key: "wave", desc: "Wave id" }],
|
|
77
|
+
valueFlags: [
|
|
78
|
+
{ key: "config", flag: "config", desc: "Path to asylumwarden.json" },
|
|
79
|
+
{ key: "stateHome", flag: "state-home", desc: "State home override" },
|
|
80
|
+
],
|
|
81
|
+
boolFlags: [],
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
tool: "warden_claim",
|
|
85
|
+
command: ["claim"],
|
|
86
|
+
description: "Acquire the lease on a cell (owner, epoch, TTL).",
|
|
87
|
+
positional: [
|
|
88
|
+
{ key: "wave", desc: "Wave id" },
|
|
89
|
+
{ key: "cell", desc: "Cell id" },
|
|
90
|
+
],
|
|
91
|
+
valueFlags: [
|
|
92
|
+
{ key: "actor", flag: "actor", desc: "Actor name (required by core)" },
|
|
93
|
+
{ key: "ttl", flag: "ttl", desc: "Lease TTL in seconds", type: "number" },
|
|
94
|
+
{ key: "config", flag: "config", desc: "Path to asylumwarden.json" },
|
|
95
|
+
{ key: "stateHome", flag: "state-home", desc: "State home override" },
|
|
96
|
+
],
|
|
97
|
+
boolFlags: [{ key: "steal", flag: "steal", desc: "Steal a live lease (audited)" }],
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
tool: "warden_renew",
|
|
101
|
+
command: ["renew"],
|
|
102
|
+
description: "Heartbeat: extend the lease of the current epoch.",
|
|
103
|
+
positional: [
|
|
104
|
+
{ key: "wave", desc: "Wave id" },
|
|
105
|
+
{ key: "cell", desc: "Cell id" },
|
|
106
|
+
],
|
|
107
|
+
valueFlags: [
|
|
108
|
+
{ key: "actor", flag: "actor", desc: "Actor name (required by core)" },
|
|
109
|
+
{ key: "epoch", flag: "epoch", desc: "Lease epoch (required by core)", type: "number" },
|
|
110
|
+
{ key: "ttl", flag: "ttl", desc: "New TTL in seconds", type: "number" },
|
|
111
|
+
{ key: "config", flag: "config", desc: "Path to asylumwarden.json" },
|
|
112
|
+
{ key: "stateHome", flag: "state-home", desc: "State home override" },
|
|
113
|
+
],
|
|
114
|
+
boolFlags: [],
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
tool: "warden_release",
|
|
118
|
+
command: ["release"],
|
|
119
|
+
description: "Voluntarily release a held lease.",
|
|
120
|
+
positional: [
|
|
121
|
+
{ key: "wave", desc: "Wave id" },
|
|
122
|
+
{ key: "cell", desc: "Cell id" },
|
|
123
|
+
],
|
|
124
|
+
valueFlags: [
|
|
125
|
+
{ key: "actor", flag: "actor", desc: "Actor name (required by core)" },
|
|
126
|
+
{ key: "epoch", flag: "epoch", desc: "Lease epoch (required by core)", type: "number" },
|
|
127
|
+
{ key: "config", flag: "config", desc: "Path to asylumwarden.json" },
|
|
128
|
+
{ key: "stateHome", flag: "state-home", desc: "State home override" },
|
|
129
|
+
],
|
|
130
|
+
boolFlags: [],
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
tool: "warden_requeue",
|
|
134
|
+
command: ["requeue"],
|
|
135
|
+
description: "Move a failed cell back to pending.",
|
|
136
|
+
positional: [
|
|
137
|
+
{ key: "wave", desc: "Wave id" },
|
|
138
|
+
{ key: "cell", desc: "Cell id" },
|
|
139
|
+
],
|
|
140
|
+
valueFlags: [
|
|
141
|
+
{ key: "config", flag: "config", desc: "Path to asylumwarden.json" },
|
|
142
|
+
{ key: "stateHome", flag: "state-home", desc: "State home override" },
|
|
143
|
+
],
|
|
144
|
+
boolFlags: [],
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
tool: "warden_done",
|
|
148
|
+
command: ["done"],
|
|
149
|
+
description: "Finish a cell as done with a receipt (core validates the receipt).",
|
|
150
|
+
positional: [
|
|
151
|
+
{ key: "wave", desc: "Wave id" },
|
|
152
|
+
{ key: "cell", desc: "Cell id" },
|
|
153
|
+
],
|
|
154
|
+
valueFlags: [
|
|
155
|
+
{ key: "actor", flag: "actor", desc: "Actor name (required by core)" },
|
|
156
|
+
{ key: "epoch", flag: "epoch", desc: "Lease epoch (required by core)", type: "number" },
|
|
157
|
+
{ key: "receipt", flag: "receipt", desc: "Receipt file path (required by core)" },
|
|
158
|
+
{ key: "config", flag: "config", desc: "Path to asylumwarden.json" },
|
|
159
|
+
{ key: "stateHome", flag: "state-home", desc: "State home override" },
|
|
160
|
+
],
|
|
161
|
+
boolFlags: [],
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
tool: "warden_fail",
|
|
165
|
+
command: ["fail"],
|
|
166
|
+
description: "Finish a cell as failed with a reason.",
|
|
167
|
+
positional: [
|
|
168
|
+
{ key: "wave", desc: "Wave id" },
|
|
169
|
+
{ key: "cell", desc: "Cell id" },
|
|
170
|
+
],
|
|
171
|
+
valueFlags: [
|
|
172
|
+
{ key: "actor", flag: "actor", desc: "Actor name (required by core)" },
|
|
173
|
+
{ key: "epoch", flag: "epoch", desc: "Lease epoch (required by core)", type: "number" },
|
|
174
|
+
{ key: "reason", flag: "reason", desc: "Failure reason (required by core)" },
|
|
175
|
+
{ key: "config", flag: "config", desc: "Path to asylumwarden.json" },
|
|
176
|
+
{ key: "stateHome", flag: "state-home", desc: "State home override" },
|
|
177
|
+
],
|
|
178
|
+
boolFlags: [],
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
tool: "warden_status",
|
|
182
|
+
command: ["status"],
|
|
183
|
+
description: "Status report for one wave or all waves.",
|
|
184
|
+
positional: [{ key: "wave", desc: "Wave id (omit for all waves)" }],
|
|
185
|
+
valueFlags: [
|
|
186
|
+
{ key: "config", flag: "config", desc: "Path to asylumwarden.json" },
|
|
187
|
+
{ key: "stateHome", flag: "state-home", desc: "State home override" },
|
|
188
|
+
],
|
|
189
|
+
boolFlags: [],
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
tool: "warden_verify",
|
|
193
|
+
command: ["verify"],
|
|
194
|
+
description: "Verify the ledger hash chain + anchor + receipt spot-check.",
|
|
195
|
+
positional: [],
|
|
196
|
+
valueFlags: [
|
|
197
|
+
{ key: "wave", flag: "wave", desc: "Restrict verification to one wave" },
|
|
198
|
+
{ key: "config", flag: "config", desc: "Path to asylumwarden.json" },
|
|
199
|
+
{ key: "stateHome", flag: "state-home", desc: "State home override" },
|
|
200
|
+
],
|
|
201
|
+
boolFlags: [],
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
tool: "warden_registry_check",
|
|
205
|
+
command: ["registry", "check"],
|
|
206
|
+
description: "Validate the registry, print its digest and the line table.",
|
|
207
|
+
positional: [],
|
|
208
|
+
valueFlags: [
|
|
209
|
+
{ key: "config", flag: "config", desc: "Path to asylumwarden.json" },
|
|
210
|
+
{ key: "stateHome", flag: "state-home", desc: "State home override" },
|
|
211
|
+
],
|
|
212
|
+
boolFlags: [],
|
|
213
|
+
},
|
|
214
|
+
];
|
|
215
|
+
|
|
216
|
+
// Pure arg -> argv mapping. Undefined/null params are omitted so core sees
|
|
217
|
+
// exactly what the caller passed (core decides required-ness, fail-closed).
|
|
218
|
+
export function buildArgv(spec, args) {
|
|
219
|
+
const argv = [...spec.command];
|
|
220
|
+
for (const p of spec.positional) {
|
|
221
|
+
if (args[p.key] !== undefined && args[p.key] !== null) argv.push(String(args[p.key]));
|
|
222
|
+
}
|
|
223
|
+
for (const f of spec.valueFlags) {
|
|
224
|
+
if (args[f.key] !== undefined && args[f.key] !== null) argv.push(`--${f.flag}`, String(args[f.key]));
|
|
225
|
+
}
|
|
226
|
+
for (const b of spec.boolFlags) {
|
|
227
|
+
if (args[b.key] === true) argv.push(`--${b.flag}`);
|
|
228
|
+
}
|
|
229
|
+
return argv;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function jsonSchemaArgs(spec) {
|
|
233
|
+
const args = {};
|
|
234
|
+
for (const p of spec.positional) args[p.key] = { type: "string", description: p.desc };
|
|
235
|
+
for (const f of spec.valueFlags) args[f.key] = { type: f.type ?? "string", description: f.desc };
|
|
236
|
+
for (const b of spec.boolFlags) args[b.key] = { type: "boolean", description: b.desc };
|
|
237
|
+
return args;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function buildTools() {
|
|
241
|
+
const tools = {};
|
|
242
|
+
for (const spec of TOOL_SPECS) {
|
|
243
|
+
tools[spec.tool] = {
|
|
244
|
+
description: spec.description,
|
|
245
|
+
args: jsonSchemaArgs(spec),
|
|
246
|
+
execute: async (rawArgs) => {
|
|
247
|
+
const argv = buildArgv(spec, rawArgs ?? {});
|
|
248
|
+
let output = "";
|
|
249
|
+
const exit = await runCli(argv, { write: (chunk) => { output += chunk; } });
|
|
250
|
+
return { output, exit };
|
|
251
|
+
},
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
return tools;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
let logged = false;
|
|
258
|
+
function logOnce(reason) {
|
|
259
|
+
if (logged) return;
|
|
260
|
+
logged = true;
|
|
261
|
+
console.error(`[asylumwarden-adapter] ${reason} — no warden_* tools registered (the CLI still works).`);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Same hooks contract the historian plugin ships: server(input, options) resolves
|
|
265
|
+
// hooks whose `tool` field maps tool name -> definition. Degrades to a no-op
|
|
266
|
+
// (empty hooks, one console.error) when the host passes a missing/unexpected
|
|
267
|
+
// shape — registration must never crash host startup.
|
|
268
|
+
async function server(input, _options) {
|
|
269
|
+
try {
|
|
270
|
+
if (input === null || typeof input !== "object") {
|
|
271
|
+
logOnce(`unexpected host API shape: server(input) received ${input === null ? "null" : typeof input}`);
|
|
272
|
+
return {};
|
|
273
|
+
}
|
|
274
|
+
return { tool: buildTools() };
|
|
275
|
+
} catch (err) {
|
|
276
|
+
logOnce(`tool registration failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
277
|
+
return {};
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const plugin = { id: "asylumwarden", server };
|
|
282
|
+
export default plugin;
|
package/package.json
CHANGED
|
@@ -1,6 +1,39 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "asylumwarden",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"description": "
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "Local, file-first control plane for multi-seat AI work: registry, DAG, leases, receipts, ledger.",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"engines": {
|
|
9
|
+
"node": ">=22.22.1"
|
|
10
|
+
},
|
|
11
|
+
"bin": {
|
|
12
|
+
"asylumwarden": "bin/asylumwarden.mjs"
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"test": "node tools/workfile-gate.mjs && node --test 'test/**/*.test.mjs'",
|
|
16
|
+
"gate:imports": "node tools/import-gate.mjs",
|
|
17
|
+
"gate:workfiles": "node tools/workfile-gate.mjs"
|
|
18
|
+
},
|
|
19
|
+
"exports": {
|
|
20
|
+
".": "./src/index.mjs",
|
|
21
|
+
"./server": "./adapters/opencode/index.js"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"src",
|
|
25
|
+
"schemas",
|
|
26
|
+
"bin",
|
|
27
|
+
"adapters",
|
|
28
|
+
"README.md",
|
|
29
|
+
"LICENSE"
|
|
30
|
+
],
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "git+https://github.com/TachikomaGundam/AsylumWarden.git"
|
|
34
|
+
},
|
|
35
|
+
"homepage": "https://github.com/TachikomaGundam/AsylumWarden",
|
|
36
|
+
"bugs": {
|
|
37
|
+
"url": "https://github.com/TachikomaGundam/AsylumWarden/issues"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "asylumwarden/config.schema.json",
|
|
4
|
+
"title": "AsylumWarden project config (asylumwarden.json)",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"allOf": [
|
|
7
|
+
{
|
|
8
|
+
"anyOf": [
|
|
9
|
+
{
|
|
10
|
+
"description": "normal mode: shadow keys forbidden",
|
|
11
|
+
"properties": {
|
|
12
|
+
"version": { "const": 1 },
|
|
13
|
+
"registry": { "type": "string", "pattern": "^~?/" },
|
|
14
|
+
"registry_sha256": { "type": "string", "pattern": "^[0-9a-f]{64}$" },
|
|
15
|
+
"self": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$" },
|
|
16
|
+
"state_home": { "type": "string", "pattern": "^~?/" },
|
|
17
|
+
"mode": { "const": "normal" },
|
|
18
|
+
"kinds": {
|
|
19
|
+
"type": "object",
|
|
20
|
+
"additionalProperties": {
|
|
21
|
+
"type": "object",
|
|
22
|
+
"properties": { "description": { "type": "string", "minLength": 1, "maxLength": 4096 } },
|
|
23
|
+
"required": ["description"],
|
|
24
|
+
"additionalProperties": false
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"anchor": {
|
|
28
|
+
"anyOf": [
|
|
29
|
+
{ "type": "null" },
|
|
30
|
+
{
|
|
31
|
+
"type": "object",
|
|
32
|
+
"properties": {
|
|
33
|
+
"type": { "enum": ["command", "remote", "human-checkpoint", "file"] },
|
|
34
|
+
"target": { "type": "string", "minLength": 1, "maxLength": 4096 },
|
|
35
|
+
"signer": { "type": "string", "minLength": 1, "maxLength": 256 }
|
|
36
|
+
},
|
|
37
|
+
"required": ["type", "target"],
|
|
38
|
+
"additionalProperties": false
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"required": ["version", "registry", "registry_sha256", "self", "state_home", "mode"],
|
|
44
|
+
"additionalProperties": false
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"description": "shadow mode: shadow_of and shadow_home required",
|
|
48
|
+
"properties": {
|
|
49
|
+
"version": { "const": 1 },
|
|
50
|
+
"registry": { "type": "string", "pattern": "^~?/" },
|
|
51
|
+
"registry_sha256": { "type": "string", "pattern": "^[0-9a-f]{64}$" },
|
|
52
|
+
"self": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$" },
|
|
53
|
+
"state_home": { "type": "string", "pattern": "^~?/" },
|
|
54
|
+
"mode": { "const": "shadow" },
|
|
55
|
+
"shadow_of": { "type": "string", "pattern": "^[0-9a-f]{64}$" },
|
|
56
|
+
"shadow_home": { "type": "string", "pattern": "^/" },
|
|
57
|
+
"protect": {
|
|
58
|
+
"type": "array",
|
|
59
|
+
"maxItems": 64,
|
|
60
|
+
"items": { "type": "string", "pattern": "^~?/" }
|
|
61
|
+
},
|
|
62
|
+
"kinds": {
|
|
63
|
+
"type": "object",
|
|
64
|
+
"additionalProperties": {
|
|
65
|
+
"type": "object",
|
|
66
|
+
"properties": { "description": { "type": "string", "minLength": 1, "maxLength": 4096 } },
|
|
67
|
+
"required": ["description"],
|
|
68
|
+
"additionalProperties": false
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
"anchor": {
|
|
72
|
+
"anyOf": [
|
|
73
|
+
{ "type": "null" },
|
|
74
|
+
{
|
|
75
|
+
"type": "object",
|
|
76
|
+
"properties": {
|
|
77
|
+
"type": { "enum": ["command", "remote", "human-checkpoint", "file"] },
|
|
78
|
+
"target": { "type": "string", "minLength": 1, "maxLength": 4096 },
|
|
79
|
+
"signer": { "type": "string", "minLength": 1, "maxLength": 256 }
|
|
80
|
+
},
|
|
81
|
+
"required": ["type", "target"],
|
|
82
|
+
"additionalProperties": false
|
|
83
|
+
}
|
|
84
|
+
]
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
"required": ["version", "registry", "registry_sha256", "self", "state_home", "mode", "shadow_of", "shadow_home", "protect"],
|
|
88
|
+
"additionalProperties": false
|
|
89
|
+
}
|
|
90
|
+
]
|
|
91
|
+
}
|
|
92
|
+
]
|
|
93
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "asylumwarden/ledger.schema.json",
|
|
4
|
+
"title": "AsylumWarden ledger entry (one per JSONL line)",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"seq": { "type": "integer", "minimum": 1 },
|
|
8
|
+
"ts": { "type": "string", "format": "date-time" },
|
|
9
|
+
"type": {
|
|
10
|
+
"enum": ["genesis", "plan", "claim", "renew", "release", "requeue", "steal", "done", "fail", "anchor"]
|
|
11
|
+
},
|
|
12
|
+
"wave": { "type": ["string", "null"], "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$" },
|
|
13
|
+
"cell": { "type": ["string", "null"], "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$" },
|
|
14
|
+
"actor": { "type": ["string", "null"], "minLength": 1, "maxLength": 256 },
|
|
15
|
+
"payload": { "type": "object" },
|
|
16
|
+
"prev": { "type": "string", "pattern": "^[0-9a-f]{64}$" },
|
|
17
|
+
"hash": { "type": "string", "pattern": "^[0-9a-f]{64}$" }
|
|
18
|
+
},
|
|
19
|
+
"required": ["seq", "ts", "type", "wave", "cell", "actor", "payload", "prev", "hash"],
|
|
20
|
+
"additionalProperties": false
|
|
21
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "asylumwarden/manifest.schema.json",
|
|
4
|
+
"title": "AsylumWarden wave manifest (wave.json)",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"version": { "const": 1 },
|
|
8
|
+
"wave": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$" },
|
|
9
|
+
"cells": {
|
|
10
|
+
"type": "array",
|
|
11
|
+
"minItems": 1,
|
|
12
|
+
"maxItems": 1024,
|
|
13
|
+
"items": {
|
|
14
|
+
"type": "object",
|
|
15
|
+
"properties": {
|
|
16
|
+
"id": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$" },
|
|
17
|
+
"kind": { "type": "string", "pattern": "^[a-z][a-z0-9_-]{0,31}$" },
|
|
18
|
+
"line": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$" },
|
|
19
|
+
"cwd": { "type": "string", "pattern": "^/" },
|
|
20
|
+
"allowed_roots": {
|
|
21
|
+
"type": "array",
|
|
22
|
+
"minItems": 1,
|
|
23
|
+
"maxItems": 64,
|
|
24
|
+
"items": { "type": "string", "pattern": "^/" }
|
|
25
|
+
},
|
|
26
|
+
"read_roots": {
|
|
27
|
+
"type": "array",
|
|
28
|
+
"maxItems": 64,
|
|
29
|
+
"items": { "type": "string", "pattern": "^/" }
|
|
30
|
+
},
|
|
31
|
+
"deps": {
|
|
32
|
+
"type": "array",
|
|
33
|
+
"maxItems": 1024,
|
|
34
|
+
"items": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$" }
|
|
35
|
+
},
|
|
36
|
+
"role": { "type": "string", "minLength": 1, "maxLength": 256 },
|
|
37
|
+
"role_file": { "type": "string", "pattern": "^/" },
|
|
38
|
+
"session_started_at": { "type": "string", "format": "date-time" },
|
|
39
|
+
"brief": { "type": "string", "maxLength": 4096 },
|
|
40
|
+
"acceptance": { "type": "string", "maxLength": 4096 }
|
|
41
|
+
},
|
|
42
|
+
"required": ["id", "kind", "line", "cwd", "allowed_roots", "deps"],
|
|
43
|
+
"additionalProperties": false
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"required": ["version", "wave", "cells"],
|
|
48
|
+
"additionalProperties": false
|
|
49
|
+
}
|