@grwnd/openclaw-governance 1.9.0 → 1.9.1

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
@@ -23,7 +23,8 @@ __export(index_exports, {
23
23
  loadUsers: () => loadUsers,
24
24
  lookupUser: () => lookupUser,
25
25
  parseSessionKey: () => parseSessionKey,
26
- plugin: () => plugin
26
+ plugin: () => plugin,
27
+ register: () => register
27
28
  });
28
29
  module.exports = __toCommonJS(index_exports);
29
30
  var import_node_path = require("path");
@@ -92,11 +93,13 @@ var plugin = {
92
93
  });
93
94
  }
94
95
  };
96
+ var register = plugin.register.bind(plugin);
95
97
  // Annotate the CommonJS export names for ESM import in node:
96
98
  0 && (module.exports = {
97
99
  loadUsers,
98
100
  lookupUser,
99
101
  parseSessionKey,
100
- plugin
102
+ plugin,
103
+ register
101
104
  });
102
105
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/parse-session-key.ts","../src/load-users.ts"],"sourcesContent":["import { resolve } from 'node:path';\nimport { parseSessionKey } from './parse-session-key.js';\nimport { loadUsers, type UsersConfig } from './load-users.js';\n\nexport { parseSessionKey, type ParsedSessionKey } from './parse-session-key.js';\nexport { loadUsers, lookupUser, type UserEntry, type UsersConfig } from './load-users.js';\n\ninterface PluginConfig {\n users_file?: string;\n}\n\ninterface PluginApi {\n on(event: string, handler: (ctx: { sessionKey?: string }) => void): void;\n}\n\nfunction applyIdentity(usersConfig: UsersConfig, sessionKey: string | undefined): void {\n if (!sessionKey) return;\n\n const parsed = parseSessionKey(sessionKey);\n if (!parsed) return;\n\n const user = usersConfig.users[`${parsed.channel}:${parsed.peerId}`] ?? usersConfig.default;\n if (!user) return;\n\n process.env.GRWND_USER = `${parsed.channel}:${parsed.peerId}`;\n process.env.GRWND_ROLE = user.role;\n if (user.org_unit) {\n process.env.GRWND_ORG_UNIT = user.org_unit;\n }\n}\n\nexport const plugin = {\n id: 'grwnd-openclaw-governance',\n\n configSchema: {\n type: 'object' as const,\n properties: {\n users_file: { type: 'string' as const, default: './openclaw-users.yaml' },\n },\n },\n\n register(api: PluginApi, config: PluginConfig = {}) {\n const usersFile = resolve(config.users_file ?? './openclaw-users.yaml');\n const usersConfig = loadUsers(usersFile);\n\n api.on('session_start', (ctx) => {\n applyIdentity(usersConfig, ctx.sessionKey);\n });\n\n api.on('message_received', (ctx) => {\n applyIdentity(usersConfig, ctx.sessionKey);\n });\n },\n};\n","export interface ParsedSessionKey {\n agentId: string;\n channel: string;\n chatType: 'dm' | 'group';\n peerId: string;\n groupId?: string;\n}\n\n/**\n * Parse an OpenClaw session key into its components.\n *\n * Supported formats:\n * agent:<agentId>:<channel>:dm:<peerId>\n * agent:<agentId>:<channel>:group:<groupId>:<peerId>\n *\n * Returns null for unrecognised formats (e.g. \"agent:<id>:main\").\n */\nexport function parseSessionKey(key: string): ParsedSessionKey | null {\n const parts = key.split(':');\n\n if (parts[0] !== 'agent' || parts.length < 5) return null;\n\n const agentId = parts[1]!;\n const channel = parts[2]!;\n const chatType = parts[3];\n\n if (chatType === 'dm' && parts.length === 5) {\n return { agentId, channel, chatType: 'dm', peerId: parts[4]! };\n }\n\n if (chatType === 'group' && parts.length === 6) {\n return { agentId, channel, chatType: 'group', groupId: parts[4]!, peerId: parts[5]! };\n }\n\n return null;\n}\n","import { readFileSync } from 'node:fs';\nimport { parse as parseYaml } from 'yaml';\n\nexport interface UserEntry {\n role: string;\n org_unit?: string;\n}\n\nexport interface UsersConfig {\n users: Record<string, UserEntry>;\n default?: UserEntry;\n}\n\n/** Load and parse an openclaw-users.yaml file. */\nexport function loadUsers(filePath: string): UsersConfig {\n const raw = readFileSync(filePath, 'utf-8');\n const parsed = parseYaml(raw) as UsersConfig;\n return {\n users: parsed.users ?? {},\n default: parsed.default,\n };\n}\n\n/** Look up a channel user, falling back to `default`. Returns null if neither matches. */\nexport function lookupUser(config: UsersConfig, channel: string, peerId: string): UserEntry | null {\n const key = `${channel}:${peerId}`;\n return config.users[key] ?? config.default ?? null;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,uBAAwB;;;ACiBjB,SAAS,gBAAgB,KAAsC;AACpE,QAAM,QAAQ,IAAI,MAAM,GAAG;AAE3B,MAAI,MAAM,CAAC,MAAM,WAAW,MAAM,SAAS,EAAG,QAAO;AAErD,QAAM,UAAU,MAAM,CAAC;AACvB,QAAM,UAAU,MAAM,CAAC;AACvB,QAAM,WAAW,MAAM,CAAC;AAExB,MAAI,aAAa,QAAQ,MAAM,WAAW,GAAG;AAC3C,WAAO,EAAE,SAAS,SAAS,UAAU,MAAM,QAAQ,MAAM,CAAC,EAAG;AAAA,EAC/D;AAEA,MAAI,aAAa,WAAW,MAAM,WAAW,GAAG;AAC9C,WAAO,EAAE,SAAS,SAAS,UAAU,SAAS,SAAS,MAAM,CAAC,GAAI,QAAQ,MAAM,CAAC,EAAG;AAAA,EACtF;AAEA,SAAO;AACT;;;ACnCA,qBAA6B;AAC7B,kBAAmC;AAa5B,SAAS,UAAU,UAA+B;AACvD,QAAM,UAAM,6BAAa,UAAU,OAAO;AAC1C,QAAM,aAAS,YAAAA,OAAU,GAAG;AAC5B,SAAO;AAAA,IACL,OAAO,OAAO,SAAS,CAAC;AAAA,IACxB,SAAS,OAAO;AAAA,EAClB;AACF;AAGO,SAAS,WAAW,QAAqB,SAAiB,QAAkC;AACjG,QAAM,MAAM,GAAG,OAAO,IAAI,MAAM;AAChC,SAAO,OAAO,MAAM,GAAG,KAAK,OAAO,WAAW;AAChD;;;AFZA,SAAS,cAAc,aAA0B,YAAsC;AACrF,MAAI,CAAC,WAAY;AAEjB,QAAM,SAAS,gBAAgB,UAAU;AACzC,MAAI,CAAC,OAAQ;AAEb,QAAM,OAAO,YAAY,MAAM,GAAG,OAAO,OAAO,IAAI,OAAO,MAAM,EAAE,KAAK,YAAY;AACpF,MAAI,CAAC,KAAM;AAEX,UAAQ,IAAI,aAAa,GAAG,OAAO,OAAO,IAAI,OAAO,MAAM;AAC3D,UAAQ,IAAI,aAAa,KAAK;AAC9B,MAAI,KAAK,UAAU;AACjB,YAAQ,IAAI,iBAAiB,KAAK;AAAA,EACpC;AACF;AAEO,IAAM,SAAS;AAAA,EACpB,IAAI;AAAA,EAEJ,cAAc;AAAA,IACZ,MAAM;AAAA,IACN,YAAY;AAAA,MACV,YAAY,EAAE,MAAM,UAAmB,SAAS,wBAAwB;AAAA,IAC1E;AAAA,EACF;AAAA,EAEA,SAAS,KAAgB,SAAuB,CAAC,GAAG;AAClD,UAAM,gBAAY,0BAAQ,OAAO,cAAc,uBAAuB;AACtE,UAAM,cAAc,UAAU,SAAS;AAEvC,QAAI,GAAG,iBAAiB,CAAC,QAAQ;AAC/B,oBAAc,aAAa,IAAI,UAAU;AAAA,IAC3C,CAAC;AAED,QAAI,GAAG,oBAAoB,CAAC,QAAQ;AAClC,oBAAc,aAAa,IAAI,UAAU;AAAA,IAC3C,CAAC;AAAA,EACH;AACF;","names":["parseYaml"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/parse-session-key.ts","../src/load-users.ts"],"sourcesContent":["import { resolve } from 'node:path';\nimport { parseSessionKey } from './parse-session-key.js';\nimport { loadUsers, type UsersConfig } from './load-users.js';\n\nexport { parseSessionKey, type ParsedSessionKey } from './parse-session-key.js';\nexport { loadUsers, lookupUser, type UserEntry, type UsersConfig } from './load-users.js';\n\ninterface PluginConfig {\n users_file?: string;\n}\n\ninterface PluginApi {\n on(event: string, handler: (ctx: { sessionKey?: string }) => void): void;\n}\n\nfunction applyIdentity(usersConfig: UsersConfig, sessionKey: string | undefined): void {\n if (!sessionKey) return;\n\n const parsed = parseSessionKey(sessionKey);\n if (!parsed) return;\n\n const user = usersConfig.users[`${parsed.channel}:${parsed.peerId}`] ?? usersConfig.default;\n if (!user) return;\n\n process.env.GRWND_USER = `${parsed.channel}:${parsed.peerId}`;\n process.env.GRWND_ROLE = user.role;\n if (user.org_unit) {\n process.env.GRWND_ORG_UNIT = user.org_unit;\n }\n}\n\nexport const plugin = {\n id: 'grwnd-openclaw-governance',\n\n configSchema: {\n type: 'object' as const,\n properties: {\n users_file: { type: 'string' as const, default: './openclaw-users.yaml' },\n },\n },\n\n register(api: PluginApi, config: PluginConfig = {}) {\n const usersFile = resolve(config.users_file ?? './openclaw-users.yaml');\n const usersConfig = loadUsers(usersFile);\n\n api.on('session_start', (ctx) => {\n applyIdentity(usersConfig, ctx.sessionKey);\n });\n\n api.on('message_received', (ctx) => {\n applyIdentity(usersConfig, ctx.sessionKey);\n });\n },\n};\n\n// Top-level named export expected by OpenClaw plugin loader\nexport const register = plugin.register.bind(plugin);\n","export interface ParsedSessionKey {\n agentId: string;\n channel: string;\n chatType: 'dm' | 'group';\n peerId: string;\n groupId?: string;\n}\n\n/**\n * Parse an OpenClaw session key into its components.\n *\n * Supported formats:\n * agent:<agentId>:<channel>:dm:<peerId>\n * agent:<agentId>:<channel>:group:<groupId>:<peerId>\n *\n * Returns null for unrecognised formats (e.g. \"agent:<id>:main\").\n */\nexport function parseSessionKey(key: string): ParsedSessionKey | null {\n const parts = key.split(':');\n\n if (parts[0] !== 'agent' || parts.length < 5) return null;\n\n const agentId = parts[1]!;\n const channel = parts[2]!;\n const chatType = parts[3];\n\n if (chatType === 'dm' && parts.length === 5) {\n return { agentId, channel, chatType: 'dm', peerId: parts[4]! };\n }\n\n if (chatType === 'group' && parts.length === 6) {\n return { agentId, channel, chatType: 'group', groupId: parts[4]!, peerId: parts[5]! };\n }\n\n return null;\n}\n","import { readFileSync } from 'node:fs';\nimport { parse as parseYaml } from 'yaml';\n\nexport interface UserEntry {\n role: string;\n org_unit?: string;\n}\n\nexport interface UsersConfig {\n users: Record<string, UserEntry>;\n default?: UserEntry;\n}\n\n/** Load and parse an openclaw-users.yaml file. */\nexport function loadUsers(filePath: string): UsersConfig {\n const raw = readFileSync(filePath, 'utf-8');\n const parsed = parseYaml(raw) as UsersConfig;\n return {\n users: parsed.users ?? {},\n default: parsed.default,\n };\n}\n\n/** Look up a channel user, falling back to `default`. Returns null if neither matches. */\nexport function lookupUser(config: UsersConfig, channel: string, peerId: string): UserEntry | null {\n const key = `${channel}:${peerId}`;\n return config.users[key] ?? config.default ?? null;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,uBAAwB;;;ACiBjB,SAAS,gBAAgB,KAAsC;AACpE,QAAM,QAAQ,IAAI,MAAM,GAAG;AAE3B,MAAI,MAAM,CAAC,MAAM,WAAW,MAAM,SAAS,EAAG,QAAO;AAErD,QAAM,UAAU,MAAM,CAAC;AACvB,QAAM,UAAU,MAAM,CAAC;AACvB,QAAM,WAAW,MAAM,CAAC;AAExB,MAAI,aAAa,QAAQ,MAAM,WAAW,GAAG;AAC3C,WAAO,EAAE,SAAS,SAAS,UAAU,MAAM,QAAQ,MAAM,CAAC,EAAG;AAAA,EAC/D;AAEA,MAAI,aAAa,WAAW,MAAM,WAAW,GAAG;AAC9C,WAAO,EAAE,SAAS,SAAS,UAAU,SAAS,SAAS,MAAM,CAAC,GAAI,QAAQ,MAAM,CAAC,EAAG;AAAA,EACtF;AAEA,SAAO;AACT;;;ACnCA,qBAA6B;AAC7B,kBAAmC;AAa5B,SAAS,UAAU,UAA+B;AACvD,QAAM,UAAM,6BAAa,UAAU,OAAO;AAC1C,QAAM,aAAS,YAAAA,OAAU,GAAG;AAC5B,SAAO;AAAA,IACL,OAAO,OAAO,SAAS,CAAC;AAAA,IACxB,SAAS,OAAO;AAAA,EAClB;AACF;AAGO,SAAS,WAAW,QAAqB,SAAiB,QAAkC;AACjG,QAAM,MAAM,GAAG,OAAO,IAAI,MAAM;AAChC,SAAO,OAAO,MAAM,GAAG,KAAK,OAAO,WAAW;AAChD;;;AFZA,SAAS,cAAc,aAA0B,YAAsC;AACrF,MAAI,CAAC,WAAY;AAEjB,QAAM,SAAS,gBAAgB,UAAU;AACzC,MAAI,CAAC,OAAQ;AAEb,QAAM,OAAO,YAAY,MAAM,GAAG,OAAO,OAAO,IAAI,OAAO,MAAM,EAAE,KAAK,YAAY;AACpF,MAAI,CAAC,KAAM;AAEX,UAAQ,IAAI,aAAa,GAAG,OAAO,OAAO,IAAI,OAAO,MAAM;AAC3D,UAAQ,IAAI,aAAa,KAAK;AAC9B,MAAI,KAAK,UAAU;AACjB,YAAQ,IAAI,iBAAiB,KAAK;AAAA,EACpC;AACF;AAEO,IAAM,SAAS;AAAA,EACpB,IAAI;AAAA,EAEJ,cAAc;AAAA,IACZ,MAAM;AAAA,IACN,YAAY;AAAA,MACV,YAAY,EAAE,MAAM,UAAmB,SAAS,wBAAwB;AAAA,IAC1E;AAAA,EACF;AAAA,EAEA,SAAS,KAAgB,SAAuB,CAAC,GAAG;AAClD,UAAM,gBAAY,0BAAQ,OAAO,cAAc,uBAAuB;AACtE,UAAM,cAAc,UAAU,SAAS;AAEvC,QAAI,GAAG,iBAAiB,CAAC,QAAQ;AAC/B,oBAAc,aAAa,IAAI,UAAU;AAAA,IAC3C,CAAC;AAED,QAAI,GAAG,oBAAoB,CAAC,QAAQ;AAClC,oBAAc,aAAa,IAAI,UAAU;AAAA,IAC3C,CAAC;AAAA,EACH;AACF;AAGO,IAAM,WAAW,OAAO,SAAS,KAAK,MAAM;","names":["parseYaml"]}
package/dist/index.d.cts CHANGED
@@ -50,5 +50,6 @@ declare const plugin: {
50
50
  };
