@grwnd/openclaw-governance 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +102 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +54 -0
- package/dist/index.d.ts +54 -0
- package/dist/index.js +74 -0
- package/dist/index.js.map +1 -0
- package/openclaw.plugin.json +7 -0
- package/package.json +57 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
loadUsers: () => loadUsers,
|
|
24
|
+
lookupUser: () => lookupUser,
|
|
25
|
+
parseSessionKey: () => parseSessionKey,
|
|
26
|
+
plugin: () => plugin
|
|
27
|
+
});
|
|
28
|
+
module.exports = __toCommonJS(index_exports);
|
|
29
|
+
var import_node_path = require("path");
|
|
30
|
+
|
|
31
|
+
// src/parse-session-key.ts
|
|
32
|
+
function parseSessionKey(key) {
|
|
33
|
+
const parts = key.split(":");
|
|
34
|
+
if (parts[0] !== "agent" || parts.length < 5) return null;
|
|
35
|
+
const agentId = parts[1];
|
|
36
|
+
const channel = parts[2];
|
|
37
|
+
const chatType = parts[3];
|
|
38
|
+
if (chatType === "dm" && parts.length === 5) {
|
|
39
|
+
return { agentId, channel, chatType: "dm", peerId: parts[4] };
|
|
40
|
+
}
|
|
41
|
+
if (chatType === "group" && parts.length === 6) {
|
|
42
|
+
return { agentId, channel, chatType: "group", groupId: parts[4], peerId: parts[5] };
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// src/load-users.ts
|
|
48
|
+
var import_node_fs = require("fs");
|
|
49
|
+
var import_yaml = require("yaml");
|
|
50
|
+
function loadUsers(filePath) {
|
|
51
|
+
const raw = (0, import_node_fs.readFileSync)(filePath, "utf-8");
|
|
52
|
+
const parsed = (0, import_yaml.parse)(raw);
|
|
53
|
+
return {
|
|
54
|
+
users: parsed.users ?? {},
|
|
55
|
+
default: parsed.default
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function lookupUser(config, channel, peerId) {
|
|
59
|
+
const key = `${channel}:${peerId}`;
|
|
60
|
+
return config.users[key] ?? config.default ?? null;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// src/index.ts
|
|
64
|
+
function applyIdentity(usersConfig, sessionKey) {
|
|
65
|
+
if (!sessionKey) return;
|
|
66
|
+
const parsed = parseSessionKey(sessionKey);
|
|
67
|
+
if (!parsed) return;
|
|
68
|
+
const user = usersConfig.users[`${parsed.channel}:${parsed.peerId}`] ?? usersConfig.default;
|
|
69
|
+
if (!user) return;
|
|
70
|
+
process.env.GRWND_USER = `${parsed.channel}:${parsed.peerId}`;
|
|
71
|
+
process.env.GRWND_ROLE = user.role;
|
|
72
|
+
if (user.org_unit) {
|
|
73
|
+
process.env.GRWND_ORG_UNIT = user.org_unit;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
var plugin = {
|
|
77
|
+
id: "grwnd-openclaw-governance",
|
|
78
|
+
configSchema: {
|
|
79
|
+
type: "object",
|
|
80
|
+
properties: {
|
|
81
|
+
users_file: { type: "string", default: "./openclaw-users.yaml" }
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
register(api, config = {}) {
|
|
85
|
+
const usersFile = (0, import_node_path.resolve)(config.users_file ?? "./openclaw-users.yaml");
|
|
86
|
+
const usersConfig = loadUsers(usersFile);
|
|
87
|
+
api.on("session_start", (ctx) => {
|
|
88
|
+
applyIdentity(usersConfig, ctx.sessionKey);
|
|
89
|
+
});
|
|
90
|
+
api.on("message_received", (ctx) => {
|
|
91
|
+
applyIdentity(usersConfig, ctx.sessionKey);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
96
|
+
0 && (module.exports = {
|
|
97
|
+
loadUsers,
|
|
98
|
+
lookupUser,
|
|
99
|
+
parseSessionKey,
|
|
100
|
+
plugin
|
|
101
|
+
});
|
|
102
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +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(\n config: UsersConfig,\n channel: string,\n peerId: string,\n): 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,WACd,QACA,SACA,QACkB;AAClB,QAAM,MAAM,GAAG,OAAO,IAAI,MAAM;AAChC,SAAO,OAAO,MAAM,GAAG,KAAK,OAAO,WAAW;AAChD;;;AFhBA,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"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
interface ParsedSessionKey {
|
|
2
|
+
agentId: string;
|
|
3
|
+
channel: string;
|
|
4
|
+
chatType: 'dm' | 'group';
|
|
5
|
+
peerId: string;
|
|
6
|
+
groupId?: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Parse an OpenClaw session key into its components.
|
|
10
|
+
*
|
|
11
|
+
* Supported formats:
|
|
12
|
+
* agent:<agentId>:<channel>:dm:<peerId>
|
|
13
|
+
* agent:<agentId>:<channel>:group:<groupId>:<peerId>
|
|
14
|
+
*
|
|
15
|
+
* Returns null for unrecognised formats (e.g. "agent:<id>:main").
|
|
16
|
+
*/
|
|
17
|
+
declare function parseSessionKey(key: string): ParsedSessionKey | null;
|
|
18
|
+
|
|
19
|
+
interface UserEntry {
|
|
20
|
+
role: string;
|
|
21
|
+
org_unit?: string;
|
|
22
|
+
}
|
|
23
|
+
interface UsersConfig {
|
|
24
|
+
users: Record<string, UserEntry>;
|
|
25
|
+
default?: UserEntry;
|
|
26
|
+
}
|
|
27
|
+
/** Load and parse an openclaw-users.yaml file. */
|
|
28
|
+
declare function loadUsers(filePath: string): UsersConfig;
|
|
29
|
+
/** Look up a channel user, falling back to `default`. Returns null if neither matches. */
|
|
30
|
+
declare function lookupUser(config: UsersConfig, channel: string, peerId: string): UserEntry | null;
|
|
31
|
+
|
|
32
|
+
interface PluginConfig {
|
|
33
|
+
users_file?: string;
|
|
34
|
+
}
|
|
35
|
+
interface PluginApi {
|
|
36
|
+
on(event: string, handler: (ctx: {
|
|
37
|
+
sessionKey?: string;
|
|
38
|
+
}) => void): void;
|
|
39
|
+
}
|
|
40
|
+
declare const plugin: {
|
|
41
|
+
id: string;
|
|
42
|
+
configSchema: {
|
|
43
|
+
type: "object";
|
|
44
|
+
properties: {
|
|
45
|
+
users_file: {
|
|
46
|
+
type: "string";
|
|
47
|
+
default: string;
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
register(api: PluginApi, config?: PluginConfig): void;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export { type ParsedSessionKey, type UserEntry, type UsersConfig, loadUsers, lookupUser, parseSessionKey, plugin };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
interface ParsedSessionKey {
|
|
2
|
+
agentId: string;
|
|
3
|
+
channel: string;
|
|
4
|
+
chatType: 'dm' | 'group';
|
|
5
|
+
peerId: string;
|
|
6
|
+
groupId?: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Parse an OpenClaw session key into its components.
|
|
10
|
+
*
|
|
11
|
+
* Supported formats:
|
|
12
|
+
* agent:<agentId>:<channel>:dm:<peerId>
|
|
13
|
+
* agent:<agentId>:<channel>:group:<groupId>:<peerId>
|
|
14
|
+
*
|
|
15
|
+
* Returns null for unrecognised formats (e.g. "agent:<id>:main").
|
|
16
|
+
*/
|
|
17
|
+
declare function parseSessionKey(key: string): ParsedSessionKey | null;
|
|
18
|
+
|
|
19
|
+
interface UserEntry {
|
|
20
|
+
role: string;
|
|
21
|
+
org_unit?: string;
|
|
22
|
+
}
|
|
23
|
+
interface UsersConfig {
|
|
24
|
+
users: Record<string, UserEntry>;
|
|
25
|
+
default?: UserEntry;
|
|
26
|
+
}
|
|
27
|
+
/** Load and parse an openclaw-users.yaml file. */
|
|
28
|
+
declare function loadUsers(filePath: string): UsersConfig;
|
|
29
|
+
/** Look up a channel user, falling back to `default`. Returns null if neither matches. */
|
|
30
|
+
declare function lookupUser(config: UsersConfig, channel: string, peerId: string): UserEntry | null;
|
|
31
|
+
|
|
32
|
+
interface PluginConfig {
|
|
33
|
+
users_file?: string;
|
|
34
|
+
}
|
|
35
|
+
interface PluginApi {
|
|
36
|
+
on(event: string, handler: (ctx: {
|
|
37
|
+
sessionKey?: string;
|
|
38
|
+
}) => void): void;
|
|
39
|
+
}
|
|
40
|
+
declare const plugin: {
|
|
41
|
+
id: string;
|
|
42
|
+
configSchema: {
|
|
43
|
+
type: "object";
|
|
44
|
+
properties: {
|
|
45
|
+
users_file: {
|
|
46
|
+
type: "string";
|
|
47
|
+
default: string;
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
register(api: PluginApi, config?: PluginConfig): void;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export { type ParsedSessionKey, type UserEntry, type UsersConfig, loadUsers, lookupUser, parseSessionKey, plugin };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { resolve } from "path";
|
|
3
|
+
|
|
4
|
+
// src/parse-session-key.ts
|
|
5
|
+
function parseSessionKey(key) {
|
|
6
|
+
const parts = key.split(":");
|
|
7
|
+
if (parts[0] !== "agent" || parts.length < 5) return null;
|
|
8
|
+
const agentId = parts[1];
|
|
9
|
+
const channel = parts[2];
|
|
10
|
+
const chatType = parts[3];
|
|
11
|
+
if (chatType === "dm" && parts.length === 5) {
|
|
12
|
+
return { agentId, channel, chatType: "dm", peerId: parts[4] };
|
|
13
|
+
}
|
|
14
|
+
if (chatType === "group" && parts.length === 6) {
|
|
15
|
+
return { agentId, channel, chatType: "group", groupId: parts[4], peerId: parts[5] };
|
|
16
|
+
}
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// src/load-users.ts
|
|
21
|
+
import { readFileSync } from "fs";
|
|
22
|
+
import { parse as parseYaml } from "yaml";
|
|
23
|
+
function loadUsers(filePath) {
|
|
24
|
+
const raw = readFileSync(filePath, "utf-8");
|
|
25
|
+
const parsed = parseYaml(raw);
|
|
26
|
+
return {
|
|
27
|
+
users: parsed.users ?? {},
|
|
28
|
+
default: parsed.default
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function lookupUser(config, channel, peerId) {
|
|
32
|
+
const key = `${channel}:${peerId}`;
|
|
33
|
+
return config.users[key] ?? config.default ?? null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// src/index.ts
|
|
37
|
+
function applyIdentity(usersConfig, sessionKey) {
|
|
38
|
+
if (!sessionKey) return;
|
|
39
|
+
const parsed = parseSessionKey(sessionKey);
|
|
40
|
+
if (!parsed) return;
|
|
41
|
+
const user = usersConfig.users[`${parsed.channel}:${parsed.peerId}`] ?? usersConfig.default;
|
|
42
|
+
if (!user) return;
|
|
43
|
+
process.env.GRWND_USER = `${parsed.channel}:${parsed.peerId}`;
|
|
44
|
+
process.env.GRWND_ROLE = user.role;
|
|
45
|
+
if (user.org_unit) {
|
|
46
|
+
process.env.GRWND_ORG_UNIT = user.org_unit;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
var plugin = {
|
|
50
|
+
id: "grwnd-openclaw-governance",
|
|
51
|
+
configSchema: {
|
|
52
|
+
type: "object",
|
|
53
|
+
properties: {
|
|
54
|
+
users_file: { type: "string", default: "./openclaw-users.yaml" }
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
register(api, config = {}) {
|
|
58
|
+
const usersFile = resolve(config.users_file ?? "./openclaw-users.yaml");
|
|
59
|
+
const usersConfig = loadUsers(usersFile);
|
|
60
|
+
api.on("session_start", (ctx) => {
|
|
61
|
+
applyIdentity(usersConfig, ctx.sessionKey);
|
|
62
|
+
});
|
|
63
|
+
api.on("message_received", (ctx) => {
|
|
64
|
+
applyIdentity(usersConfig, ctx.sessionKey);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
export {
|
|
69
|
+
loadUsers,
|
|
70
|
+
lookupUser,
|
|
71
|
+
parseSessionKey,
|
|
72
|
+
plugin
|
|
73
|
+
};
|
|
74
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +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(\n config: UsersConfig,\n channel: string,\n peerId: string,\n): 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,WACd,QACA,SACA,QACkB;AAClB,QAAM,MAAM,GAAG,OAAO,IAAI,MAAM;AAChC,SAAO,OAAO,MAAM,GAAG,KAAK,OAAO,WAAW;AAChD;;;AFhBA,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":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@grwnd/openclaw-governance",
|
|
3
|
+
"version": "1.4.0",
|
|
4
|
+
"description": "OpenClaw identity bridge plugin for @grwnd/pi-governance",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"author": "Grwnd AI",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/Grwnd-AI/pi-governance.git",
|
|
10
|
+
"directory": "packages/openclaw-plugin"
|
|
11
|
+
},
|
|
12
|
+
"type": "module",
|
|
13
|
+
"main": "./dist/index.cjs",
|
|
14
|
+
"module": "./dist/index.js",
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"import": {
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"default": "./dist/index.js"
|
|
21
|
+
},
|
|
22
|
+
"require": {
|
|
23
|
+
"types": "./dist/index.d.cts",
|
|
24
|
+
"default": "./dist/index.cjs"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"dist",
|
|
30
|
+
"openclaw.plugin.json"
|
|
31
|
+
],
|
|
32
|
+
"openclaw": {
|
|
33
|
+
"extensions": [
|
|
34
|
+
"./dist/index.js"
|
|
35
|
+
]
|
|
36
|
+
},
|
|
37
|
+
"scripts": {
|
|
38
|
+
"build": "tsup",
|
|
39
|
+
"test": "vitest run",
|
|
40
|
+
"test:watch": "vitest",
|
|
41
|
+
"typecheck": "tsc --noEmit"
|
|
42
|
+
},
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"yaml": "^2.0.0"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"tsup": "^8.0.0",
|
|
48
|
+
"typescript": "^5.5.0",
|
|
49
|
+
"vitest": "^3.0.0"
|
|
50
|
+
},
|
|
51
|
+
"publishConfig": {
|
|
52
|
+
"access": "public"
|
|
53
|
+
},
|
|
54
|
+
"engines": {
|
|
55
|
+
"node": ">=20"
|
|
56
|
+
}
|
|
57
|
+
}
|