refactor: restructure project layout and add install.mjs
- Move src/ → plugin/ with subdirectories: - plugin/core/ (business logic, models, store, permissions, utils, memory) - plugin/tools/ (query, resources) - plugin/commands/ (placeholder for slash commands) - plugin/hooks/ (placeholder for lifecycle hooks) - plugin/index.ts (wiring layer only, no business logic) - Add install.mjs with --install, --uninstall, --openclaw-profile-path - Add skills/ and docs/ root directories - Move planning docs (PLAN.md, FEAT.md, AGENT_TASKS.md) to docs/ - Remove old scripts/install.sh - Update tsconfig rootDir: src → plugin - Update README.md and README.zh.md with new layout - Bump version to 0.2.0 - All tests pass
This commit is contained in:
48
README.md
48
README.md
@@ -24,24 +24,20 @@ Yonexus is an OpenClaw plugin for organization hierarchy and agent identity mana
|
||||
|
||||
```text
|
||||
.
|
||||
├─ plugin.json
|
||||
├─ src/
|
||||
│ ├─ index.ts
|
||||
│ ├─ models/
|
||||
│ ├─ permissions/
|
||||
│ ├─ store/
|
||||
│ ├─ tools/
|
||||
│ ├─ memory/
|
||||
│ └─ utils/
|
||||
├─ scripts/
|
||||
│ ├─ install.sh
|
||||
│ └─ demo.ts
|
||||
├─ tests/
|
||||
│ └─ smoke.ts
|
||||
├─ examples/
|
||||
│ └─ sample-data.json
|
||||
└─ dist/
|
||||
└─ yonexus/
|
||||
├─ plugin/
|
||||
│ ├─ index.ts # wiring: init, register commands/hooks/tools
|
||||
│ ├─ commands/ # slash commands
|
||||
│ ├─ tools/ # query & resource tools
|
||||
│ ├─ hooks/ # lifecycle hooks
|
||||
│ └─ core/ # business logic, models, store, permissions
|
||||
├─ skills/ # skill definitions
|
||||
├─ docs/ # project documentation
|
||||
├─ scripts/ # demo & utility scripts
|
||||
├─ tests/ # tests
|
||||
├─ install.mjs # install/uninstall script
|
||||
├─ plugin.json # plugin manifest
|
||||
├─ README.md
|
||||
└─ README.zh.md
|
||||
```
|
||||
|
||||
## Requirements
|
||||
@@ -54,11 +50,23 @@ Yonexus is an OpenClaw plugin for organization hierarchy and agent identity mana
|
||||
```bash
|
||||
npm install
|
||||
npm run build
|
||||
bash scripts/install.sh
|
||||
npm run test:smoke
|
||||
npm run demo
|
||||
```
|
||||
|
||||
## Install / Uninstall
|
||||
|
||||
```bash
|
||||
# Install (builds and copies to ~/.openclaw/plugins/yonexus)
|
||||
node install.mjs --install
|
||||
|
||||
# Install to custom openclaw profile path
|
||||
node install.mjs --install --openclaw-profile-path /path/to/.openclaw
|
||||
|
||||
# Uninstall
|
||||
node install.mjs --uninstall
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
`plugin.json` includes default config:
|
||||
@@ -98,8 +106,6 @@ Data & audit:
|
||||
|
||||
## Testing
|
||||
|
||||
Smoke test:
|
||||
|
||||
```bash
|
||||
npm run test:smoke
|
||||
```
|
||||
|
||||
48
README.zh.md
48
README.zh.md
@@ -24,24 +24,20 @@ Yonexus 是一个用于 OpenClaw 的组织结构与 Agent 身份管理插件。
|
||||
|
||||
```text
|
||||
.
|
||||
├─ plugin.json
|
||||
├─ src/
|
||||
│ ├─ index.ts
|
||||
│ ├─ models/
|
||||
│ ├─ permissions/
|
||||
│ ├─ store/
|
||||
│ ├─ tools/
|
||||
│ ├─ memory/
|
||||
│ └─ utils/
|
||||
├─ scripts/
|
||||
│ ├─ install.sh
|
||||
│ └─ demo.ts
|
||||
├─ tests/
|
||||
│ └─ smoke.ts
|
||||
├─ examples/
|
||||
│ └─ sample-data.json
|
||||
└─ dist/
|
||||
└─ yonexus/
|
||||
├─ plugin/
|
||||
│ ├─ index.ts # 接线层:初始化、注册命令/hooks/tools
|
||||
│ ├─ commands/ # slash commands
|
||||
│ ├─ tools/ # 查询与资源工具
|
||||
│ ├─ hooks/ # 生命周期钩子
|
||||
│ └─ core/ # 业务逻辑、模型、存储、权限
|
||||
├─ skills/ # 技能定义
|
||||
├─ docs/ # 项目文档
|
||||
├─ scripts/ # 演示与工具脚本
|
||||
├─ tests/ # 测试
|
||||
├─ install.mjs # 安装/卸载脚本
|
||||
├─ plugin.json # 插件清单
|
||||
├─ README.md
|
||||
└─ README.zh.md
|
||||
```
|
||||
|
||||
## 环境要求
|
||||
@@ -54,11 +50,23 @@ Yonexus 是一个用于 OpenClaw 的组织结构与 Agent 身份管理插件。
|
||||
```bash
|
||||
npm install
|
||||
npm run build
|
||||
bash scripts/install.sh
|
||||
npm run test:smoke
|
||||
npm run demo
|
||||
```
|
||||
|
||||
## 安装 / 卸载
|
||||
|
||||
```bash
|
||||
# 安装(构建并复制到 ~/.openclaw/plugins/yonexus)
|
||||
node install.mjs --install
|
||||
|
||||
# 安装到自定义 openclaw profile 路径
|
||||
node install.mjs --install --openclaw-profile-path /path/to/.openclaw
|
||||
|
||||
# 卸载
|
||||
node install.mjs --uninstall
|
||||
```
|
||||
|
||||
## 配置说明
|
||||
|
||||
`plugin.json` 默认包含以下配置:
|
||||
@@ -98,8 +106,6 @@ npm run demo
|
||||
|
||||
## 测试
|
||||
|
||||
冒烟测试:
|
||||
|
||||
```bash
|
||||
npm run test:smoke
|
||||
```
|
||||
|
||||
0
docs/.gitkeep
Normal file
0
docs/.gitkeep
Normal file
145
install.mjs
Normal file
145
install.mjs
Normal file
@@ -0,0 +1,145 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Yonexus Plugin Installer v0.2.0
|
||||
*
|
||||
* Usage:
|
||||
* node install.mjs --install
|
||||
* node install.mjs --install --openclaw-profile-path /path/to/.openclaw
|
||||
* node install.mjs --uninstall
|
||||
* node install.mjs --uninstall --openclaw-profile-path /path/to/.openclaw
|
||||
*/
|
||||
|
||||
import { execSync } from 'child_process';
|
||||
import { existsSync, mkdirSync, copyFileSync, readdirSync, rmSync } from 'fs';
|
||||
import { dirname, join, resolve } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { homedir } from 'os';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = resolve(dirname(__filename));
|
||||
|
||||
const PLUGIN_NAME = 'yonexus';
|
||||
const SRC_DIST_DIR = join(__dirname, 'dist', PLUGIN_NAME);
|
||||
|
||||
// ── Parse arguments ─────────────────────────────────────────────────────
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
const isInstall = args.includes('--install');
|
||||
const isUninstall = args.includes('--uninstall');
|
||||
|
||||
const profileIdx = args.indexOf('--openclaw-profile-path');
|
||||
let openclawProfilePath = null;
|
||||
if (profileIdx !== -1 && args[profileIdx + 1]) {
|
||||
openclawProfilePath = resolve(args[profileIdx + 1]);
|
||||
}
|
||||
|
||||
function resolveOpenclawPath() {
|
||||
if (openclawProfilePath) return openclawProfilePath;
|
||||
if (process.env.OPENCLAW_PATH) return resolve(process.env.OPENCLAW_PATH);
|
||||
return join(homedir(), '.openclaw');
|
||||
}
|
||||
|
||||
// ── Colors ──────────────────────────────────────────────────────────────
|
||||
|
||||
const c = {
|
||||
reset: '\x1b[0m', red: '\x1b[31m', green: '\x1b[32m',
|
||||
yellow: '\x1b[33m', blue: '\x1b[34m', cyan: '\x1b[36m',
|
||||
};
|
||||
function log(msg, color = 'reset') { console.log(`${c[color]}${msg}${c.reset}`); }
|
||||
function logOk(msg) { log(` ✓ ${msg}`, 'green'); }
|
||||
function logWarn(msg) { log(` ⚠ ${msg}`, 'yellow'); }
|
||||
function logErr(msg) { log(` ✗ ${msg}`, 'red'); }
|
||||
|
||||
// ── Helpers ─────────────────────────────────────────────────────────────
|
||||
|
||||
function copyDir(src, dest) {
|
||||
mkdirSync(dest, { recursive: true });
|
||||
for (const entry of readdirSync(src, { withFileTypes: true })) {
|
||||
const s = join(src, entry.name);
|
||||
const d = join(dest, entry.name);
|
||||
if (entry.name === 'node_modules') continue;
|
||||
entry.isDirectory() ? copyDir(s, d) : copyFileSync(s, d);
|
||||
}
|
||||
}
|
||||
|
||||
// ── Install ─────────────────────────────────────────────────────────────
|
||||
|
||||
function install() {
|
||||
console.log('');
|
||||
log('╔══════════════════════════════════════════════╗', 'cyan');
|
||||
log('║ Yonexus Plugin Installer v0.2.0 ║', 'cyan');
|
||||
log('╚══════════════════════════════════════════════╝', 'cyan');
|
||||
console.log('');
|
||||
|
||||
// 1. Build
|
||||
log('[1/3] Building...', 'cyan');
|
||||
execSync('npm install', { cwd: __dirname, stdio: 'inherit' });
|
||||
execSync('npm run build', { cwd: __dirname, stdio: 'inherit' });
|
||||
|
||||
if (!existsSync(SRC_DIST_DIR)) {
|
||||
logErr(`Build output not found at ${SRC_DIST_DIR}`);
|
||||
process.exit(1);
|
||||
}
|
||||
logOk('Build complete');
|
||||
|
||||
// 2. Copy to plugins dir
|
||||
log('[2/3] Installing...', 'cyan');
|
||||
const openclawPath = resolveOpenclawPath();
|
||||
const destDir = join(openclawPath, 'plugins', PLUGIN_NAME);
|
||||
|
||||
log(` OpenClaw path: ${openclawPath}`, 'blue');
|
||||
|
||||
if (existsSync(destDir)) rmSync(destDir, { recursive: true, force: true });
|
||||
copyDir(SRC_DIST_DIR, destDir);
|
||||
logOk(`Plugin files → ${destDir}`);
|
||||
|
||||
// 3. Summary
|
||||
log('[3/3] Done!', 'cyan');
|
||||
console.log('');
|
||||
log('✓ Yonexus installed successfully!', 'green');
|
||||
console.log('');
|
||||
log('Next steps:', 'blue');
|
||||
log(' openclaw gateway restart', 'cyan');
|
||||
console.log('');
|
||||
}
|
||||
|
||||
// ── Uninstall ───────────────────────────────────────────────────────────
|
||||
|
||||
function uninstall() {
|
||||
console.log('');
|
||||
log('Uninstalling Yonexus...', 'cyan');
|
||||
|
||||
const openclawPath = resolveOpenclawPath();
|
||||
const destDir = join(openclawPath, 'plugins', PLUGIN_NAME);
|
||||
|
||||
if (existsSync(destDir)) {
|
||||
rmSync(destDir, { recursive: true, force: true });
|
||||
logOk(`Removed ${destDir}`);
|
||||
} else {
|
||||
logWarn(`${destDir} not found, nothing to remove`);
|
||||
}
|
||||
|
||||
console.log('');
|
||||
log('✓ Yonexus uninstalled.', 'green');
|
||||
log('\nNext: openclaw gateway restart', 'yellow');
|
||||
console.log('');
|
||||
}
|
||||
|
||||
// ── Main ────────────────────────────────────────────────────────────────
|
||||
|
||||
if (!isInstall && !isUninstall) {
|
||||
console.log('');
|
||||
log('Yonexus Plugin Installer', 'cyan');
|
||||
console.log('');
|
||||
log('Usage:', 'blue');
|
||||
log(' node install.mjs --install Install plugin', 'reset');
|
||||
log(' node install.mjs --install --openclaw-profile-path <path> Install to custom path', 'reset');
|
||||
log(' node install.mjs --uninstall Uninstall plugin', 'reset');
|
||||
log(' node install.mjs --uninstall --openclaw-profile-path <path> Uninstall from custom path', 'reset');
|
||||
console.log('');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (isInstall) install();
|
||||
if (isUninstall) uninstall();
|
||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "openclaw-plugin-yonexus",
|
||||
"version": "0.1.0",
|
||||
"version": "0.2.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "openclaw-plugin-yonexus",
|
||||
"version": "0.1.0",
|
||||
"version": "0.2.0",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.13.10",
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"name": "openclaw-plugin-yonexus",
|
||||
"version": "0.1.0",
|
||||
"version": "0.2.0",
|
||||
"description": "Yonexus OpenClaw plugin: hierarchy, identities, permissions, and scoped memory",
|
||||
"main": "dist/yonexus/index.js",
|
||||
"types": "dist/yonexus/index.d.ts",
|
||||
"scripts": {
|
||||
"build": "tsc -p tsconfig.json",
|
||||
"build": "tsc -p tsconfig.json && cp plugin.json dist/yonexus/plugin.json",
|
||||
"clean": "rm -rf dist",
|
||||
"prepare": "npm run clean && npm run build",
|
||||
"test:smoke": "tsx tests/smoke.ts",
|
||||
|
||||
0
plugin/commands/.gitkeep
Normal file
0
plugin/commands/.gitkeep
Normal file
@@ -16,8 +16,8 @@ import type {
|
||||
import { authorize } from "./permissions/authorize";
|
||||
import { AuditStore } from "./store/auditStore";
|
||||
import { JsonStore } from "./store/jsonStore";
|
||||
import { queryIdentities } from "./tools/query";
|
||||
import { ResourceLayout } from "./tools/resources";
|
||||
import { queryIdentities } from "../tools/query";
|
||||
import { ResourceLayout } from "../tools/resources";
|
||||
import { makeId } from "./utils/id";
|
||||
|
||||
export interface YonexusOptions {
|
||||
@@ -243,5 +243,3 @@ export class Yonexus {
|
||||
return this.store.snapshot();
|
||||
}
|
||||
}
|
||||
|
||||
export default Yonexus;
|
||||
0
plugin/hooks/.gitkeep
Normal file
0
plugin/hooks/.gitkeep
Normal file
45
plugin/index.ts
Normal file
45
plugin/index.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Yonexus Plugin Entry
|
||||
*
|
||||
* This file is the wiring layer: it initializes and re-exports the core
|
||||
* Yonexus class along with models, tools, and memory adapters.
|
||||
* No business logic lives here.
|
||||
*/
|
||||
|
||||
// ── Core ────────────────────────────────────────────────────────────────
|
||||
export { Yonexus, type YonexusOptions } from "./core/yonexus";
|
||||
|
||||
// ── Models ──────────────────────────────────────────────────────────────
|
||||
export { YonexusError } from "./core/models/errors";
|
||||
export type { ErrorCode } from "./core/models/errors";
|
||||
export type { AuditLogEntry } from "./core/models/audit";
|
||||
export type {
|
||||
Action,
|
||||
Actor,
|
||||
Agent,
|
||||
Department,
|
||||
DocsScope,
|
||||
DocsTopic,
|
||||
Identity,
|
||||
Organization,
|
||||
QueryFilter,
|
||||
QueryInput,
|
||||
QueryOptions,
|
||||
Role,
|
||||
SchemaField,
|
||||
Scope,
|
||||
StoreState,
|
||||
Supervisor,
|
||||
Team,
|
||||
YonexusSchema,
|
||||
} from "./core/models/types";
|
||||
|
||||
// ── Tools ───────────────────────────────────────────────────────────────
|
||||
export { queryIdentities } from "./tools/query";
|
||||
export { ResourceLayout } from "./tools/resources";
|
||||
|
||||
// ── Memory ──────────────────────────────────────────────────────────────
|
||||
export { ScopeMemory, type MemoryPort } from "./core/memory/scopeMemory";
|
||||
|
||||
// ── Default export ──────────────────────────────────────────────────────
|
||||
export { Yonexus as default } from "./core/yonexus";
|
||||
@@ -1,5 +1,5 @@
|
||||
import { YonexusError } from '../models/errors';
|
||||
import type { Identity, QueryFilter, QueryInput, QueryOptions, YonexusSchema } from "../models/types";
|
||||
import { YonexusError } from '../core/models/errors';
|
||||
import type { Identity, QueryFilter, QueryInput, QueryOptions, YonexusSchema } from "../core/models/types";
|
||||
|
||||
const DEFAULT_LIMIT = 20;
|
||||
const MAX_LIMIT = 100;
|
||||
@@ -1,8 +1,8 @@
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { YonexusError } from '../models/errors';
|
||||
import type { DocsScope, DocsTopic } from '../models/types';
|
||||
import { slug } from '../utils/id';
|
||||
import { YonexusError } from '../core/models/errors';
|
||||
import type { DocsScope, DocsTopic } from '../core/models/types';
|
||||
import { slug } from '../core/utils/id';
|
||||
|
||||
const TOPICS: DocsTopic[] = ['docs', 'notes', 'knowledge', 'rules', 'lessons', 'workflows'];
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import path from 'node:path';
|
||||
import fs from 'node:fs';
|
||||
import { Yonexus } from '../src/index';
|
||||
import { Yonexus } from '../plugin/index';
|
||||
|
||||
const dataFile = path.resolve(process.cwd(), 'data/demo-org.json');
|
||||
if (fs.existsSync(dataFile)) fs.unlinkSync(dataFile);
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Yonexus install script
|
||||
# - Registers plugin name: yonexus
|
||||
# - Places build output in dist/yonexus
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
DIST_DIR="$ROOT_DIR/dist/yonexus"
|
||||
|
||||
cd "$ROOT_DIR"
|
||||
|
||||
if [ ! -d node_modules ]; then
|
||||
npm install
|
||||
fi
|
||||
|
||||
npm run build
|
||||
mkdir -p "$DIST_DIR"
|
||||
cp -f "$ROOT_DIR/plugin.json" "$DIST_DIR/plugin.json"
|
||||
|
||||
echo "[yonexus] install complete -> $DIST_DIR"
|
||||
0
skills/.gitkeep
Normal file
0
skills/.gitkeep
Normal file
@@ -1,8 +1,8 @@
|
||||
import assert from 'node:assert';
|
||||
import path from 'node:path';
|
||||
import fs from 'node:fs';
|
||||
import { Yonexus } from '../src/index';
|
||||
import { YonexusError } from '../src/models/errors';
|
||||
import { Yonexus } from '../plugin/index';
|
||||
import { YonexusError } from '../plugin/core/models/errors';
|
||||
|
||||
const root = path.resolve(process.cwd(), 'data/test-openclaw');
|
||||
const dataFile = path.resolve(process.cwd(), 'data/test-org.json');
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"skipLibCheck": true,
|
||||
"outDir": "dist/yonexus",
|
||||
"rootDir": "src",
|
||||
"rootDir": "plugin",
|
||||
"declaration": true,
|
||||
"types": ["node"]
|
||||
},
|
||||
"include": ["src/**/*.ts"]
|
||||
"include": ["plugin/**/*.ts"]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user