51
51
  register(api: PluginApi, config?: PluginConfig): void;
52
52
  };
53
+ declare const register: (api: PluginApi, config?: PluginConfig) => void;
53
54
 
54
- export { type ParsedSessionKey, type UserEntry, type UsersConfig, loadUsers, lookupUser, parseSessionKey, plugin };
55
+ export { type ParsedSessionKey, type UserEntry, type UsersConfig, loadUsers, lookupUser, parseSessionKey, plugin, register };
package/dist/index.d.ts CHANGED
@@ -50,5 +50,6 @@ declare const plugin: {
50
50
  };
51
51
  register(api: PluginApi, config?: PluginConfig): void;
52
52
  };
53
+ declare const register: (api: PluginApi, config?: PluginConfig) => void;
53
54
 
54
- export { type ParsedSessionKey, type UserEntry, type UsersConfig, loadUsers, lookupUser, parseSessionKey, plugin };
55
+ export { type ParsedSessionKey, type UserEntry, type UsersConfig, loadUsers, lookupUser, parseSessionKey, plugin, register };
package/dist/index.js CHANGED
@@ -65,10 +65,12 @@ var plugin = {
65
65
  });
66
66
  }
67
67
  };
68
+ var register = plugin.register.bind(plugin);
68
69
  export {
69
70
  loadUsers,
70
71
  lookupUser,
71
72
  parseSessionKey,
72
- plugin
73
+ plugin,
74
+ register
73
75
  };
