openclaw-plugin-edicts 0.1.9 → 0.1.11

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/dist/index.cjs CHANGED
@@ -35,7 +35,7 @@ __export(index_exports, {
35
35
  module.exports = __toCommonJS(index_exports);
36
36
  var import_node_fs = require("fs");
37
37
  var import_node_path = __toESM(require("path"), 1);
38
- var import_edicts3 = require("edicts");
38
+ var import_edicts2 = require("edicts");
39
39
 
40
40
  // src/config.ts
41
41
  function resolveConfig(raw) {
@@ -56,7 +56,6 @@ function resolveConfig(raw) {
56
56
  }
57
57
 
58
58
  // src/context.ts
59
- var import_edicts = require("edicts");
60
59
  function createContextHook(store, config) {
61
60
  return async () => {
62
61
  try {
@@ -68,11 +67,17 @@ function createContextHook(store, config) {
68
67
  if (edicts.length === 0) {
69
68
  return {};
70
69
  }
71
- const rendered = (0, import_edicts.renderPlain)(edicts);
70
+ const rendered = renderEdictTexts(edicts);
72
71
  const prependSystemContext = wrapEdicts(rendered);
73
72
  return { prependSystemContext };
74
73
  };
75
74
  }
75
+ function renderEdictTexts(edicts) {
76
+ return edicts.map((edict) => {
77
+ const prefix = edict.category ? `[${edict.category}] ` : "";
78
+ return `- ${prefix}${edict.text}`;
79
+ }).join("\n");
80
+ }
76
81
  function wrapEdicts(rendered) {
77
82
  return [
78
83
  "## EDICTS \u2014 BINDING STANDING INSTRUCTIONS",
@@ -88,7 +93,7 @@ function wrapEdicts(rendered) {
88
93
  }
89
94
 
90
95
  // src/tools.ts
91
- var import_edicts2 = require("edicts");
96
+ var import_edicts = require("edicts");
92
97
  function text(msg) {
93
98
  return { content: [{ type: "text", text: msg }] };
94
99
  }
@@ -96,11 +101,11 @@ function serialize(value) {
96
101
  return JSON.stringify(value, null, 2);
97
102
  }
98
103
  function friendlyError(err) {
99
- if (err instanceof import_edicts2.EdictNotFoundError) return `No edict found with id '${err.id ?? "unknown"}'`;
100
- if (err instanceof import_edicts2.EdictValidationError) return `Validation error: ${err.message}`;
101
- if (err instanceof import_edicts2.EdictBudgetExceededError) return `Token budget exceeded: ${err.message}`;
102
- if (err instanceof import_edicts2.EdictCountLimitError) return `Edict count limit reached: ${err.message}`;
103
- if (err instanceof import_edicts2.EdictCategoryError) return `Category error: ${err.message}`;
104
+ if (err instanceof import_edicts.EdictNotFoundError) return `No edict found with id '${err.id ?? "unknown"}'`;
105
+ if (err instanceof import_edicts.EdictValidationError) return `Validation error: ${err.message}`;
106
+ if (err instanceof import_edicts.EdictBudgetExceededError) return `Token budget exceeded: ${err.message}`;
107
+ if (err instanceof import_edicts.EdictCountLimitError) return `Edict count limit reached: ${err.message}`;
108
+ if (err instanceof import_edicts.EdictCategoryError) return `Category error: ${err.message}`;
104
109
  if (err instanceof Error) return err.message;
105
110
  return String(err);
106
111
  }
@@ -345,7 +350,7 @@ var plugin = {
345
350
  console.log(`[edicts] register: workspaceDir=${workspaceDir}, configPath=${config.path}`);
346
351
  const storePath = import_node_path.default.resolve(workspaceDir, config.path);
347
352
  ensureEdictsFile(storePath);
348
- const store = new import_edicts3.EdictStore({
353
+ const store = new import_edicts2.EdictStore({
349
354
  path: storePath,
350
355
  format: config.format,
351
356
  tokenBudget: config.tokenBudget,
@@ -1 +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 config?: Record<string, any>;\n resolvePath?(relativePath: string): 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: 'openclaw-plugin-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 // Resolve workspace dir from config (agents.defaults.workspace), fall back to resolvePath('.')\n const configWorkspace = (api.config as any)?.agents?.defaults?.workspace;\n const workspaceDir = configWorkspace ?? api.resolvePath?.('.') ?? null;\n if (!workspaceDir) {\n console.log('[edicts] register: no workspace dir available — skipping init (install-time probe)');\n return;\n }\n\n console.log(`[edicts] register: workspaceDir=${workspaceDir}, configPath=${config.path}`);\n\n const storePath = path.resolve(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) as any);\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<{ prependSystemContext?: 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 prependSystemContext = wrapEdicts(rendered);\n\n return { prependSystemContext };\n };\n}\n\nfunction wrapEdicts(rendered: string): string {\n return [\n '## EDICTS — BINDING STANDING INSTRUCTIONS',\n '',\n 'The following are standing instructions provided by the user for this workspace/session.',\n 'Treat them as binding operational rules unless explicitly overridden by the user.',\n 'These edicts complement the system and developer instructions. If there is a conflict, follow higher-priority instructions first, then these edicts.',\n '',\n rendered,\n '',\n '## END EDICTS',\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"]}
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 config?: Record<string, any>;\n resolvePath?(relativePath: string): 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: 'openclaw-plugin-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 // Resolve workspace dir from config (agents.defaults.workspace), fall back to resolvePath('.')\n const configWorkspace = (api.config as any)?.agents?.defaults?.workspace;\n const workspaceDir = configWorkspace ?? api.resolvePath?.('.') ?? null;\n if (!workspaceDir) {\n console.log('[edicts] register: no workspace dir available — skipping init (install-time probe)');\n return;\n }\n\n console.log(`[edicts] register: workspaceDir=${workspaceDir}, configPath=${config.path}`);\n\n const storePath = path.resolve(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) as any);\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 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<{ prependSystemContext?: 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 = renderEdictTexts(edicts);\n const prependSystemContext = wrapEdicts(rendered);\n\n return { prependSystemContext };\n };\n}\n\nfunction renderEdictTexts(edicts: Array<{ text: string; category?: string }>): string {\n return edicts.map((edict) => {\n const prefix = edict.category ? `[${edict.category}] ` : '';\n return `- ${prefix}${edict.text}`;\n }).join('\\n');\n}\n\nfunction wrapEdicts(rendered: string): string {\n return [\n '## EDICTS — BINDING STANDING INSTRUCTIONS',\n '',\n 'The following are standing instructions provided by the user for this workspace/session.',\n 'Treat them as binding operational rules unless explicitly overridden by the user.',\n 'These edicts complement the system and developer instructions. If there is a conflict, follow higher-priority instructions first, then these edicts.',\n '',\n rendered,\n '',\n '## END EDICTS',\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","result","path"]}
package/dist/index.js CHANGED
@@ -22,7 +22,6 @@ function resolveConfig(raw) {
22
22
  }
23
23
 
24
24
  // src/context.ts
25
- import { renderPlain } from "edicts";
26
25
  function createContextHook(store, config) {
27
26
  return async () => {
28
27
  try {
@@ -34,11 +33,17 @@ function createContextHook(store, config) {
34
33
  if (edicts.length === 0) {
35
34
  return {};
36
35
  }
37
- const rendered = renderPlain(edicts);
36
+ const rendered = renderEdictTexts(edicts);
38
37
  const prependSystemContext = wrapEdicts(rendered);
39
38
  return { prependSystemContext };
40
39
  };
41
40
  }
41
+ function renderEdictTexts(edicts) {
42
+ return edicts.map((edict) => {
43
+ const prefix = edict.category ? `[${edict.category}] ` : "";
44
+ return `- ${prefix}${edict.text}`;
45
+ }).join("\n");
46
+ }
42
47
  function wrapEdicts(rendered) {
43
48
  return [
44
49
  "## EDICTS \u2014 BINDING STANDING INSTRUCTIONS",
package/dist/index.js.map CHANGED
@@ -1 +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 config?: Record<string, any>;\n resolvePath?(relativePath: string): 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: 'openclaw-plugin-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 // Resolve workspace dir from config (agents.defaults.workspace), fall back to resolvePath('.')\n const configWorkspace = (api.config as any)?.agents?.defaults?.workspace;\n const workspaceDir = configWorkspace ?? api.resolvePath?.('.') ?? null;\n if (!workspaceDir) {\n console.log('[edicts] register: no workspace dir available — skipping init (install-time probe)');\n return;\n }\n\n console.log(`[edicts] register: workspaceDir=${workspaceDir}, configPath=${config.path}`);\n\n const storePath = path.resolve(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) as any);\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<{ prependSystemContext?: 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 prependSystemContext = wrapEdicts(rendered);\n\n return { prependSystemContext };\n };\n}\n\nfunction wrapEdicts(rendered: string): string {\n return [\n '## EDICTS — BINDING STANDING INSTRUCTIONS',\n '',\n 'The following are standing instructions provided by the user for this workspace/session.',\n 'Treat them as binding operational rules unless explicitly overridden by the user.',\n 'These edicts complement the system and developer instructions. If there is a conflict, follow higher-priority instructions first, then these edicts.',\n '',\n rendered,\n '',\n '## END EDICTS',\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":["result"]}
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 config?: Record<string, any>;\n resolvePath?(relativePath: string): 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: 'openclaw-plugin-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 // Resolve workspace dir from config (agents.defaults.workspace), fall back to resolvePath('.')\n const configWorkspace = (api.config as any)?.agents?.defaults?.workspace;\n const workspaceDir = configWorkspace ?? api.resolvePath?.('.') ?? null;\n if (!workspaceDir) {\n console.log('[edicts] register: no workspace dir available — skipping init (install-time probe)');\n return;\n }\n\n console.log(`[edicts] register: workspaceDir=${workspaceDir}, configPath=${config.path}`);\n\n const storePath = path.resolve(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) as any);\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 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<{ prependSystemContext?: 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 = renderEdictTexts(edicts);\n const prependSystemContext = wrapEdicts(rendered);\n\n return { prependSystemContext };\n };\n}\n\nfunction renderEdictTexts(edicts: Array<{ text: string; category?: string }>): string {\n return edicts.map((edict) => {\n const prefix = edict.category ? `[${edict.category}] ` : '';\n return `- ${prefix}${edict.text}`;\n }).join('\\n');\n}\n\nfunction wrapEdicts(rendered: string): string {\n return [\n '## EDICTS — BINDING STANDING INSTRUCTIONS',\n '',\n 'The following are standing instructions provided by the user for this workspace/session.',\n 'Treat them as binding operational rules unless explicitly overridden by the user.',\n 'These edicts complement the system and developer instructions. If there is a conflict, follow higher-priority instructions first, then these edicts.',\n '',\n rendered,\n '',\n '## END EDICTS',\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":["result"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openclaw-plugin-edicts",
3
- "version": "0.1.9",
3
+ "version": "0.1.11",
4
4
  "description": "OpenClaw plugin adapter for Edicts — ground truth layer for AI agents",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",