@openduo/channel-feishu 0.2.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/package.json ADDED
@@ -0,0 +1,73 @@
1
+ {
2
+ "name": "@openduo/channel-feishu",
3
+ "version": "0.2.0",
4
+ "private": false,
5
+ "type": "module",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
9
+ "main": "dist/plugin.js",
10
+ "files": [
11
+ "bin/duoduo-feishu",
12
+ "config/",
13
+ "dist/",
14
+ "scripts/postinstall.mjs",
15
+ "package.json"
16
+ ],
17
+ "bin": {
18
+ "duoduo-feishu": "bin/duoduo-feishu"
19
+ },
20
+ "aladuo": {
21
+ "channel": {
22
+ "type": "feishu",
23
+ "bin": "dist/plugin.js",
24
+ "envAllowlist": [
25
+ "FEISHU_APP_ID",
26
+ "FEISHU_APP_SECRET",
27
+ "FEISHU_DOMAIN",
28
+ "FEISHU_LOG_LEVEL",
29
+ "FEISHU_MESSAGE_CACHE_DIR",
30
+ "FEISHU_BOT_OPEN_ID",
31
+ "FEISHU_DM_POLICY",
32
+ "FEISHU_GROUP_POLICY",
33
+ "FEISHU_REQUIRE_MENTION",
34
+ "FEISHU_ALLOW_FROM",
35
+ "FEISHU_ALLOW_GROUPS",
36
+ "FEISHU_RENDER_MODE",
37
+ "FEISHU_TEXT_CHUNK_LIMIT",
38
+ "FEISHU_CS_MODE",
39
+ "FEISHU_CS_ROOT_USERS",
40
+ "FEISHU_CS_BINDING_STORE_PATH",
41
+ "FEISHU_CS_CODE_TTL_MINUTES",
42
+ "FEISHU_CS_AUTO_APPROVE_NEW_INSTANCES",
43
+ "FEISHU_CS_ROOT_CHAT_ID",
44
+ "FEISHU_CS_BOOTSTRAP_SESSION_KEY",
45
+ "FEISHU_CS_BINDING_BACKEND",
46
+ "FEISHU_CS_CONTROL_PLANE_BASE_URL",
47
+ "FEISHU_CS_CONTROL_PLANE_INTERNAL_TOKEN",
48
+ "FEISHU_CS_TENANT_ID"
49
+ ]
50
+ }
51
+ },
52
+ "dependencies": {
53
+ "@larksuiteoapi/node-sdk": "^1.58.0",
54
+ "ws": "^8.19.0",
55
+ "@openduo/protocol": "0.2.0"
56
+ },
57
+ "devDependencies": {
58
+ "@types/node": "^20.11.30",
59
+ "@types/ws": "^8.18.1",
60
+ "tsx": "^4.19.2",
61
+ "typescript": "^5.5.4",
62
+ "vitest": "^2.1.8"
63
+ },
64
+ "scripts": {
65
+ "postinstall": "node scripts/postinstall.mjs",
66
+ "start": "tsx src/main.ts",
67
+ "build:plugin": "esbuild src/main.ts --bundle --platform=node --format=esm --target=node20 --minify --legal-comments=none --log-level=info --outfile=dist/plugin.js",
68
+ "lint:types": "tsc --noEmit",
69
+ "test": "vitest run",
70
+ "test:watch": "vitest",
71
+ "build": "tsc"
72
+ }
73
+ }
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * postinstall.mjs — Install default channel kind descriptor to bootstrap/config/.
4
+ *
5
+ * Runs as npm/pnpm postinstall hook. Merges (never overwrites) so user edits
6
+ * and agent-curated configs survive upgrades.
7
+ *
8
+ * Exits silently (code 0) if not inside an ALADUO project — safe for any
9
+ * npm install context.
10
+ */
11
+ import { existsSync, copyFileSync, readdirSync, mkdirSync } from "node:fs";
12
+ import path from "node:path";
13
+ import process from "node:process";
14
+ import { fileURLToPath } from "node:url";
15
+
16
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
17
+ const pkgRoot = path.resolve(__dirname, "..");
18
+ const configSrc = path.join(pkgRoot, "config");
19
+
20
+ if (!existsSync(configSrc)) process.exit(0);
21
+
22
+ // Walk up from a starting directory to find bootstrap/config/.
23
+ // Works in both monorepo (packages/channel-xxx) and standalone install
24
+ // (node_modules/@openduo/channel-xxx) layouts.
25
+ function findBootstrapConfig(start) {
26
+ let dir = start;
27
+ for (let i = 0; i < 10; i++) {
28
+ const candidate = path.join(dir, "bootstrap", "config");
29
+ if (existsSync(candidate)) return candidate;
30
+ const parent = path.dirname(dir);
31
+ if (parent === dir) break;
32
+ dir = parent;
33
+ }
34
+ // Fallback: INIT_CWD (set by npm/pnpm to the dir where install was invoked)
35
+ const initCwd = process.env.INIT_CWD;
36
+ if (initCwd) {
37
+ const candidate = path.join(initCwd, "bootstrap", "config");
38
+ if (existsSync(candidate)) return candidate;
39
+ }
40
+ return null;
41
+ }
42
+
43
+ const target = findBootstrapConfig(pkgRoot);
44
+ if (!target) process.exit(0);
45
+
46
+ // Merge: copy .md files that don't already exist at target
47
+ for (const file of readdirSync(configSrc)) {
48
+ if (!file.endsWith(".md")) continue;
49
+ const dest = path.join(target, file);
50
+ if (!existsSync(dest)) {
51
+ mkdirSync(path.dirname(dest), { recursive: true });
52
+ copyFileSync(path.join(configSrc, file), dest);
53
+ }
54
+ }