74
76
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/parse-session-key.ts","../src/load-users.ts"],"sourcesContent":["import { resolve } from 'node:path';\nimport { parseSessionKey } from './parse-session-key.js';\nimport { loadUsers, type UsersConfig } from './load-users.js';\n\nexport { parseSessionKey, type ParsedSessionKey } from './parse-session-key.js';\nexport { loadUsers, lookupUser, type UserEntry, type UsersConfig } from './load-users.js';\n\ninterface PluginConfig {\n users_file?: string;\n}\n\ninterface PluginApi {\n on(event: string, handler: (ctx: { sessionKey?: string }) => void): void;\n}\n\nfunction applyIdentity(usersConfig: UsersConfig, sessionKey: string | undefined): void {\n if (!sessionKey) return;\n\n const parsed = parseSessionKey(sessionKey);\n if (!parsed) return;\n\n const user = usersConfig.users[`${parsed.channel}:${parsed.peerId}`] ?? usersConfig.default;\n if (!user) return;\n\n process.env.GRWND_USER = `${parsed.channel}:${parsed.peerId}`;\n process.env.GRWND_ROLE = user.role;\n if (user.org_unit) {\n process.env.GRWND_ORG_UNIT = user.org_unit;\n }\n}\n\nexport const plugin = {\n id: 'grwnd-openclaw-governance',\n\n configSchema: {\n type: 'object' as const,\n properties: {\n users_file: { type: 'string' as const, default: './openclaw-users.yaml' },\n },\n },\n\n register(api: PluginApi, config: PluginConfig = {}) {\n const usersFile = resolve(config.users_file ?? './openclaw-users.yaml');\n const usersConfig = loadUsers(usersFile);\n\n api.on('session_start', (ctx) => {\n applyIdentity(usersConfig, ctx.sessionKey);\n });\n\n api.on('message_received', (ctx) => {\n applyIdentity(usersConfig, ctx.sessionKey);\n });\n },\n};\n","export interface ParsedSessionKey {\n agentId: string;\n channel: string;\n chatType: 'dm' | 'group';\n peerId: string;\n groupId?: string;\n}\n\n/**\n * Parse an OpenClaw session key into its components.\n *\n * Supported formats:\n * agent:<agentId>:<channel>:dm:<peerId>\n * agent:<agentId>:<channel>:group:<groupId>:<peerId>\n *\n * Returns null for unrecognised formats (e.g. \"agent:<id>:main\").\n */\nexport function parseSessionKey(key: string): ParsedSessionKey | null {\n const parts = key.split(':');\n\n if (parts[0] !== 'agent' || parts.length < 5) return null;\n\n const agentId = parts[1]!;\n const channel = parts[2]!;\n const chatType = parts[3];\n\n if (chatType === 'dm' && parts.length === 5) {\n return { agentId, channel, chatType: 'dm', peerId: parts[4]! };\n }\n\n if (chatType === 'group' && parts.length === 6) {\n return { agentId, channel, chatType: 'group', groupId: parts[4]!, peerId: parts[5]! };\n }\n\n return null;\n}\n","import { readFileSync } from 'node:fs';\nimport { parse as parseYaml } from 'yaml';\n\nexport interface UserEntry {\n role: string;\n org_unit?: string;\n}\n\nexport interface UsersConfig {\n users: Record<string, UserEntry>;\n default?: UserEntry;\n}\n\n/** Load and parse an openclaw-users.yaml file. */\nexport function loadUsers(filePath: string): UsersConfig {\n const raw = readFileSync(filePath, 'utf-8');\n const parsed = parseYaml(raw) as UsersConfig;\n return {\n users: parsed.users ?? {},\n default: parsed.default,\n };\n}\n\n/** Look up a channel user, falling back to `default`. Returns null if neither matches. */\nexport function lookupUser(config: UsersConfig, channel: string, peerId: string): UserEntry | null {\n const key = `${channel}:${peerId}`;\n return config.users[key] ?? config.default ?? null;\n}\n"],"mappings":";AAAA,SAAS,eAAe;;;ACiBjB,SAAS,gBAAgB,KAAsC;AACpE,QAAM,QAAQ,IAAI,MAAM,GAAG;AAE3B,MAAI,MAAM,CAAC,MAAM,WAAW,MAAM,SAAS,EAAG,QAAO;AAErD,QAAM,UAAU,MAAM,CAAC;AACvB,QAAM,UAAU,MAAM,CAAC;AACvB,QAAM,WAAW,MAAM,CAAC;AAExB,MAAI,aAAa,QAAQ,MAAM,WAAW,GAAG;AAC3C,WAAO,EAAE,SAAS,SAAS,UAAU,MAAM,QAAQ,MAAM,CAAC,EAAG;AAAA,EAC/D;AAEA,MAAI,aAAa,WAAW,MAAM,WAAW,GAAG;AAC9C,WAAO,EAAE,SAAS,SAAS,UAAU,SAAS,SAAS,MAAM,CAAC,GAAI,QAAQ,MAAM,CAAC,EAAG;AAAA,EACtF;AAEA,SAAO;AACT;;;ACnCA,SAAS,oBAAoB;AAC7B,SAAS,SAAS,iBAAiB;AAa5B,SAAS,UAAU,UAA+B;AACvD,QAAM,MAAM,aAAa,UAAU,OAAO;AAC1C,QAAM,SAAS,UAAU,GAAG;AAC5B,SAAO;AAAA,IACL,OAAO,OAAO,SAAS,CAAC;AAAA,IACxB,SAAS,OAAO;AAAA,EAClB;AACF;AAGO,SAAS,WAAW,QAAqB,SAAiB,QAAkC;AACjG,QAAM,MAAM,GAAG,OAAO,IAAI,MAAM;AAChC,SAAO,OAAO,MAAM,GAAG,KAAK,OAAO,WAAW;AAChD;;;AFZA,SAAS,cAAc,aAA0B,YAAsC;AACrF,MAAI,CAAC,WAAY;AAEjB,QAAM,SAAS,gBAAgB,UAAU;AACzC,MAAI,CAAC,OAAQ;AAEb,QAAM,OAAO,YAAY,MAAM,GAAG,OAAO,OAAO,IAAI,OAAO,MAAM,EAAE,KAAK,YAAY;AACpF,MAAI,CAAC,KAAM;AAEX,UAAQ,IAAI,aAAa,GAAG,OAAO,OAAO,IAAI,OAAO,MAAM;AAC3D,UAAQ,IAAI,aAAa,KAAK;AAC9B,MAAI,KAAK,UAAU;AACjB,YAAQ,IAAI,iBAAiB,KAAK;AAAA,EACpC;AACF;AAEO,IAAM,SAAS;AAAA,EACpB,IAAI;AAAA,EAEJ,cAAc;AAAA,IACZ,MAAM;AAAA,IACN,YAAY;AAAA,MACV,YAAY,EAAE,MAAM,UAAmB,SAAS,wBAAwB;AAAA,IAC1E;AAAA,EACF;AAAA,EAEA,SAAS,KAAgB,SAAuB,CAAC,GAAG;AAClD,UAAM,YAAY,QAAQ,OAAO,cAAc,uBAAuB;AACtE,UAAM,cAAc,UAAU,SAAS;AAEvC,QAAI,GAAG,iBAAiB,CAAC,QAAQ;AAC/B,oBAAc,aAAa,IAAI,UAAU;AAAA,IAC3C,CAAC;AAED,QAAI,GAAG,oBAAoB,CAAC,QAAQ;AAClC,oBAAc,aAAa,IAAI,UAAU;AAAA,IAC3C,CAAC;AAAA,EACH;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/parse-session-key.ts","../src/load-users.ts"],"sourcesContent":["import { resolve } from 'node:path';\nimport { parseSessionKey } from './parse-session-key.js';\nimport { loadUsers, type UsersConfig } from './load-users.js';\n\nexport { parseSessionKey, type ParsedSessionKey } from './parse-session-key.js';\nexport { loadUsers, lookupUser, type UserEntry, type UsersConfig } from './load-users.js';\n\ninterface PluginConfig {\n users_file?: string;\n}\n\ninterface PluginApi {\n on(event: string, handler: (ctx: { sessionKey?: string }) => void): void;\n}\n\nfunction applyIdentity(usersConfig: UsersConfig, sessionKey: string | undefined): void {\n if (!sessionKey) return;\n\n const parsed = parseSessionKey(sessionKey);\n if (!parsed) return;\n\n const user = usersConfig.users[`${parsed.channel}:${parsed.peerId}`] ?? usersConfig.default;\n if (!user) return;\n\n process.env.GRWND_USER = `${parsed.channel}:${parsed.peerId}`;\n process.env.GRWND_ROLE = user.role;\n if (user.org_unit) {\n process.env.GRWND_ORG_UNIT = user.org_unit;\n }\n}\n\nexport const plugin = {\n id: 'grwnd-openclaw-governance',\n\n configSchema: {\n type: 'object' as const,\n properties: {\n users_file: { type: 'string' as const, default: './openclaw-users.yaml' },\n },\n },\n\n register(api: PluginApi, config: PluginConfig = {}) {\n const usersFile = resolve(config.users_file ?? './openclaw-users.yaml');\n const usersConfig = loadUsers(usersFile);\n\n api.on('session_start', (ctx) => {\n applyIdentity(usersConfig, ctx.sessionKey);\n });\n\n api.on('message_received', (ctx) => {\n applyIdentity(usersConfig, ctx.sessionKey);\n });\n },\n};\n\n// Top-level named export expected by OpenClaw plugin loader\nexport const register = plugin.register.bind(plugin);\n","export interface ParsedSessionKey {\n agentId: string;\n channel: string;\n chatType: 'dm' | 'group';\n peerId: string;\n groupId?: string;\n}\n\n/**\n * Parse an OpenClaw session key into its components.\n *\n * Supported formats:\n * agent:<agentId>:<channel>:dm:<peerId>\n * agent:<agentId>:<channel>:group:<groupId>:<peerId>\n *\n * Returns null for unrecognised formats (e.g. \"agent:<id>:main\").\n */\nexport function parseSessionKey(key: string): ParsedSessionKey | null {\n const parts = key.split(':');\n\n if (parts[0] !== 'agent' || parts.length < 5) return null;\n\n const agentId = parts[1]!;\n const channel = parts[2]!;\n const chatType = parts[3];\n\n if (chatType === 'dm' && parts.length === 5) {\n return { agentId, channel, chatType: 'dm', peerId: parts[4]! };\n }\n\n if (chatType === 'group' && parts.length === 6) {\n return { agentId, channel, chatType: 'group', groupId: parts[4]!, peerId: parts[5]! };\n }\n\n return null;\n}\n","import { readFileSync } from 'node:fs';\nimport { parse as parseYaml } from 'yaml';\n\nexport interface UserEntry {\n role: string;\n org_unit?: string;\n}\n\nexport interface UsersConfig {\n users: Record<string, UserEntry>;\n default?: UserEntry;\n}\n\n/** Load and parse an openclaw-users.yaml file. */\nexport function loadUsers(filePath: string): UsersConfig {\n const raw = readFileSync(filePath, 'utf-8');\n const parsed = parseYaml(raw) as UsersConfig;\n return {\n users: parsed.users ?? {},\n default: parsed.default,\n };\n}\n\n/** Look up a channel user, falling back to `default`. Returns null if neither matches. */\nexport function lookupUser(config: UsersConfig, channel: string, peerId: string): UserEntry | null {\n const key = `${channel}:${peerId}`;\n return config.users[key] ?? config.default ?? null;\n}\n"],"mappings":";AAAA,SAAS,eAAe;;;ACiBjB,SAAS,gBAAgB,KAAsC;AACpE,QAAM,QAAQ,IAAI,MAAM,GAAG;AAE3B,MAAI,MAAM,CAAC,MAAM,WAAW,MAAM,SAAS,EAAG,QAAO;AAErD,QAAM,UAAU,MAAM,CAAC;AACvB,QAAM,UAAU,MAAM,CAAC;AACvB,QAAM,WAAW,MAAM,CAAC;AAExB,MAAI,aAAa,QAAQ,MAAM,WAAW,GAAG;AAC3C,WAAO,EAAE,SAAS,SAAS,UAAU,MAAM,QAAQ,MAAM,CAAC,EAAG;AAAA,EAC/D;AAEA,MAAI,aAAa,WAAW,MAAM,WAAW,GAAG;AAC9C,WAAO,EAAE,SAAS,SAAS,UAAU,SAAS,SAAS,MAAM,CAAC,GAAI,QAAQ,MAAM,CAAC,EAAG;AAAA,EACtF;AAEA,SAAO;AACT;;;ACnCA,SAAS,oBAAoB;AAC7B,SAAS,SAAS,iBAAiB;AAa5B,SAAS,UAAU,UAA+B;AACvD,QAAM,MAAM,aAAa,UAAU,OAAO;AAC1C,QAAM,SAAS,UAAU,GAAG;AAC5B,SAAO;AAAA,IACL,OAAO,OAAO,SAAS,CAAC;AAAA,IACxB,SAAS,OAAO;AAAA,EAClB;AACF;AAGO,SAAS,WAAW,QAAqB,SAAiB,QAAkC;AACjG,QAAM,MAAM,GAAG,OAAO,IAAI,MAAM;AAChC,SAAO,OAAO,MAAM,GAAG,KAAK,OAAO,WAAW;AAChD;;;AFZA,SAAS,cAAc,aAA0B,YAAsC;AACrF,MAAI,CAAC,WAAY;AAEjB,QAAM,SAAS,gBAAgB,UAAU;AACzC,MAAI,CAAC,OAAQ;AAEb,QAAM,OAAO,YAAY,MAAM,GAAG,OAAO,OAAO,IAAI,OAAO,MAAM,EAAE,KAAK,YAAY;AACpF,MAAI,CAAC,KAAM;AAEX,UAAQ,IAAI,aAAa,GAAG,OAAO,OAAO,IAAI,OAAO,MAAM;AAC3D,UAAQ,IAAI,aAAa,KAAK;AAC9B,MAAI,KAAK,UAAU;AACjB,YAAQ,IAAI,iBAAiB,KAAK;AAAA,EACpC;AACF;AAEO,IAAM,SAAS;AAAA,EACpB,IAAI;AAAA,EAEJ,cAAc;AAAA,IACZ,MAAM;AAAA,IACN,YAAY;AAAA,MACV,YAAY,EAAE,MAAM,UAAmB,SAAS,wBAAwB;AAAA,IAC1E;AAAA,EACF;AAAA,EAEA,SAAS,KAAgB,SAAuB,CAAC,GAAG;AAClD,UAAM,YAAY,QAAQ,OAAO,cAAc,uBAAuB;AACtE,UAAM,cAAc,UAAU,SAAS;AAEvC,QAAI,GAAG,iBAAiB,CAAC,QAAQ;AAC/B,oBAAc,aAAa,IAAI,UAAU;AAAA,IAC3C,CAAC;AAED,QAAI,GAAG,oBAAoB,CAAC,QAAQ;AAClC,oBAAc,aAAa,IAAI,UAAU;AAAA,IAC3C,CAAC;AAAA,EACH;AACF;AAGO,IAAM,WAAW,OAAO,SAAS,KAAK,MAAM;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grwnd/openclaw-governance",
3
- "version": "1.9.0",
3
+ "version": "1.9.1",
4
4
  "description": "OpenClaw identity bridge plugin for @grwnd/pi-governance",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Grwnd AI",