openclaw-plugin-edicts 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/README.md +88 -0
- package/dist/index.cjs +349 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +33 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +324 -0
- package/dist/index.js.map +1 -0
- package/openclaw.plugin.json +39 -0
- package/package.json +53 -0
package/README.md
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# openclaw-plugin-edicts
|
|
2
|
+
|
|
3
|
+
OpenClaw plugin for [Edicts](https://github.com/mssteuer/edicts) — ground truth for AI agents.
|
|
4
|
+
|
|
5
|
+
Automatically injects edicts into every agent session and exposes CRUD tools so agents can read, create, and manage edicts at runtime.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
openclaw plugins install github:mssteuer/openclaw-plugin-edicts
|
|
11
|
+
openclaw gateway restart
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
That's it. The plugin auto-creates `edicts.yaml` in your workspace on first run.
|
|
15
|
+
|
|
16
|
+
## What it does
|
|
17
|
+
|
|
18
|
+
- **Context injection** — Before every prompt, relevant edicts are serialized and injected into the system context. Your agent always knows the ground truth.
|
|
19
|
+
- **Agent tools** — Seven tools registered automatically:
|
|
20
|
+
|
|
21
|
+
| Tool | Description |
|
|
22
|
+
|------|-------------|
|
|
23
|
+
| `edicts_list` | List edicts with optional filtering by category, tags, or TTL |
|
|
24
|
+
| `edicts_add` | Create a new edict |
|
|
25
|
+
| `edicts_update` | Update an existing edict by id |
|
|
26
|
+
| `edicts_remove` | Remove an edict |
|
|
27
|
+
| `edicts_search` | Free-text search across edicts |
|
|
28
|
+
| `edicts_stats` | Show store statistics (counts, token usage, budget) |
|
|
29
|
+
| `edicts_review` | Review and clean up stale/expired edicts |
|
|
30
|
+
|
|
31
|
+
## Configuration
|
|
32
|
+
|
|
33
|
+
The plugin works with zero configuration. To customize, add options to your `openclaw.json`:
|
|
34
|
+
|
|
35
|
+
```json
|
|
36
|
+
{
|
|
37
|
+
"plugins": {
|
|
38
|
+
"entries": {
|
|
39
|
+
"edicts": {
|
|
40
|
+
"enabled": true,
|
|
41
|
+
"config": {
|
|
42
|
+
"path": "edicts.yaml",
|
|
43
|
+
"format": "yaml",
|
|
44
|
+
"autoInject": true,
|
|
45
|
+
"tokenBudget": 2000
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
| Option | Default | Description |
|
|
54
|
+
|--------|---------|-------------|
|
|
55
|
+
| `path` | `edicts.yaml` | Path to storage file (relative to workspace) |
|
|
56
|
+
| `format` | `yaml` | Storage format (`yaml` or `json`) |
|
|
57
|
+
| `autoInject` | `true` | Inject edicts into system context on every session |
|
|
58
|
+
| `autoInjectFilter` | `all` | Which edicts to inject (v1: only `all`) |
|
|
59
|
+
| `tokenBudget` | `2000` | Max tokens for context injection |
|
|
60
|
+
|
|
61
|
+
## How edicts work
|
|
62
|
+
|
|
63
|
+
Edicts are small, verified facts your agent treats as non-negotiable:
|
|
64
|
+
|
|
65
|
+
```yaml
|
|
66
|
+
version: 1
|
|
67
|
+
edicts:
|
|
68
|
+
- text: "v2.0 launches April 15, 2026"
|
|
69
|
+
category: product
|
|
70
|
+
confidence: verified
|
|
71
|
+
ttl: event
|
|
72
|
+
- text: "Never mention Project X publicly"
|
|
73
|
+
category: compliance
|
|
74
|
+
confidence: verified
|
|
75
|
+
ttl: permanent
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Add them via the CLI, agent tools, or edit the YAML directly.
|
|
79
|
+
|
|
80
|
+
## Links
|
|
81
|
+
|
|
82
|
+
- [Edicts library](https://github.com/mssteuer/edicts) — standalone core (no OpenClaw dependency)
|
|
83
|
+
- [edicts.ai](https://mssteuer.github.io/edicts.ai/) — docs and landing page
|
|
84
|
+
- [OpenClaw](https://openclaw.ai) — the agent platform
|
|
85
|
+
|
|
86
|
+
## License
|
|
87
|
+
|
|
88
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
default: () => index_default
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(index_exports);
|
|
36
|
+
var import_node_fs = require("fs");
|
|
37
|
+
var import_node_path = __toESM(require("path"), 1);
|
|
38
|
+
var import_edicts3 = require("edicts");
|
|
39
|
+
|
|
40
|
+
// src/config.ts
|
|
41
|
+
function resolveConfig(raw) {
|
|
42
|
+
const userPath = typeof raw.path === "string" ? raw.path : "edicts.yaml";
|
|
43
|
+
let format;
|
|
44
|
+
if (raw.format === "json" || raw.format === "yaml") {
|
|
45
|
+
format = raw.format;
|
|
46
|
+
} else {
|
|
47
|
+
format = userPath.endsWith(".json") ? "json" : "yaml";
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
path: userPath,
|
|
51
|
+
format,
|
|
52
|
+
autoInject: typeof raw.autoInject === "boolean" ? raw.autoInject : true,
|
|
53
|
+
autoInjectFilter: "all",
|
|
54
|
+
tokenBudget: typeof raw.tokenBudget === "number" ? raw.tokenBudget : 2e3
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// src/context.ts
|
|
59
|
+
var import_edicts = require("edicts");
|
|
60
|
+
function createContextHook(store, config) {
|
|
61
|
+
return async () => {
|
|
62
|
+
try {
|
|
63
|
+
await store.load();
|
|
64
|
+
} catch {
|
|
65
|
+
return {};
|
|
66
|
+
}
|
|
67
|
+
const edicts = await store.all();
|
|
68
|
+
if (edicts.length === 0) {
|
|
69
|
+
return {};
|
|
70
|
+
}
|
|
71
|
+
const rendered = (0, import_edicts.renderPlain)(edicts);
|
|
72
|
+
const appendSystemContext = wrapEdicts(rendered);
|
|
73
|
+
return { appendSystemContext };
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
function wrapEdicts(rendered) {
|
|
77
|
+
return [
|
|
78
|
+
"## Edicts (Standing Instructions)",
|
|
79
|
+
"The following are your standing instructions. Follow them unless explicitly overridden.",
|
|
80
|
+
"",
|
|
81
|
+
rendered
|
|
82
|
+
].join("\n");
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// src/tools.ts
|
|
86
|
+
var import_edicts2 = require("edicts");
|
|
87
|
+
function text(msg) {
|
|
88
|
+
return { content: [{ type: "text", text: msg }] };
|
|
89
|
+
}
|
|
90
|
+
function serialize(value) {
|
|
91
|
+
return JSON.stringify(value, null, 2);
|
|
92
|
+
}
|
|
93
|
+
function friendlyError(err) {
|
|
94
|
+
if (err instanceof import_edicts2.EdictNotFoundError) return `No edict found with id '${err.id ?? "unknown"}'`;
|
|
95
|
+
if (err instanceof import_edicts2.EdictValidationError) return `Validation error: ${err.message}`;
|
|
96
|
+
if (err instanceof import_edicts2.EdictBudgetExceededError) return `Token budget exceeded: ${err.message}`;
|
|
97
|
+
if (err instanceof import_edicts2.EdictCountLimitError) return `Edict count limit reached: ${err.message}`;
|
|
98
|
+
if (err instanceof import_edicts2.EdictCategoryError) return `Category error: ${err.message}`;
|
|
99
|
+
if (err instanceof Error) return err.message;
|
|
100
|
+
return String(err);
|
|
101
|
+
}
|
|
102
|
+
var TOOL_NAMES = [
|
|
103
|
+
"edicts_list",
|
|
104
|
+
"edicts_add",
|
|
105
|
+
"edicts_update",
|
|
106
|
+
"edicts_remove",
|
|
107
|
+
"edicts_search",
|
|
108
|
+
"edicts_stats",
|
|
109
|
+
"edicts_review"
|
|
110
|
+
];
|
|
111
|
+
async function ensureLoaded(store) {
|
|
112
|
+
await store.load();
|
|
113
|
+
return store;
|
|
114
|
+
}
|
|
115
|
+
function buildTools(store) {
|
|
116
|
+
return [
|
|
117
|
+
{
|
|
118
|
+
name: "edicts_list",
|
|
119
|
+
description: "List edicts with optional filtering by category, tags, or ttl.",
|
|
120
|
+
parameters: {
|
|
121
|
+
type: "object",
|
|
122
|
+
additionalProperties: false,
|
|
123
|
+
properties: {
|
|
124
|
+
category: { type: "string" },
|
|
125
|
+
tags: { type: "array", items: { type: "string" } },
|
|
126
|
+
ttl: { type: "string", enum: ["ephemeral", "event", "durable", "permanent"] },
|
|
127
|
+
limit: { type: "number" }
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
async execute(_id, params = {}) {
|
|
131
|
+
try {
|
|
132
|
+
const s = await ensureLoaded(store);
|
|
133
|
+
let results = await s.find(params);
|
|
134
|
+
if (typeof params.limit === "number" && params.limit > 0) {
|
|
135
|
+
results = results.slice(0, params.limit);
|
|
136
|
+
}
|
|
137
|
+
if (results.length === 0) return text("No edicts found matching the criteria.");
|
|
138
|
+
return text(`${results.length} edict(s) found:
|
|
139
|
+
|
|
140
|
+
${serialize(results)}`);
|
|
141
|
+
} catch (err) {
|
|
142
|
+
return text(`Error listing edicts: ${friendlyError(err)}`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
name: "edicts_add",
|
|
148
|
+
description: "Create a new edict (standing instruction).",
|
|
149
|
+
parameters: {
|
|
150
|
+
type: "object",
|
|
151
|
+
additionalProperties: false,
|
|
152
|
+
properties: {
|
|
153
|
+
text: { type: "string" },
|
|
154
|
+
category: { type: "string" },
|
|
155
|
+
tags: { type: "array", items: { type: "string" } },
|
|
156
|
+
confidence: { type: "string", enum: ["verified", "inferred", "user"] },
|
|
157
|
+
source: { type: "string" },
|
|
158
|
+
key: { type: "string" },
|
|
159
|
+
ttl: { type: "string", enum: ["ephemeral", "event", "durable", "permanent"] },
|
|
160
|
+
expiresAt: { type: "string" }
|
|
161
|
+
},
|
|
162
|
+
required: ["text", "category"]
|
|
163
|
+
},
|
|
164
|
+
async execute(_id, params) {
|
|
165
|
+
try {
|
|
166
|
+
const s = await ensureLoaded(store);
|
|
167
|
+
const result = await s.add(params);
|
|
168
|
+
return text(`Edict created:
|
|
169
|
+
${serialize(result)}`);
|
|
170
|
+
} catch (err) {
|
|
171
|
+
return text(`Error adding edict: ${friendlyError(err)}`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
name: "edicts_update",
|
|
177
|
+
description: "Update an existing edict by id.",
|
|
178
|
+
parameters: {
|
|
179
|
+
type: "object",
|
|
180
|
+
additionalProperties: false,
|
|
181
|
+
properties: {
|
|
182
|
+
id: { type: "string" },
|
|
183
|
+
text: { type: "string" },
|
|
184
|
+
category: { type: "string" },
|
|
185
|
+
tags: { type: "array", items: { type: "string" } },
|
|
186
|
+
confidence: { type: "string", enum: ["verified", "inferred", "user"] },
|
|
187
|
+
ttl: { type: "string", enum: ["ephemeral", "event", "durable", "permanent"] },
|
|
188
|
+
expiresAt: { type: "string" }
|
|
189
|
+
},
|
|
190
|
+
required: ["id"]
|
|
191
|
+
},
|
|
192
|
+
async execute(_id, params) {
|
|
193
|
+
try {
|
|
194
|
+
const { id, ...patch } = params;
|
|
195
|
+
const s = await ensureLoaded(store);
|
|
196
|
+
const result = await s.update(id, patch);
|
|
197
|
+
return text(`Edict updated:
|
|
198
|
+
${serialize(result)}`);
|
|
199
|
+
} catch (err) {
|
|
200
|
+
return text(`Error updating edict: ${friendlyError(err)}`);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
name: "edicts_remove",
|
|
206
|
+
description: "Remove an edict.",
|
|
207
|
+
parameters: {
|
|
208
|
+
type: "object",
|
|
209
|
+
additionalProperties: false,
|
|
210
|
+
properties: {
|
|
211
|
+
id: { type: "string" }
|
|
212
|
+
},
|
|
213
|
+
required: ["id"]
|
|
214
|
+
},
|
|
215
|
+
async execute(_id, params) {
|
|
216
|
+
try {
|
|
217
|
+
const s = await ensureLoaded(store);
|
|
218
|
+
const result = await s.remove(params.id);
|
|
219
|
+
return text(`Edict removed:
|
|
220
|
+
${serialize(result)}`);
|
|
221
|
+
} catch (err) {
|
|
222
|
+
return text(`Error removing edict: ${friendlyError(err)}`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
name: "edicts_search",
|
|
228
|
+
description: "Free-text search across edicts.",
|
|
229
|
+
parameters: {
|
|
230
|
+
type: "object",
|
|
231
|
+
additionalProperties: false,
|
|
232
|
+
properties: {
|
|
233
|
+
query: { type: "string" },
|
|
234
|
+
limit: { type: "number" }
|
|
235
|
+
},
|
|
236
|
+
required: ["query"]
|
|
237
|
+
},
|
|
238
|
+
async execute(_id, params) {
|
|
239
|
+
try {
|
|
240
|
+
const s = await ensureLoaded(store);
|
|
241
|
+
let results = await s.search(params.query);
|
|
242
|
+
if (typeof params.limit === "number" && params.limit > 0) {
|
|
243
|
+
results = results.slice(0, params.limit);
|
|
244
|
+
}
|
|
245
|
+
if (results.length === 0) return text("No edicts matched the search query.");
|
|
246
|
+
return text(`${results.length} match(es):
|
|
247
|
+
|
|
248
|
+
${serialize(results)}`);
|
|
249
|
+
} catch (err) {
|
|
250
|
+
return text(`Error searching edicts: ${friendlyError(err)}`);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
name: "edicts_stats",
|
|
256
|
+
description: "Show edict store statistics.",
|
|
257
|
+
parameters: {
|
|
258
|
+
type: "object",
|
|
259
|
+
additionalProperties: false,
|
|
260
|
+
properties: {}
|
|
261
|
+
},
|
|
262
|
+
async execute() {
|
|
263
|
+
try {
|
|
264
|
+
const s = await ensureLoaded(store);
|
|
265
|
+
const stats = await s.stats();
|
|
266
|
+
return text(`Edict store statistics:
|
|
267
|
+
|
|
268
|
+
${serialize(stats)}`);
|
|
269
|
+
} catch (err) {
|
|
270
|
+
return text(`Error fetching stats: ${friendlyError(err)}`);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
name: "edicts_review",
|
|
276
|
+
description: "Review and optionally clean up stale/expired edicts.",
|
|
277
|
+
parameters: {
|
|
278
|
+
type: "object",
|
|
279
|
+
additionalProperties: false,
|
|
280
|
+
properties: {
|
|
281
|
+
action: { type: "string", enum: ["preview", "compact"] }
|
|
282
|
+
}
|
|
283
|
+
},
|
|
284
|
+
async execute(_id, params = {}) {
|
|
285
|
+
try {
|
|
286
|
+
const s = await ensureLoaded(store);
|
|
287
|
+
const action = params.action ?? "preview";
|
|
288
|
+
if (action === "compact") {
|
|
289
|
+
const result2 = await s.review();
|
|
290
|
+
return text(`Compaction candidates (auto-compact requires LLM callback \u2014 v2):
|
|
291
|
+
|
|
292
|
+
${serialize(result2)}`);
|
|
293
|
+
}
|
|
294
|
+
const result = await s.review();
|
|
295
|
+
return text(`Review (preview):
|
|
296
|
+
|
|
297
|
+
${serialize(result)}`);
|
|
298
|
+
} catch (err) {
|
|
299
|
+
return text(`Error reviewing edicts: ${friendlyError(err)}`);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
];
|
|
304
|
+
}
|
|
305
|
+
function registerEdictTools(api, store) {
|
|
306
|
+
api.registerTool(() => buildTools(store), {
|
|
307
|
+
names: [...TOOL_NAMES],
|
|
308
|
+
optional: false
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// index.ts
|
|
313
|
+
function ensureEdictsFile(filePath) {
|
|
314
|
+
if ((0, import_node_fs.existsSync)(filePath)) return;
|
|
315
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
316
|
+
const template = [
|
|
317
|
+
"version: 1",
|
|
318
|
+
"config:",
|
|
319
|
+
" maxEdicts: 200",
|
|
320
|
+
" tokenBudget: 4000",
|
|
321
|
+
" categories: []",
|
|
322
|
+
"edicts: []",
|
|
323
|
+
"history: []",
|
|
324
|
+
""
|
|
325
|
+
].join("\n");
|
|
326
|
+
(0, import_node_fs.writeFileSync)(filePath, template, "utf-8");
|
|
327
|
+
}
|
|
328
|
+
var plugin = {
|
|
329
|
+
id: "edicts",
|
|
330
|
+
name: "Edicts",
|
|
331
|
+
description: "Inject agent edicts into context and expose CRUD tools.",
|
|
332
|
+
register(api) {
|
|
333
|
+
const config = resolveConfig(api.pluginConfig ?? {});
|
|
334
|
+
const storePath = import_node_path.default.resolve(api.workspaceDir, config.path);
|
|
335
|
+
ensureEdictsFile(storePath);
|
|
336
|
+
const store = new import_edicts3.EdictStore({
|
|
337
|
+
path: storePath,
|
|
338
|
+
format: config.format,
|
|
339
|
+
tokenBudget: config.tokenBudget,
|
|
340
|
+
autoSave: true
|
|
341
|
+
});
|
|
342
|
+
registerEdictTools(api, store);
|
|
343
|
+
if (config.autoInject) {
|
|
344
|
+
api.on("before_prompt_build", createContextHook(store, config));
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
};
|
|
348
|
+
var index_default = plugin;
|
|
349
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../index.ts","../src/config.ts","../src/context.ts","../src/tools.ts"],"sourcesContent":["import { existsSync, writeFileSync } from 'node:fs';\nimport path from 'node:path';\nimport { EdictStore } from 'edicts';\nimport { resolveConfig } from './src/config.js';\nimport { createContextHook } from './src/context.js';\nimport { registerEdictTools } from './src/tools.js';\n\n/**\n * OpenClaw plugin API surface — types inferred from OpenClaw runtime.\n * No compile-time dependency on OpenClaw; the runtime provides the API object.\n */\nexport interface OpenClawPluginApi {\n pluginConfig?: Record<string, unknown>;\n workspaceDir: string;\n registerTool(\n factory: () => Array<{\n name: string;\n description: string;\n parameters: unknown;\n execute: (id: string, params: any) => Promise<{ content: Array<{ type: 'text'; text: string }> }>;\n }>,\n opts?: { names?: string[]; optional?: boolean },\n ): void;\n on(\n hookName: 'before_prompt_build',\n handler: () => Promise<{ appendSystemContext?: string } | Record<string, never>>,\n ): void;\n}\n\n/**\n * Create a starter edicts.yaml if the file doesn't exist yet.\n * For OpenClaw users this means zero bootstrapping — install the plugin and go.\n */\nfunction ensureEdictsFile(filePath: string): void {\n if (existsSync(filePath)) return;\n const now = new Date().toISOString();\n const template = [\n 'version: 1',\n 'config:',\n ' maxEdicts: 200',\n ' tokenBudget: 4000',\n ' categories: []',\n 'edicts: []',\n 'history: []',\n '',\n ].join('\\n');\n writeFileSync(filePath, template, 'utf-8');\n}\n\nconst plugin = {\n id: 'edicts',\n name: 'Edicts',\n description: 'Inject agent edicts into context and expose CRUD tools.',\n\n register(api: OpenClawPluginApi) {\n const config = resolveConfig(api.pluginConfig ?? {});\n\n const storePath = path.resolve(api.workspaceDir, config.path);\n\n // Auto-create edicts file on first run — no manual init needed\n ensureEdictsFile(storePath);\n\n const store = new EdictStore({\n path: storePath,\n format: config.format,\n tokenBudget: config.tokenBudget,\n autoSave: true,\n });\n\n registerEdictTools(api, store);\n\n if (config.autoInject) {\n api.on('before_prompt_build', createContextHook(store, config));\n }\n },\n};\n\nexport default plugin;\n","export interface ResolvedConfig {\n path: string;\n format: 'yaml' | 'json';\n autoInject: boolean;\n autoInjectFilter: 'all';\n tokenBudget: number;\n}\n\n/**\n * Merge user-provided plugin config over defaults.\n * Infers format from path extension when not explicitly set.\n */\nexport function resolveConfig(raw: Record<string, unknown>): ResolvedConfig {\n const userPath = typeof raw.path === 'string' ? raw.path : 'edicts.yaml';\n\n let format: 'yaml' | 'json';\n if (raw.format === 'json' || raw.format === 'yaml') {\n format = raw.format;\n } else {\n format = userPath.endsWith('.json') ? 'json' : 'yaml';\n }\n\n return {\n path: userPath,\n format,\n autoInject: typeof raw.autoInject === 'boolean' ? raw.autoInject : true,\n autoInjectFilter: 'all',\n tokenBudget: typeof raw.tokenBudget === 'number' ? raw.tokenBudget : 2000,\n };\n}\n","import { renderPlain } from 'edicts';\nimport type { EdictStore } from 'edicts';\nimport type { ResolvedConfig } from './config.js';\n\n/**\n * Creates the before_prompt_build hook that injects edicts into system context.\n * v1: injects all edicts (autoInjectFilter = \"all\").\n */\nexport function createContextHook(\n store: EdictStore,\n config: ResolvedConfig,\n): () => Promise<{ appendSystemContext?: string } | Record<string, never>> {\n return async () => {\n try {\n await store.load();\n } catch {\n // File doesn't exist yet — empty store, nothing to inject\n return {};\n }\n\n const edicts = await store.all();\n\n if (edicts.length === 0) {\n return {};\n }\n\n const rendered = renderPlain(edicts);\n const appendSystemContext = wrapEdicts(rendered);\n\n return { appendSystemContext };\n };\n}\n\nfunction wrapEdicts(rendered: string): string {\n return [\n '## Edicts (Standing Instructions)',\n 'The following are your standing instructions. Follow them unless explicitly overridden.',\n '',\n rendered,\n ].join('\\n');\n}\n","import type { EdictStore } from 'edicts';\nimport type { EdictInput, FindQuery } from 'edicts';\nimport {\n EdictNotFoundError,\n EdictValidationError,\n EdictBudgetExceededError,\n EdictCountLimitError,\n EdictCategoryError,\n} from 'edicts';\n\ntype ToolResult = { content: Array<{ type: 'text'; text: string }> };\ntype Tool = {\n name: string;\n description: string;\n parameters: unknown;\n execute: (id: string, params?: any) => Promise<ToolResult>;\n};\n\nfunction text(msg: string): ToolResult {\n return { content: [{ type: 'text', text: msg }] };\n}\n\nfunction serialize(value: unknown): string {\n return JSON.stringify(value, null, 2);\n}\n\nfunction friendlyError(err: unknown): string {\n if (err instanceof EdictNotFoundError) return `No edict found with id '${(err as any).id ?? 'unknown'}'`;\n if (err instanceof EdictValidationError) return `Validation error: ${err.message}`;\n if (err instanceof EdictBudgetExceededError) return `Token budget exceeded: ${err.message}`;\n if (err instanceof EdictCountLimitError) return `Edict count limit reached: ${err.message}`;\n if (err instanceof EdictCategoryError) return `Category error: ${err.message}`;\n if (err instanceof Error) return err.message;\n return String(err);\n}\n\nconst TOOL_NAMES = [\n 'edicts_list',\n 'edicts_add',\n 'edicts_update',\n 'edicts_remove',\n 'edicts_search',\n 'edicts_stats',\n 'edicts_review',\n] as const;\n\nasync function ensureLoaded(store: EdictStore): Promise<EdictStore> {\n await store.load();\n return store;\n}\n\nfunction buildTools(store: EdictStore): Tool[] {\n return [\n {\n name: 'edicts_list',\n description: 'List edicts with optional filtering by category, tags, or ttl.',\n parameters: {\n type: 'object',\n additionalProperties: false,\n properties: {\n category: { type: 'string' },\n tags: { type: 'array', items: { type: 'string' } },\n ttl: { type: 'string', enum: ['ephemeral', 'event', 'durable', 'permanent'] },\n limit: { type: 'number' },\n },\n },\n async execute(_id: string, params: FindQuery & { limit?: number } = {}) {\n try {\n const s = await ensureLoaded(store);\n let results = await s.find(params);\n if (typeof params.limit === 'number' && params.limit > 0) {\n results = results.slice(0, params.limit);\n }\n if (results.length === 0) return text('No edicts found matching the criteria.');\n return text(`${results.length} edict(s) found:\\n\\n${serialize(results)}`);\n } catch (err: unknown) {\n return text(`Error listing edicts: ${friendlyError(err)}`);\n }\n },\n },\n {\n name: 'edicts_add',\n description: 'Create a new edict (standing instruction).',\n parameters: {\n type: 'object',\n additionalProperties: false,\n properties: {\n text: { type: 'string' },\n category: { type: 'string' },\n tags: { type: 'array', items: { type: 'string' } },\n confidence: { type: 'string', enum: ['verified', 'inferred', 'user'] },\n source: { type: 'string' },\n key: { type: 'string' },\n ttl: { type: 'string', enum: ['ephemeral', 'event', 'durable', 'permanent'] },\n expiresAt: { type: 'string' },\n },\n required: ['text', 'category'],\n },\n async execute(_id: string, params: EdictInput) {\n try {\n const s = await ensureLoaded(store);\n const result = await s.add(params);\n return text(`Edict created:\\n${serialize(result)}`);\n } catch (err: unknown) {\n return text(`Error adding edict: ${friendlyError(err)}`);\n }\n },\n },\n {\n name: 'edicts_update',\n description: 'Update an existing edict by id.',\n parameters: {\n type: 'object',\n additionalProperties: false,\n properties: {\n id: { type: 'string' },\n text: { type: 'string' },\n category: { type: 'string' },\n tags: { type: 'array', items: { type: 'string' } },\n confidence: { type: 'string', enum: ['verified', 'inferred', 'user'] },\n ttl: { type: 'string', enum: ['ephemeral', 'event', 'durable', 'permanent'] },\n expiresAt: { type: 'string' },\n },\n required: ['id'],\n },\n async execute(_id: string, params: { id: string } & Partial<EdictInput>) {\n try {\n const { id, ...patch } = params;\n const s = await ensureLoaded(store);\n const result = await s.update(id, patch);\n return text(`Edict updated:\\n${serialize(result)}`);\n } catch (err: unknown) {\n return text(`Error updating edict: ${friendlyError(err)}`);\n }\n },\n },\n {\n name: 'edicts_remove',\n description: 'Remove an edict.',\n parameters: {\n type: 'object',\n additionalProperties: false,\n properties: {\n id: { type: 'string' },\n },\n required: ['id'],\n },\n async execute(_id: string, params: { id: string }) {\n try {\n const s = await ensureLoaded(store);\n const result = await s.remove(params.id);\n return text(`Edict removed:\\n${serialize(result)}`);\n } catch (err: unknown) {\n return text(`Error removing edict: ${friendlyError(err)}`);\n }\n },\n },\n {\n name: 'edicts_search',\n description: 'Free-text search across edicts.',\n parameters: {\n type: 'object',\n additionalProperties: false,\n properties: {\n query: { type: 'string' },\n limit: { type: 'number' },\n },\n required: ['query'],\n },\n async execute(_id: string, params: { query: string; limit?: number }) {\n try {\n const s = await ensureLoaded(store);\n let results = await s.search(params.query);\n if (typeof params.limit === 'number' && params.limit > 0) {\n results = results.slice(0, params.limit);\n }\n if (results.length === 0) return text('No edicts matched the search query.');\n return text(`${results.length} match(es):\\n\\n${serialize(results)}`);\n } catch (err: unknown) {\n return text(`Error searching edicts: ${friendlyError(err)}`);\n }\n },\n },\n {\n name: 'edicts_stats',\n description: 'Show edict store statistics.',\n parameters: {\n type: 'object',\n additionalProperties: false,\n properties: {},\n },\n async execute() {\n try {\n const s = await ensureLoaded(store);\n const stats = await s.stats();\n return text(`Edict store statistics:\\n\\n${serialize(stats)}`);\n } catch (err: unknown) {\n return text(`Error fetching stats: ${friendlyError(err)}`);\n }\n },\n },\n {\n name: 'edicts_review',\n description: 'Review and optionally clean up stale/expired edicts.',\n parameters: {\n type: 'object',\n additionalProperties: false,\n properties: {\n action: { type: 'string', enum: ['preview', 'compact'] },\n },\n },\n async execute(_id: string, params: { action?: 'preview' | 'compact' } = {}) {\n try {\n const s = await ensureLoaded(store);\n const action = params.action ?? 'preview';\n if (action === 'compact') {\n // compact() requires a callback-driven merge (group + merged edict).\n // For now, run review() and flag compaction candidates.\n const result = await s.review();\n return text(`Compaction candidates (auto-compact requires LLM callback — v2):\\n\\n${serialize(result)}`);\n }\n const result = await s.review();\n return text(`Review (preview):\\n\\n${serialize(result)}`);\n } catch (err: unknown) {\n return text(`Error reviewing edicts: ${friendlyError(err)}`);\n }\n },\n },\n ];\n}\n\n/**\n * Register all edicts tools with the OpenClaw plugin API.\n * Tools are required (always available when plugin is enabled).\n */\nexport function registerEdictTools(\n api: { registerTool: (factory: () => Tool[], opts?: { names?: string[]; optional?: boolean }) => void },\n store: EdictStore,\n): void {\n api.registerTool(() => buildTools(store), {\n names: [...TOOL_NAMES],\n optional: false,\n });\n}\n"],"mappings":"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","names":["import_edicts","import_edicts","result","path"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenClaw plugin API surface — types inferred from OpenClaw runtime.
|
|
3
|
+
* No compile-time dependency on OpenClaw; the runtime provides the API object.
|
|
4
|
+
*/
|
|
5
|
+
interface OpenClawPluginApi {
|
|
6
|
+
pluginConfig?: Record<string, unknown>;
|
|
7
|
+
workspaceDir: string;
|
|
8
|
+
registerTool(factory: () => Array<{
|
|
9
|
+
name: string;
|
|
10
|
+
description: string;
|
|
11
|
+
parameters: unknown;
|
|
12
|
+
execute: (id: string, params: any) => Promise<{
|
|
13
|
+
content: Array<{
|
|
14
|
+
type: 'text';
|
|
15
|
+
text: string;
|
|
16
|
+
}>;
|
|
17
|
+
}>;
|
|
18
|
+
}>, opts?: {
|
|
19
|
+
names?: string[];
|
|
20
|
+
optional?: boolean;
|
|
21
|
+
}): void;
|
|
22
|
+
on(hookName: 'before_prompt_build', handler: () => Promise<{
|
|
23
|
+
appendSystemContext?: string;
|
|
24
|
+
} | Record<string, never>>): void;
|
|
25
|
+
}
|
|
26
|
+
declare const plugin: {
|
|
27
|
+
id: string;
|
|
28
|
+
name: string;
|
|
29
|
+
description: string;
|
|
30
|
+
register(api: OpenClawPluginApi): void;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export { type OpenClawPluginApi, plugin as default };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenClaw plugin API surface — types inferred from OpenClaw runtime.
|
|
3
|
+
* No compile-time dependency on OpenClaw; the runtime provides the API object.
|
|
4
|
+
*/
|
|
5
|
+
interface OpenClawPluginApi {
|
|
6
|
+
pluginConfig?: Record<string, unknown>;
|
|
7
|
+
workspaceDir: string;
|
|
8
|
+
registerTool(factory: () => Array<{
|
|
9
|
+
name: string;
|
|
10
|
+
description: string;
|
|
11
|
+
parameters: unknown;
|
|
12
|
+
execute: (id: string, params: any) => Promise<{
|
|
13
|
+
content: Array<{
|
|
14
|
+
type: 'text';
|
|
15
|
+
text: string;
|
|
16
|
+
}>;
|
|
17
|
+
}>;
|
|
18
|
+
}>, opts?: {
|
|
19
|
+
names?: string[];
|
|
20
|
+
optional?: boolean;
|
|
21
|
+
}): void;
|
|
22
|
+
on(hookName: 'before_prompt_build', handler: () => Promise<{
|
|
23
|
+
appendSystemContext?: string;
|
|
24
|
+
} | Record<string, never>>): void;
|
|
25
|
+
}
|
|
26
|
+
declare const plugin: {
|
|
27
|
+
id: string;
|
|
28
|
+
name: string;
|
|
29
|
+
description: string;
|
|
30
|
+
register(api: OpenClawPluginApi): void;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export { type OpenClawPluginApi, plugin as default };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
// index.ts
|
|
2
|
+
import { existsSync, writeFileSync } from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { EdictStore } from "edicts";
|
|
5
|
+
|
|
6
|
+
// src/config.ts
|
|
7
|
+
function resolveConfig(raw) {
|
|
8
|
+
const userPath = typeof raw.path === "string" ? raw.path : "edicts.yaml";
|
|
9
|
+
let format;
|
|
10
|
+
if (raw.format === "json" || raw.format === "yaml") {
|
|
11
|
+
format = raw.format;
|
|
12
|
+
} else {
|
|
13
|
+
format = userPath.endsWith(".json") ? "json" : "yaml";
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
path: userPath,
|
|
17
|
+
format,
|
|
18
|
+
autoInject: typeof raw.autoInject === "boolean" ? raw.autoInject : true,
|
|
19
|
+
autoInjectFilter: "all",
|
|
20
|
+
tokenBudget: typeof raw.tokenBudget === "number" ? raw.tokenBudget : 2e3
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// src/context.ts
|
|
25
|
+
import { renderPlain } from "edicts";
|
|
26
|
+
function createContextHook(store, config) {
|
|
27
|
+
return async () => {
|
|
28
|
+
try {
|
|
29
|
+
await store.load();
|
|
30
|
+
} catch {
|
|
31
|
+
return {};
|
|
32
|
+
}
|
|
33
|
+
const edicts = await store.all();
|
|
34
|
+
if (edicts.length === 0) {
|
|
35
|
+
return {};
|
|
36
|
+
}
|
|
37
|
+
const rendered = renderPlain(edicts);
|
|
38
|
+
const appendSystemContext = wrapEdicts(rendered);
|
|
39
|
+
return { appendSystemContext };
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function wrapEdicts(rendered) {
|
|
43
|
+
return [
|
|
44
|
+
"## Edicts (Standing Instructions)",
|
|
45
|
+
"The following are your standing instructions. Follow them unless explicitly overridden.",
|
|
46
|
+
"",
|
|
47
|
+
rendered
|
|
48
|
+
].join("\n");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// src/tools.ts
|
|
52
|
+
import {
|
|
53
|
+
EdictNotFoundError,
|
|
54
|
+
EdictValidationError,
|
|
55
|
+
EdictBudgetExceededError,
|
|
56
|
+
EdictCountLimitError,
|
|
57
|
+
EdictCategoryError
|
|
58
|
+
} from "edicts";
|
|
59
|
+
function text(msg) {
|
|
60
|
+
return { content: [{ type: "text", text: msg }] };
|
|
61
|
+
}
|
|
62
|
+
function serialize(value) {
|
|
63
|
+
return JSON.stringify(value, null, 2);
|
|
64
|
+
}
|
|
65
|
+
function friendlyError(err) {
|
|
66
|
+
if (err instanceof EdictNotFoundError) return `No edict found with id '${err.id ?? "unknown"}'`;
|
|
67
|
+
if (err instanceof EdictValidationError) return `Validation error: ${err.message}`;
|
|
68
|
+
if (err instanceof EdictBudgetExceededError) return `Token budget exceeded: ${err.message}`;
|
|
69
|
+
if (err instanceof EdictCountLimitError) return `Edict count limit reached: ${err.message}`;
|
|
70
|
+
if (err instanceof EdictCategoryError) return `Category error: ${err.message}`;
|
|
71
|
+
if (err instanceof Error) return err.message;
|
|
72
|
+
return String(err);
|
|
73
|
+
}
|
|
74
|
+
var TOOL_NAMES = [
|
|
75
|
+
"edicts_list",
|
|
76
|
+
"edicts_add",
|
|
77
|
+
"edicts_update",
|
|
78
|
+
"edicts_remove",
|
|
79
|
+
"edicts_search",
|
|
80
|
+
"edicts_stats",
|
|
81
|
+
"edicts_review"
|
|
82
|
+
];
|
|
83
|
+
async function ensureLoaded(store) {
|
|
84
|
+
await store.load();
|
|
85
|
+
return store;
|
|
86
|
+
}
|
|
87
|
+
function buildTools(store) {
|
|
88
|
+
return [
|
|
89
|
+
{
|
|
90
|
+
name: "edicts_list",
|
|
91
|
+
description: "List edicts with optional filtering by category, tags, or ttl.",
|
|
92
|
+
parameters: {
|
|
93
|
+
type: "object",
|
|
94
|
+
additionalProperties: false,
|
|
95
|
+
properties: {
|
|
96
|
+
category: { type: "string" },
|
|
97
|
+
tags: { type: "array", items: { type: "string" } },
|
|
98
|
+
ttl: { type: "string", enum: ["ephemeral", "event", "durable", "permanent"] },
|
|
99
|
+
limit: { type: "number" }
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
async execute(_id, params = {}) {
|
|
103
|
+
try {
|
|
104
|
+
const s = await ensureLoaded(store);
|
|
105
|
+
let results = await s.find(params);
|
|
106
|
+
if (typeof params.limit === "number" && params.limit > 0) {
|
|
107
|
+
results = results.slice(0, params.limit);
|
|
108
|
+
}
|
|
109
|
+
if (results.length === 0) return text("No edicts found matching the criteria.");
|
|
110
|
+
return text(`${results.length} edict(s) found:
|
|
111
|
+
|
|
112
|
+
${serialize(results)}`);
|
|
113
|
+
} catch (err) {
|
|
114
|
+
return text(`Error listing edicts: ${friendlyError(err)}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
name: "edicts_add",
|
|
120
|
+
description: "Create a new edict (standing instruction).",
|
|
121
|
+
parameters: {
|
|
122
|
+
type: "object",
|
|
123
|
+
additionalProperties: false,
|
|
124
|
+
properties: {
|
|
125
|
+
text: { type: "string" },
|
|
126
|
+
category: { type: "string" },
|
|
127
|
+
tags: { type: "array", items: { type: "string" } },
|
|
128
|
+
confidence: { type: "string", enum: ["verified", "inferred", "user"] },
|
|
129
|
+
source: { type: "string" },
|
|
130
|
+
key: { type: "string" },
|
|
131
|
+
ttl: { type: "string", enum: ["ephemeral", "event", "durable", "permanent"] },
|
|
132
|
+
expiresAt: { type: "string" }
|
|
133
|
+
},
|
|
134
|
+
required: ["text", "category"]
|
|
135
|
+
},
|
|
136
|
+
async execute(_id, params) {
|
|
137
|
+
try {
|
|
138
|
+
const s = await ensureLoaded(store);
|
|
139
|
+
const result = await s.add(params);
|
|
140
|
+
return text(`Edict created:
|
|
141
|
+
${serialize(result)}`);
|
|
142
|
+
} catch (err) {
|
|
143
|
+
return text(`Error adding edict: ${friendlyError(err)}`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
name: "edicts_update",
|
|
149
|
+
description: "Update an existing edict by id.",
|
|
150
|
+
parameters: {
|
|
151
|
+
type: "object",
|
|
152
|
+
additionalProperties: false,
|
|
153
|
+
properties: {
|
|
154
|
+
id: { type: "string" },
|
|
155
|
+
text: { type: "string" },
|
|
156
|
+
category: { type: "string" },
|
|
157
|
+
tags: { type: "array", items: { type: "string" } },
|
|
158
|
+
confidence: { type: "string", enum: ["verified", "inferred", "user"] },
|
|
159
|
+
ttl: { type: "string", enum: ["ephemeral", "event", "durable", "permanent"] },
|
|
160
|
+
expiresAt: { type: "string" }
|
|
161
|
+
},
|
|
162
|
+
required: ["id"]
|
|
163
|
+
},
|
|
164
|
+
async execute(_id, params) {
|
|
165
|
+
try {
|
|
166
|
+
const { id, ...patch } = params;
|
|
167
|
+
const s = await ensureLoaded(store);
|
|
168
|
+
const result = await s.update(id, patch);
|
|
169
|
+
return text(`Edict updated:
|
|
170
|
+
${serialize(result)}`);
|
|
171
|
+
} catch (err) {
|
|
172
|
+
return text(`Error updating edict: ${friendlyError(err)}`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
name: "edicts_remove",
|
|
178
|
+
description: "Remove an edict.",
|
|
179
|
+
parameters: {
|
|
180
|
+
type: "object",
|
|
181
|
+
additionalProperties: false,
|
|
182
|
+
properties: {
|
|
183
|
+
id: { type: "string" }
|
|
184
|
+
},
|
|
185
|
+
required: ["id"]
|
|
186
|
+
},
|
|
187
|
+
async execute(_id, params) {
|
|
188
|
+
try {
|
|
189
|
+
const s = await ensureLoaded(store);
|
|
190
|
+
const result = await s.remove(params.id);
|
|
191
|
+
return text(`Edict removed:
|
|
192
|
+
${serialize(result)}`);
|
|
193
|
+
} catch (err) {
|
|
194
|
+
return text(`Error removing edict: ${friendlyError(err)}`);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
name: "edicts_search",
|
|
200
|
+
description: "Free-text search across edicts.",
|
|
201
|
+
parameters: {
|
|
202
|
+
type: "object",
|
|
203
|
+
additionalProperties: false,
|
|
204
|
+
properties: {
|
|
205
|
+
query: { type: "string" },
|
|
206
|
+
limit: { type: "number" }
|
|
207
|
+
},
|
|
208
|
+
required: ["query"]
|
|
209
|
+
},
|
|
210
|
+
async execute(_id, params) {
|
|
211
|
+
try {
|
|
212
|
+
const s = await ensureLoaded(store);
|
|
213
|
+
let results = await s.search(params.query);
|
|
214
|
+
if (typeof params.limit === "number" && params.limit > 0) {
|
|
215
|
+
results = results.slice(0, params.limit);
|
|
216
|
+
}
|
|
217
|
+
if (results.length === 0) return text("No edicts matched the search query.");
|
|
218
|
+
return text(`${results.length} match(es):
|
|
219
|
+
|
|
220
|
+
${serialize(results)}`);
|
|
221
|
+
} catch (err) {
|
|
222
|
+
return text(`Error searching edicts: ${friendlyError(err)}`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
name: "edicts_stats",
|
|
228
|
+
description: "Show edict store statistics.",
|
|
229
|
+
parameters: {
|
|
230
|
+
type: "object",
|
|
231
|
+
additionalProperties: false,
|
|
232
|
+
properties: {}
|
|
233
|
+
},
|
|
234
|
+
async execute() {
|
|
235
|
+
try {
|
|
236
|
+
const s = await ensureLoaded(store);
|
|
237
|
+
const stats = await s.stats();
|
|
238
|
+
return text(`Edict store statistics:
|
|
239
|
+
|
|
240
|
+
${serialize(stats)}`);
|
|
241
|
+
} catch (err) {
|
|
242
|
+
return text(`Error fetching stats: ${friendlyError(err)}`);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
name: "edicts_review",
|
|
248
|
+
description: "Review and optionally clean up stale/expired edicts.",
|
|
249
|
+
parameters: {
|
|
250
|
+
type: "object",
|
|
251
|
+
additionalProperties: false,
|
|
252
|
+
properties: {
|
|
253
|
+
action: { type: "string", enum: ["preview", "compact"] }
|
|
254
|
+
}
|
|
255
|
+
},
|
|
256
|
+
async execute(_id, params = {}) {
|
|
257
|
+
try {
|
|
258
|
+
const s = await ensureLoaded(store);
|
|
259
|
+
const action = params.action ?? "preview";
|
|
260
|
+
if (action === "compact") {
|
|
261
|
+
const result2 = await s.review();
|
|
262
|
+
return text(`Compaction candidates (auto-compact requires LLM callback \u2014 v2):
|
|
263
|
+
|
|
264
|
+
${serialize(result2)}`);
|
|
265
|
+
}
|
|
266
|
+
const result = await s.review();
|
|
267
|
+
return text(`Review (preview):
|
|
268
|
+
|
|
269
|
+
${serialize(result)}`);
|
|
270
|
+
} catch (err) {
|
|
271
|
+
return text(`Error reviewing edicts: ${friendlyError(err)}`);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
];
|
|
276
|
+
}
|
|
277
|
+
function registerEdictTools(api, store) {
|
|
278
|
+
api.registerTool(() => buildTools(store), {
|
|
279
|
+
names: [...TOOL_NAMES],
|
|
280
|
+
optional: false
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// index.ts
|
|
285
|
+
function ensureEdictsFile(filePath) {
|
|
286
|
+
if (existsSync(filePath)) return;
|
|
287
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
288
|
+
const template = [
|
|
289
|
+
"version: 1",
|
|
290
|
+
"config:",
|
|
291
|
+
" maxEdicts: 200",
|
|
292
|
+
" tokenBudget: 4000",
|
|
293
|
+
" categories: []",
|
|
294
|
+
"edicts: []",
|
|
295
|
+
"history: []",
|
|
296
|
+
""
|
|
297
|
+
].join("\n");
|
|
298
|
+
writeFileSync(filePath, template, "utf-8");
|
|
299
|
+
}
|
|
300
|
+
var plugin = {
|
|
301
|
+
id: "edicts",
|
|
302
|
+
name: "Edicts",
|
|
303
|
+
description: "Inject agent edicts into context and expose CRUD tools.",
|
|
304
|
+
register(api) {
|
|
305
|
+
const config = resolveConfig(api.pluginConfig ?? {});
|
|
306
|
+
const storePath = path.resolve(api.workspaceDir, config.path);
|
|
307
|
+
ensureEdictsFile(storePath);
|
|
308
|
+
const store = new EdictStore({
|
|
309
|
+
path: storePath,
|
|
310
|
+
format: config.format,
|
|
311
|
+
tokenBudget: config.tokenBudget,
|
|
312
|
+
autoSave: true
|
|
313
|
+
});
|
|
314
|
+
registerEdictTools(api, store);
|
|
315
|
+
if (config.autoInject) {
|
|
316
|
+
api.on("before_prompt_build", createContextHook(store, config));
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
var index_default = plugin;
|
|
321
|
+
export {
|
|
322
|
+
index_default as default
|
|
323
|
+
};
|
|
324
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../index.ts","../src/config.ts","../src/context.ts","../src/tools.ts"],"sourcesContent":["import { existsSync, writeFileSync } from 'node:fs';\nimport path from 'node:path';\nimport { EdictStore } from 'edicts';\nimport { resolveConfig } from './src/config.js';\nimport { createContextHook } from './src/context.js';\nimport { registerEdictTools } from './src/tools.js';\n\n/**\n * OpenClaw plugin API surface — types inferred from OpenClaw runtime.\n * No compile-time dependency on OpenClaw; the runtime provides the API object.\n */\nexport interface OpenClawPluginApi {\n pluginConfig?: Record<string, unknown>;\n workspaceDir: string;\n registerTool(\n factory: () => Array<{\n name: string;\n description: string;\n parameters: unknown;\n execute: (id: string, params: any) => Promise<{ content: Array<{ type: 'text'; text: string }> }>;\n }>,\n opts?: { names?: string[]; optional?: boolean },\n ): void;\n on(\n hookName: 'before_prompt_build',\n handler: () => Promise<{ appendSystemContext?: string } | Record<string, never>>,\n ): void;\n}\n\n/**\n * Create a starter edicts.yaml if the file doesn't exist yet.\n * For OpenClaw users this means zero bootstrapping — install the plugin and go.\n */\nfunction ensureEdictsFile(filePath: string): void {\n if (existsSync(filePath)) return;\n const now = new Date().toISOString();\n const template = [\n 'version: 1',\n 'config:',\n ' maxEdicts: 200',\n ' tokenBudget: 4000',\n ' categories: []',\n 'edicts: []',\n 'history: []',\n '',\n ].join('\\n');\n writeFileSync(filePath, template, 'utf-8');\n}\n\nconst plugin = {\n id: 'edicts',\n name: 'Edicts',\n description: 'Inject agent edicts into context and expose CRUD tools.',\n\n register(api: OpenClawPluginApi) {\n const config = resolveConfig(api.pluginConfig ?? {});\n\n const storePath = path.resolve(api.workspaceDir, config.path);\n\n // Auto-create edicts file on first run — no manual init needed\n ensureEdictsFile(storePath);\n\n const store = new EdictStore({\n path: storePath,\n format: config.format,\n tokenBudget: config.tokenBudget,\n autoSave: true,\n });\n\n registerEdictTools(api, store);\n\n if (config.autoInject) {\n api.on('before_prompt_build', createContextHook(store, config));\n }\n },\n};\n\nexport default plugin;\n","export interface ResolvedConfig {\n path: string;\n format: 'yaml' | 'json';\n autoInject: boolean;\n autoInjectFilter: 'all';\n tokenBudget: number;\n}\n\n/**\n * Merge user-provided plugin config over defaults.\n * Infers format from path extension when not explicitly set.\n */\nexport function resolveConfig(raw: Record<string, unknown>): ResolvedConfig {\n const userPath = typeof raw.path === 'string' ? raw.path : 'edicts.yaml';\n\n let format: 'yaml' | 'json';\n if (raw.format === 'json' || raw.format === 'yaml') {\n format = raw.format;\n } else {\n format = userPath.endsWith('.json') ? 'json' : 'yaml';\n }\n\n return {\n path: userPath,\n format,\n autoInject: typeof raw.autoInject === 'boolean' ? raw.autoInject : true,\n autoInjectFilter: 'all',\n tokenBudget: typeof raw.tokenBudget === 'number' ? raw.tokenBudget : 2000,\n };\n}\n","import { renderPlain } from 'edicts';\nimport type { EdictStore } from 'edicts';\nimport type { ResolvedConfig } from './config.js';\n\n/**\n * Creates the before_prompt_build hook that injects edicts into system context.\n * v1: injects all edicts (autoInjectFilter = \"all\").\n */\nexport function createContextHook(\n store: EdictStore,\n config: ResolvedConfig,\n): () => Promise<{ appendSystemContext?: string } | Record<string, never>> {\n return async () => {\n try {\n await store.load();\n } catch {\n // File doesn't exist yet — empty store, nothing to inject\n return {};\n }\n\n const edicts = await store.all();\n\n if (edicts.length === 0) {\n return {};\n }\n\n const rendered = renderPlain(edicts);\n const appendSystemContext = wrapEdicts(rendered);\n\n return { appendSystemContext };\n };\n}\n\nfunction wrapEdicts(rendered: string): string {\n return [\n '## Edicts (Standing Instructions)',\n 'The following are your standing instructions. Follow them unless explicitly overridden.',\n '',\n rendered,\n ].join('\\n');\n}\n","import type { EdictStore } from 'edicts';\nimport type { EdictInput, FindQuery } from 'edicts';\nimport {\n EdictNotFoundError,\n EdictValidationError,\n EdictBudgetExceededError,\n EdictCountLimitError,\n EdictCategoryError,\n} from 'edicts';\n\ntype ToolResult = { content: Array<{ type: 'text'; text: string }> };\ntype Tool = {\n name: string;\n description: string;\n parameters: unknown;\n execute: (id: string, params?: any) => Promise<ToolResult>;\n};\n\nfunction text(msg: string): ToolResult {\n return { content: [{ type: 'text', text: msg }] };\n}\n\nfunction serialize(value: unknown): string {\n return JSON.stringify(value, null, 2);\n}\n\nfunction friendlyError(err: unknown): string {\n if (err instanceof EdictNotFoundError) return `No edict found with id '${(err as any).id ?? 'unknown'}'`;\n if (err instanceof EdictValidationError) return `Validation error: ${err.message}`;\n if (err instanceof EdictBudgetExceededError) return `Token budget exceeded: ${err.message}`;\n if (err instanceof EdictCountLimitError) return `Edict count limit reached: ${err.message}`;\n if (err instanceof EdictCategoryError) return `Category error: ${err.message}`;\n if (err instanceof Error) return err.message;\n return String(err);\n}\n\nconst TOOL_NAMES = [\n 'edicts_list',\n 'edicts_add',\n 'edicts_update',\n 'edicts_remove',\n 'edicts_search',\n 'edicts_stats',\n 'edicts_review',\n] as const;\n\nasync function ensureLoaded(store: EdictStore): Promise<EdictStore> {\n await store.load();\n return store;\n}\n\nfunction buildTools(store: EdictStore): Tool[] {\n return [\n {\n name: 'edicts_list',\n description: 'List edicts with optional filtering by category, tags, or ttl.',\n parameters: {\n type: 'object',\n additionalProperties: false,\n properties: {\n category: { type: 'string' },\n tags: { type: 'array', items: { type: 'string' } },\n ttl: { type: 'string', enum: ['ephemeral', 'event', 'durable', 'permanent'] },\n limit: { type: 'number' },\n },\n },\n async execute(_id: string, params: FindQuery & { limit?: number } = {}) {\n try {\n const s = await ensureLoaded(store);\n let results = await s.find(params);\n if (typeof params.limit === 'number' && params.limit > 0) {\n results = results.slice(0, params.limit);\n }\n if (results.length === 0) return text('No edicts found matching the criteria.');\n return text(`${results.length} edict(s) found:\\n\\n${serialize(results)}`);\n } catch (err: unknown) {\n return text(`Error listing edicts: ${friendlyError(err)}`);\n }\n },\n },\n {\n name: 'edicts_add',\n description: 'Create a new edict (standing instruction).',\n parameters: {\n type: 'object',\n additionalProperties: false,\n properties: {\n text: { type: 'string' },\n category: { type: 'string' },\n tags: { type: 'array', items: { type: 'string' } },\n confidence: { type: 'string', enum: ['verified', 'inferred', 'user'] },\n source: { type: 'string' },\n key: { type: 'string' },\n ttl: { type: 'string', enum: ['ephemeral', 'event', 'durable', 'permanent'] },\n expiresAt: { type: 'string' },\n },\n required: ['text', 'category'],\n },\n async execute(_id: string, params: EdictInput) {\n try {\n const s = await ensureLoaded(store);\n const result = await s.add(params);\n return text(`Edict created:\\n${serialize(result)}`);\n } catch (err: unknown) {\n return text(`Error adding edict: ${friendlyError(err)}`);\n }\n },\n },\n {\n name: 'edicts_update',\n description: 'Update an existing edict by id.',\n parameters: {\n type: 'object',\n additionalProperties: false,\n properties: {\n id: { type: 'string' },\n text: { type: 'string' },\n category: { type: 'string' },\n tags: { type: 'array', items: { type: 'string' } },\n confidence: { type: 'string', enum: ['verified', 'inferred', 'user'] },\n ttl: { type: 'string', enum: ['ephemeral', 'event', 'durable', 'permanent'] },\n expiresAt: { type: 'string' },\n },\n required: ['id'],\n },\n async execute(_id: string, params: { id: string } & Partial<EdictInput>) {\n try {\n const { id, ...patch } = params;\n const s = await ensureLoaded(store);\n const result = await s.update(id, patch);\n return text(`Edict updated:\\n${serialize(result)}`);\n } catch (err: unknown) {\n return text(`Error updating edict: ${friendlyError(err)}`);\n }\n },\n },\n {\n name: 'edicts_remove',\n description: 'Remove an edict.',\n parameters: {\n type: 'object',\n additionalProperties: false,\n properties: {\n id: { type: 'string' },\n },\n required: ['id'],\n },\n async execute(_id: string, params: { id: string }) {\n try {\n const s = await ensureLoaded(store);\n const result = await s.remove(params.id);\n return text(`Edict removed:\\n${serialize(result)}`);\n } catch (err: unknown) {\n return text(`Error removing edict: ${friendlyError(err)}`);\n }\n },\n },\n {\n name: 'edicts_search',\n description: 'Free-text search across edicts.',\n parameters: {\n type: 'object',\n additionalProperties: false,\n properties: {\n query: { type: 'string' },\n limit: { type: 'number' },\n },\n required: ['query'],\n },\n async execute(_id: string, params: { query: string; limit?: number }) {\n try {\n const s = await ensureLoaded(store);\n let results = await s.search(params.query);\n if (typeof params.limit === 'number' && params.limit > 0) {\n results = results.slice(0, params.limit);\n }\n if (results.length === 0) return text('No edicts matched the search query.');\n return text(`${results.length} match(es):\\n\\n${serialize(results)}`);\n } catch (err: unknown) {\n return text(`Error searching edicts: ${friendlyError(err)}`);\n }\n },\n },\n {\n name: 'edicts_stats',\n description: 'Show edict store statistics.',\n parameters: {\n type: 'object',\n additionalProperties: false,\n properties: {},\n },\n async execute() {\n try {\n const s = await ensureLoaded(store);\n const stats = await s.stats();\n return text(`Edict store statistics:\\n\\n${serialize(stats)}`);\n } catch (err: unknown) {\n return text(`Error fetching stats: ${friendlyError(err)}`);\n }\n },\n },\n {\n name: 'edicts_review',\n description: 'Review and optionally clean up stale/expired edicts.',\n parameters: {\n type: 'object',\n additionalProperties: false,\n properties: {\n action: { type: 'string', enum: ['preview', 'compact'] },\n },\n },\n async execute(_id: string, params: { action?: 'preview' | 'compact' } = {}) {\n try {\n const s = await ensureLoaded(store);\n const action = params.action ?? 'preview';\n if (action === 'compact') {\n // compact() requires a callback-driven merge (group + merged edict).\n // For now, run review() and flag compaction candidates.\n const result = await s.review();\n return text(`Compaction candidates (auto-compact requires LLM callback — v2):\\n\\n${serialize(result)}`);\n }\n const result = await s.review();\n return text(`Review (preview):\\n\\n${serialize(result)}`);\n } catch (err: unknown) {\n return text(`Error reviewing edicts: ${friendlyError(err)}`);\n }\n },\n },\n ];\n}\n\n/**\n * Register all edicts tools with the OpenClaw plugin API.\n * Tools are required (always available when plugin is enabled).\n */\nexport function registerEdictTools(\n api: { registerTool: (factory: () => Tool[], opts?: { names?: string[]; optional?: boolean }) => void },\n store: EdictStore,\n): void {\n api.registerTool(() => buildTools(store), {\n names: [...TOOL_NAMES],\n optional: false,\n });\n}\n"],"mappings":";AAAA,SAAS,YAAY,qBAAqB;AAC1C,OAAO,UAAU;AACjB,SAAS,kBAAkB;;;ACUpB,SAAS,cAAc,KAA8C;AAC1E,QAAM,WAAW,OAAO,IAAI,SAAS,WAAW,IAAI,OAAO;AAE3D,MAAI;AACJ,MAAI,IAAI,WAAW,UAAU,IAAI,WAAW,QAAQ;AAClD,aAAS,IAAI;AAAA,EACf,OAAO;AACL,aAAS,SAAS,SAAS,OAAO,IAAI,SAAS;AAAA,EACjD;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,IACA,YAAY,OAAO,IAAI,eAAe,YAAY,IAAI,aAAa;AAAA,IACnE,kBAAkB;AAAA,IAClB,aAAa,OAAO,IAAI,gBAAgB,WAAW,IAAI,cAAc;AAAA,EACvE;AACF;;;AC7BA,SAAS,mBAAmB;AAQrB,SAAS,kBACd,OACA,QACyE;AACzE,SAAO,YAAY;AACjB,QAAI;AACF,YAAM,MAAM,KAAK;AAAA,IACnB,QAAQ;AAEN,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,SAAS,MAAM,MAAM,IAAI;AAE/B,QAAI,OAAO,WAAW,GAAG;AACvB,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,WAAW,YAAY,MAAM;AACnC,UAAM,sBAAsB,WAAW,QAAQ;AAE/C,WAAO,EAAE,oBAAoB;AAAA,EAC/B;AACF;AAEA,SAAS,WAAW,UAA0B;AAC5C,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;;;ACtCA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAUP,SAAS,KAAK,KAAyB;AACrC,SAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,IAAI,CAAC,EAAE;AAClD;AAEA,SAAS,UAAU,OAAwB;AACzC,SAAO,KAAK,UAAU,OAAO,MAAM,CAAC;AACtC;AAEA,SAAS,cAAc,KAAsB;AAC3C,MAAI,eAAe,mBAAoB,QAAO,2BAA4B,IAAY,MAAM,SAAS;AACrG,MAAI,eAAe,qBAAsB,QAAO,qBAAqB,IAAI,OAAO;AAChF,MAAI,eAAe,yBAA0B,QAAO,0BAA0B,IAAI,OAAO;AACzF,MAAI,eAAe,qBAAsB,QAAO,8BAA8B,IAAI,OAAO;AACzF,MAAI,eAAe,mBAAoB,QAAO,mBAAmB,IAAI,OAAO;AAC5E,MAAI,eAAe,MAAO,QAAO,IAAI;AACrC,SAAO,OAAO,GAAG;AACnB;AAEA,IAAM,aAAa;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,eAAe,aAAa,OAAwC;AAClE,QAAM,MAAM,KAAK;AACjB,SAAO;AACT;AAEA,SAAS,WAAW,OAA2B;AAC7C,SAAO;AAAA,IACL;AAAA,MACE,MAAM;AAAA,MACN,aAAa;AAAA,MACb,YAAY;AAAA,QACV,MAAM;AAAA,QACN,sBAAsB;AAAA,QACtB,YAAY;AAAA,UACV,UAAU,EAAE,MAAM,SAAS;AAAA,UAC3B,MAAM,EAAE,MAAM,SAAS,OAAO,EAAE,MAAM,SAAS,EAAE;AAAA,UACjD,KAAK,EAAE,MAAM,UAAU,MAAM,CAAC,aAAa,SAAS,WAAW,WAAW,EAAE;AAAA,UAC5E,OAAO,EAAE,MAAM,SAAS;AAAA,QAC1B;AAAA,MACF;AAAA,MACA,MAAM,QAAQ,KAAa,SAAyC,CAAC,GAAG;AACtE,YAAI;AACF,gBAAM,IAAI,MAAM,aAAa,KAAK;AAClC,cAAI,UAAU,MAAM,EAAE,KAAK,MAAM;AACjC,cAAI,OAAO,OAAO,UAAU,YAAY,OAAO,QAAQ,GAAG;AACxD,sBAAU,QAAQ,MAAM,GAAG,OAAO,KAAK;AAAA,UACzC;AACA,cAAI,QAAQ,WAAW,EAAG,QAAO,KAAK,wCAAwC;AAC9E,iBAAO,KAAK,GAAG,QAAQ,MAAM;AAAA;AAAA,EAAuB,UAAU,OAAO,CAAC,EAAE;AAAA,QAC1E,SAAS,KAAc;AACrB,iBAAO,KAAK,yBAAyB,cAAc,GAAG,CAAC,EAAE;AAAA,QAC3D;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,aAAa;AAAA,MACb,YAAY;AAAA,QACV,MAAM;AAAA,QACN,sBAAsB;AAAA,QACtB,YAAY;AAAA,UACV,MAAM,EAAE,MAAM,SAAS;AAAA,UACvB,UAAU,EAAE,MAAM,SAAS;AAAA,UAC3B,MAAM,EAAE,MAAM,SAAS,OAAO,EAAE,MAAM,SAAS,EAAE;AAAA,UACjD,YAAY,EAAE,MAAM,UAAU,MAAM,CAAC,YAAY,YAAY,MAAM,EAAE;AAAA,UACrE,QAAQ,EAAE,MAAM,SAAS;AAAA,UACzB,KAAK,EAAE,MAAM,SAAS;AAAA,UACtB,KAAK,EAAE,MAAM,UAAU,MAAM,CAAC,aAAa,SAAS,WAAW,WAAW,EAAE;AAAA,UAC5E,WAAW,EAAE,MAAM,SAAS;AAAA,QAC9B;AAAA,QACA,UAAU,CAAC,QAAQ,UAAU;AAAA,MAC/B;AAAA,MACA,MAAM,QAAQ,KAAa,QAAoB;AAC7C,YAAI;AACF,gBAAM,IAAI,MAAM,aAAa,KAAK;AAClC,gBAAM,SAAS,MAAM,EAAE,IAAI,MAAM;AACjC,iBAAO,KAAK;AAAA,EAAmB,UAAU,MAAM,CAAC,EAAE;AAAA,QACpD,SAAS,KAAc;AACrB,iBAAO,KAAK,uBAAuB,cAAc,GAAG,CAAC,EAAE;AAAA,QACzD;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,aAAa;AAAA,MACb,YAAY;AAAA,QACV,MAAM;AAAA,QACN,sBAAsB;AAAA,QACtB,YAAY;AAAA,UACV,IAAI,EAAE,MAAM,SAAS;AAAA,UACrB,MAAM,EAAE,MAAM,SAAS;AAAA,UACvB,UAAU,EAAE,MAAM,SAAS;AAAA,UAC3B,MAAM,EAAE,MAAM,SAAS,OAAO,EAAE,MAAM,SAAS,EAAE;AAAA,UACjD,YAAY,EAAE,MAAM,UAAU,MAAM,CAAC,YAAY,YAAY,MAAM,EAAE;AAAA,UACrE,KAAK,EAAE,MAAM,UAAU,MAAM,CAAC,aAAa,SAAS,WAAW,WAAW,EAAE;AAAA,UAC5E,WAAW,EAAE,MAAM,SAAS;AAAA,QAC9B;AAAA,QACA,UAAU,CAAC,IAAI;AAAA,MACjB;AAAA,MACA,MAAM,QAAQ,KAAa,QAA8C;AACvE,YAAI;AACF,gBAAM,EAAE,IAAI,GAAG,MAAM,IAAI;AACzB,gBAAM,IAAI,MAAM,aAAa,KAAK;AAClC,gBAAM,SAAS,MAAM,EAAE,OAAO,IAAI,KAAK;AACvC,iBAAO,KAAK;AAAA,EAAmB,UAAU,MAAM,CAAC,EAAE;AAAA,QACpD,SAAS,KAAc;AACrB,iBAAO,KAAK,yBAAyB,cAAc,GAAG,CAAC,EAAE;AAAA,QAC3D;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,aAAa;AAAA,MACb,YAAY;AAAA,QACV,MAAM;AAAA,QACN,sBAAsB;AAAA,QACtB,YAAY;AAAA,UACV,IAAI,EAAE,MAAM,SAAS;AAAA,QACvB;AAAA,QACA,UAAU,CAAC,IAAI;AAAA,MACjB;AAAA,MACA,MAAM,QAAQ,KAAa,QAAwB;AACjD,YAAI;AACF,gBAAM,IAAI,MAAM,aAAa,KAAK;AAClC,gBAAM,SAAS,MAAM,EAAE,OAAO,OAAO,EAAE;AACvC,iBAAO,KAAK;AAAA,EAAmB,UAAU,MAAM,CAAC,EAAE;AAAA,QACpD,SAAS,KAAc;AACrB,iBAAO,KAAK,yBAAyB,cAAc,GAAG,CAAC,EAAE;AAAA,QAC3D;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,aAAa;AAAA,MACb,YAAY;AAAA,QACV,MAAM;AAAA,QACN,sBAAsB;AAAA,QACtB,YAAY;AAAA,UACV,OAAO,EAAE,MAAM,SAAS;AAAA,UACxB,OAAO,EAAE,MAAM,SAAS;AAAA,QAC1B;AAAA,QACA,UAAU,CAAC,OAAO;AAAA,MACpB;AAAA,MACA,MAAM,QAAQ,KAAa,QAA2C;AACpE,YAAI;AACF,gBAAM,IAAI,MAAM,aAAa,KAAK;AAClC,cAAI,UAAU,MAAM,EAAE,OAAO,OAAO,KAAK;AACzC,cAAI,OAAO,OAAO,UAAU,YAAY,OAAO,QAAQ,GAAG;AACxD,sBAAU,QAAQ,MAAM,GAAG,OAAO,KAAK;AAAA,UACzC;AACA,cAAI,QAAQ,WAAW,EAAG,QAAO,KAAK,qCAAqC;AAC3E,iBAAO,KAAK,GAAG,QAAQ,MAAM;AAAA;AAAA,EAAkB,UAAU,OAAO,CAAC,EAAE;AAAA,QACrE,SAAS,KAAc;AACrB,iBAAO,KAAK,2BAA2B,cAAc,GAAG,CAAC,EAAE;AAAA,QAC7D;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,aAAa;AAAA,MACb,YAAY;AAAA,QACV,MAAM;AAAA,QACN,sBAAsB;AAAA,QACtB,YAAY,CAAC;AAAA,MACf;AAAA,MACA,MAAM,UAAU;AACd,YAAI;AACF,gBAAM,IAAI,MAAM,aAAa,KAAK;AAClC,gBAAM,QAAQ,MAAM,EAAE,MAAM;AAC5B,iBAAO,KAAK;AAAA;AAAA,EAA8B,UAAU,KAAK,CAAC,EAAE;AAAA,QAC9D,SAAS,KAAc;AACrB,iBAAO,KAAK,yBAAyB,cAAc,GAAG,CAAC,EAAE;AAAA,QAC3D;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,aAAa;AAAA,MACb,YAAY;AAAA,QACV,MAAM;AAAA,QACN,sBAAsB;AAAA,QACtB,YAAY;AAAA,UACV,QAAQ,EAAE,MAAM,UAAU,MAAM,CAAC,WAAW,SAAS,EAAE;AAAA,QACzD;AAAA,MACF;AAAA,MACA,MAAM,QAAQ,KAAa,SAA6C,CAAC,GAAG;AAC1E,YAAI;AACF,gBAAM,IAAI,MAAM,aAAa,KAAK;AAClC,gBAAM,SAAS,OAAO,UAAU;AAChC,cAAI,WAAW,WAAW;AAGxB,kBAAMA,UAAS,MAAM,EAAE,OAAO;AAC9B,mBAAO,KAAK;AAAA;AAAA,EAAuE,UAAUA,OAAM,CAAC,EAAE;AAAA,UACxG;AACA,gBAAM,SAAS,MAAM,EAAE,OAAO;AAC9B,iBAAO,KAAK;AAAA;AAAA,EAAwB,UAAU,MAAM,CAAC,EAAE;AAAA,QACzD,SAAS,KAAc;AACrB,iBAAO,KAAK,2BAA2B,cAAc,GAAG,CAAC,EAAE;AAAA,QAC7D;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAMO,SAAS,mBACd,KACA,OACM;AACN,MAAI,aAAa,MAAM,WAAW,KAAK,GAAG;AAAA,IACxC,OAAO,CAAC,GAAG,UAAU;AAAA,IACrB,UAAU;AAAA,EACZ,CAAC;AACH;;;AHlNA,SAAS,iBAAiB,UAAwB;AAChD,MAAI,WAAW,QAAQ,EAAG;AAC1B,QAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,QAAM,WAAW;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACX,gBAAc,UAAU,UAAU,OAAO;AAC3C;AAEA,IAAM,SAAS;AAAA,EACb,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EAEb,SAAS,KAAwB;AAC/B,UAAM,SAAS,cAAc,IAAI,gBAAgB,CAAC,CAAC;AAEnD,UAAM,YAAY,KAAK,QAAQ,IAAI,cAAc,OAAO,IAAI;AAG5D,qBAAiB,SAAS;AAE1B,UAAM,QAAQ,IAAI,WAAW;AAAA,MAC3B,MAAM;AAAA,MACN,QAAQ,OAAO;AAAA,MACf,aAAa,OAAO;AAAA,MACpB,UAAU;AAAA,IACZ,CAAC;AAED,uBAAmB,KAAK,KAAK;AAE7B,QAAI,OAAO,YAAY;AACrB,UAAI,GAAG,uBAAuB,kBAAkB,OAAO,MAAM,CAAC;AAAA,IAChE;AAAA,EACF;AACF;AAEA,IAAO,gBAAQ;","names":["result"]}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "edicts",
|
|
3
|
+
"name": "Edicts",
|
|
4
|
+
"description": "Inject agent edicts into context and expose CRUD tools.",
|
|
5
|
+
"configSchema": {
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"properties": {
|
|
9
|
+
"path": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"description": "Path to edicts storage file (YAML or JSON)"
|
|
12
|
+
},
|
|
13
|
+
"format": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"enum": ["yaml", "json"],
|
|
16
|
+
"description": "Storage format"
|
|
17
|
+
},
|
|
18
|
+
"autoInject": {
|
|
19
|
+
"type": "boolean",
|
|
20
|
+
"description": "Auto-inject edicts into system context on every session"
|
|
21
|
+
},
|
|
22
|
+
"autoInjectFilter": {
|
|
23
|
+
"type": "string",
|
|
24
|
+
"enum": ["all"],
|
|
25
|
+
"description": "Which edicts to inject (v1: only 'all')"
|
|
26
|
+
},
|
|
27
|
+
"tokenBudget": {
|
|
28
|
+
"type": "number",
|
|
29
|
+
"description": "Max tokens for context injection"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"uiHints": {
|
|
34
|
+
"path": { "label": "Storage Path", "placeholder": "edicts.yaml" },
|
|
35
|
+
"format": { "label": "Storage Format" },
|
|
36
|
+
"autoInject": { "label": "Auto-inject into Context" },
|
|
37
|
+
"tokenBudget": { "label": "Token Budget", "placeholder": "2000" }
|
|
38
|
+
}
|
|
39
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "openclaw-plugin-edicts",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "OpenClaw plugin adapter for Edicts — ground truth layer for AI agents",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./dist/index.d.cts",
|
|
17
|
+
"default": "./dist/index.cjs"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist",
|
|
23
|
+
"openclaw.plugin.json"
|
|
24
|
+
],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsup",
|
|
27
|
+
"test": "vitest run",
|
|
28
|
+
"test:watch": "vitest",
|
|
29
|
+
"lint": "tsc --noEmit",
|
|
30
|
+
"prepublishOnly": "npm run build"
|
|
31
|
+
},
|
|
32
|
+
"keywords": [
|
|
33
|
+
"openclaw",
|
|
34
|
+
"plugin",
|
|
35
|
+
"edicts",
|
|
36
|
+
"ai",
|
|
37
|
+
"agents",
|
|
38
|
+
"context"
|
|
39
|
+
],
|
|
40
|
+
"license": "MIT",
|
|
41
|
+
"engines": {
|
|
42
|
+
"node": ">=20"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"edicts": "^0.1.0"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@types/node": "^25.5.0",
|
|
49
|
+
"tsup": "^8.5.1",
|
|
50
|
+
"typescript": "^5.9.3",
|
|
51
|
+
"vitest": "^4.1.0"
|
|
52
|
+
}
|
|
53
|
+
}
|