openclaw-plugin-edicts 0.1.6 → 0.1.8

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
@@ -75,10 +75,15 @@ function createContextHook(store, config) {
75
75
  }
76
76
  function wrapEdicts(rendered) {
77
77
  return [
78
- "## Edicts (Standing Instructions)",
79
- "The following are your standing instructions. Follow them unless explicitly overridden.",
78
+ "## EDICTS \u2014 BINDING STANDING INSTRUCTIONS",
80
79
  "",
81
- rendered
80
+ "The following are standing instructions provided by the user for this workspace/session.",
81
+ "Treat them as binding operational rules unless explicitly overridden by the user.",
82
+ "These edicts complement the system and developer instructions. If there is a conflict, follow higher-priority instructions first, then these edicts.",
83
+ "",
84
+ rendered,
85
+ "",
86
+ "## END EDICTS"
82
87
  ].join("\n");
83
88
  }
84
89
 
@@ -331,7 +336,8 @@ var plugin = {
331
336
  description: "Inject agent edicts into context and expose CRUD tools.",
332
337
  register(api) {
333
338
  const config = resolveConfig(api.pluginConfig ?? {});
334
- const workspaceDir = api.resolvePath?.(".") ?? api.workspaceDir ?? null;
339
+ const configWorkspace = api.config?.agents?.defaults?.workspace;
340
+ const workspaceDir = configWorkspace ?? api.resolvePath?.(".") ?? null;
335
341
  if (!workspaceDir) {
336
342
  console.log("[edicts] register: no workspace dir available \u2014 skipping init (install-time probe)");
337
343
  return;
@@ -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 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: prefer resolvePath API, fall back to workspaceDir, then cwd\n const workspaceDir = api.resolvePath?.('.') ?? api.workspaceDir ?? 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));\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"]}
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));\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 — 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"]}
package/dist/index.d.cts CHANGED
@@ -5,6 +5,7 @@
5
5
  interface OpenClawPluginApi {
6
6
  pluginConfig?: Record<string, unknown>;
7
7
  workspaceDir?: string;
8
+ config?: Record<string, any>;
8
9
  resolvePath?(relativePath: string): string;
9
10
  registerTool(factory: () => Array<{
10
11
  name: string;
package/dist/index.d.ts CHANGED
@@ -5,6 +5,7 @@
5
5
  interface OpenClawPluginApi {
6
6
  pluginConfig?: Record<string, unknown>;
7
7
  workspaceDir?: string;
8
+ config?: Record<string, any>;
8
9
  resolvePath?(relativePath: string): string;
9
10
  registerTool(factory: () => Array<{
10
11
  name: string;
package/dist/index.js CHANGED
@@ -41,10 +41,15 @@ function createContextHook(store, config) {
41
41
  }
42
42
  function wrapEdicts(rendered) {
43
43
  return [
44
- "## Edicts (Standing Instructions)",
45
- "The following are your standing instructions. Follow them unless explicitly overridden.",
44
+ "## EDICTS \u2014 BINDING STANDING INSTRUCTIONS",
46
45
  "",
47
- rendered
46
+ "The following are standing instructions provided by the user for this workspace/session.",
47
+ "Treat them as binding operational rules unless explicitly overridden by the user.",
48
+ "These edicts complement the system and developer instructions. If there is a conflict, follow higher-priority instructions first, then these edicts.",
49
+ "",
50
+ rendered,
51
+ "",
52
+ "## END EDICTS"
48
53
  ].join("\n");
49
54
  }
50
55
 
@@ -303,7 +308,8 @@ var plugin = {
303
308
  description: "Inject agent edicts into context and expose CRUD tools.",
304
309
  register(api) {
305
310
  const config = resolveConfig(api.pluginConfig ?? {});
306
- const workspaceDir = api.resolvePath?.(".") ?? api.workspaceDir ?? null;
311
+ const configWorkspace = api.config?.agents?.defaults?.workspace;
312
+ const workspaceDir = configWorkspace ?? api.resolvePath?.(".") ?? null;
307
313
  if (!workspaceDir) {
308
314
  console.log("[edicts] register: no workspace dir available \u2014 skipping init (install-time probe)");
309
315
  return;
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 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: prefer resolvePath API, fall back to workspaceDir, then cwd\n const workspaceDir = api.resolvePath?.('.') ?? api.workspaceDir ?? 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));\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":["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));\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 — 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.6",
3
+ "version": "0.1.8",
4
4
  "description": "OpenClaw plugin adapter for Edicts — ground truth layer for AI agents",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",