diff --git a/CHANGELOG.md b/CHANGELOG.md index c5ef19d9..13ac314d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ All notable changes to `@useorgx/openclaw-plugin` are documented in this file. +## 0.7.35 - 2026-05-18 + +### OpenClaw 2026.5 Compatibility +- Declared startup activation so the OrgX dashboard and local HTTP routes load when the gateway starts. +- Added the runtime tool ownership contract required by newer OpenClaw plugin loading. +- Redirected legacy `/orgx/chat` deep links into the live dashboard while preserving query parameters. +- Updated local deploy/dev scripts to target OpenClaw's managed npm plugin install before the legacy extension path. + ## 0.7.33 - 2026-04-13 ### Release Management diff --git a/openclaw.plugin.json b/openclaw.plugin.json index 6276fbd6..1bde431c 100644 --- a/openclaw.plugin.json +++ b/openclaw.plugin.json @@ -1,7 +1,7 @@ { "id": "orgx", "name": "OrgX for OpenClaw", - "version": "0.7.34", + "version": "0.7.35", "description": "Persistent organizational memory and coordinated execution for OpenClaw agents", "entry": "./dist/index.js", "author": "OrgX Team", @@ -13,6 +13,9 @@ "engines": { "node": ">=18.0.0" }, + "activation": { + "onStartup": true + }, "skills": ["skills"], "capabilities": { "tools": true, @@ -20,6 +23,43 @@ "cli": true, "http": true }, + "contracts": { + "tools": [ + "orgx_status", + "orgx_sentinel_catalog", + "orgx_sync", + "orgx_get_morning_brief", + "orgx_query_org_memory", + "orgx_recommend_next_action", + "orgx_delegation_preflight", + "orgx_run_action", + "orgx_checkpoints_list", + "orgx_checkpoint_restore", + "orgx_spawn_check", + "orgx_quality_score", + "orgx_proof_status", + "orgx_verify_completion", + "orgx_record_outcome", + "orgx_get_outcome_attribution", + "orgx_create_entity", + "orgx_update_entity", + "orgx_reassign_stream", + "orgx_reassign_streams", + "orgx_list_entities", + "orgx_emit_activity", + "orgx_apply_changeset", + "orgx_report_progress", + "orgx_request_decision", + "orgx_register_artifact", + "orgx_agent_sessions", + "orgx_resume_agent_session", + "orgx_clear_agent_session", + "list_agent_configs", + "get_agent_config", + "update_agent_config", + "update_stream_progress" + ] + }, "configSchema": { "type": "object", "properties": { diff --git a/package-lock.json b/package-lock.json index f16f4bc4..796c70a3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@useorgx/openclaw-plugin", - "version": "0.7.34", + "version": "0.7.35", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@useorgx/openclaw-plugin", - "version": "0.7.34", + "version": "0.7.35", "license": "MIT", "dependencies": { "better-sqlite3": "^11.10.0" diff --git a/package.json b/package.json index 6bef6b61..4fe81771 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@useorgx/openclaw-plugin", - "version": "0.7.34", + "version": "0.7.35", "description": "Persistent organizational memory and coordination for OpenClaw agents", "type": "module", "main": "./dist/index.js", diff --git a/scripts/deploy-local.sh b/scripts/deploy-local.sh index e5fb4e02..81b50f18 100755 --- a/scripts/deploy-local.sh +++ b/scripts/deploy-local.sh @@ -11,7 +11,8 @@ set -euo pipefail REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" -EXTENSIONS_DIR="${HOME}/.openclaw/extensions/openclaw-plugin" +LEGACY_EXTENSIONS_DIR="${HOME}/.openclaw/extensions/openclaw-plugin" +NPM_PLUGIN_DIR="${HOME}/.openclaw/npm/node_modules/@useorgx/openclaw-plugin" CONFIG_FILE="${HOME}/.openclaw/openclaw.json" LAUNCH_AGENT="gui/$(id -u)/ai.openclaw.gateway" @@ -60,24 +61,36 @@ if ! $LOCAL_ONLY; then echo "Published @useorgx/openclaw-plugin@${VERSION}" fi -# --- Install to extensions dir --- -echo "Installing to ${EXTENSIONS_DIR}..." -if [ -d "$EXTENSIONS_DIR" ]; then - find "$EXTENSIONS_DIR" -mindepth 1 -delete 2>/dev/null || true +INSTALL_DIRS=() +if [ -d "$NPM_PLUGIN_DIR" ]; then + INSTALL_DIRS+=("$NPM_PLUGIN_DIR") +else + INSTALL_DIRS+=("$LEGACY_EXTENSIONS_DIR") fi -mkdir -p "$EXTENSIONS_DIR" -if $LOCAL_ONLY; then - cp -R dist openclaw.plugin.json package.json LICENSE README.md "$EXTENSIONS_DIR/" - [ -d dashboard/dist ] && mkdir -p "$EXTENSIONS_DIR/dashboard" && cp -R dashboard/dist "$EXTENSIONS_DIR/dashboard/" - [ -d skills ] && cp -R skills "$EXTENSIONS_DIR/" - echo "Installing runtime dependencies for local extension..." - (cd "$EXTENSIONS_DIR" && npm install --omit=dev) -else +if ! $LOCAL_ONLY; then TMPDIR=$(mktemp -d) - (cd "$TMPDIR" && npm pack "@useorgx/openclaw-plugin@${VERSION}" --silent && tar xzf *.tgz && cp -R package/* "$EXTENSIONS_DIR/") + (cd "$TMPDIR" && npm pack "@useorgx/openclaw-plugin@${VERSION}" --silent && tar xzf *.tgz) fi +for INSTALL_DIR in "${INSTALL_DIRS[@]}"; do + echo "Installing to ${INSTALL_DIR}..." + if [ -d "$INSTALL_DIR" ]; then + find "$INSTALL_DIR" -mindepth 1 -delete 2>/dev/null || true + fi + mkdir -p "$INSTALL_DIR" + + if $LOCAL_ONLY; then + cp -R dist openclaw.plugin.json package.json LICENSE README.md "$INSTALL_DIR/" + [ -d dashboard/dist ] && mkdir -p "$INSTALL_DIR/dashboard" && cp -R dashboard/dist "$INSTALL_DIR/dashboard/" + [ -d skills ] && cp -R skills "$INSTALL_DIR/" + echo "Installing runtime dependencies for local plugin at ${INSTALL_DIR}..." + (cd "$INSTALL_DIR" && npm install --omit=dev) + else + cp -R "$TMPDIR"/package/* "$INSTALL_DIR/" + fi +done + # --- Update config version --- if [ -f "$CONFIG_FILE" ]; then sed -i '' "s/\"version\": \"[0-9]*\.[0-9]*\.[0-9]*\"/\"version\": \"${VERSION}\"/" "$CONFIG_FILE" @@ -89,5 +102,8 @@ launchctl kickstart -k "$LAUNCH_AGENT" 2>/dev/null || echo "Gateway not running echo "" echo "Deployed @useorgx/openclaw-plugin@${VERSION}" -echo " Extensions: ${EXTENSIONS_DIR}" +printf " Installed paths:\\n" +for INSTALL_DIR in "${INSTALL_DIRS[@]}"; do + printf " - %s\\n" "$INSTALL_DIR" +done echo " Gateway: restarted" diff --git a/scripts/live-dev-serve.mjs b/scripts/live-dev-serve.mjs index ee01a554..f54ab44e 100644 --- a/scripts/live-dev-serve.mjs +++ b/scripts/live-dev-serve.mjs @@ -8,10 +8,17 @@ import { fileURLToPath } from "node:url"; const scriptDir = resolve(fileURLToPath(new URL(".", import.meta.url))); const repoRoot = resolve(scriptDir, ".."); const dashboardDir = resolve(repoRoot, "dashboard"); -const extensionRoot = resolve( - process.env.HOME || "~", - ".openclaw/extensions/openclaw-plugin" +const openclawHome = resolve(process.env.HOME || "~", ".openclaw"); +const npmPluginRoot = resolve( + openclawHome, + "npm/node_modules/@useorgx/openclaw-plugin" ); +const legacyExtensionRoot = resolve(openclawHome, "extensions/openclaw-plugin"); +const extensionRoot = process.env.ORGX_OPENCLAW_PLUGIN_EXTENSION_ROOT + ? resolve(process.env.ORGX_OPENCLAW_PLUGIN_EXTENSION_ROOT) + : existsSync(npmPluginRoot) + ? npmPluginRoot + : legacyExtensionRoot; const gatewayPort = String(process.env.ORGX_DEV_GATEWAY_PORT || "18890").trim(); function log(message) { diff --git a/src/http/index.ts b/src/http/index.ts index 74c3bfdb..af581b30 100644 --- a/src/http/index.ts +++ b/src/http/index.ts @@ -4880,6 +4880,19 @@ export function createHttpHandler( return true; } + // Legacy/direct chat links load the dashboard SPA. The chat surface is a + // dock within /orgx/live, while chat data APIs remain under /orgx/api/chat/*. + if (url === "/orgx/chat" || url.startsWith("/orgx/chat/")) { + const suffix = queryString && queryString.trim().length > 0 ? `?${queryString}` : ""; + res.writeHead(302, { + Location: `/orgx/live${suffix}`, + ...SECURITY_HEADERS, + ...CORS_HEADERS, + }); + res.end(); + return true; + } + // Requests under /orgx/live if (url === "/orgx/live" || url.startsWith("/orgx/live/")) { const subPath = url.replace(/^\/orgx\/live\/?/, ""); diff --git a/tests/http/workspace-hub-redirect.test.mjs b/tests/http/workspace-hub-redirect.test.mjs index 9e257f73..6cde2628 100644 --- a/tests/http/workspace-hub-redirect.test.mjs +++ b/tests/http/workspace-hub-redirect.test.mjs @@ -90,3 +90,23 @@ test("legacy /workspace-hub deep links redirect to /orgx/live", async () => { "/orgx/live?center=2577519c-d0bf-4682-a7ec-e9ab28d19822&view=activity" ); }); + +test("legacy /orgx/chat deep links redirect to /orgx/live", async () => { + const config = baseConfig(); + const client = { getBaseUrl: () => config.baseUrl }; + const handler = createHttpHandler(config, client, () => null, createNoopOnboarding()); + + const res = createStubResponse(); + const handled = await handler( + { + method: "GET", + url: "/orgx/chat?session=agent%3Amain%3Amain", + headers: {}, + }, + res + ); + + assert.equal(handled, true); + assert.equal(res.status, 302); + assert.equal(res.headers?.Location, "/orgx/live?session=agent%3Amain%3Amain"); +});