@useorgx/openclaw-plugin 0.4.6 → 0.4.9
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/README.md +310 -24
- package/dashboard/dist/assets/B5NEElEI.css +1 -0
- package/dashboard/dist/assets/BhapSNAs.js +215 -0
- package/dashboard/dist/assets/iFdvE7lx.js +1 -0
- package/dashboard/dist/assets/jRJsmpYM.js +1 -0
- package/dashboard/dist/index.html +2 -2
- package/dist/activity-actor-fields.d.ts +3 -0
- package/dist/activity-actor-fields.js +128 -0
- package/dist/activity-store.js +12 -19
- package/dist/agent-context-store.js +5 -25
- package/dist/agent-run-store.js +5 -25
- package/dist/agent-suite.js +1 -8
- package/dist/artifacts/register-artifact.d.ts +47 -0
- package/dist/artifacts/register-artifact.js +271 -0
- package/dist/auth/flows.d.ts +47 -0
- package/dist/auth/flows.js +169 -0
- package/dist/auth-store.js +14 -39
- package/dist/byok-store.js +5 -19
- package/dist/cli/orgx.d.ts +66 -0
- package/dist/cli/orgx.js +91 -0
- package/dist/config/refresh.d.ts +32 -0
- package/dist/config/refresh.js +55 -0
- package/dist/config/resolution.d.ts +37 -0
- package/dist/config/resolution.js +178 -0
- package/dist/contracts/client.d.ts +1 -0
- package/dist/contracts/client.js +7 -5
- package/dist/contracts/shared-types.d.ts +147 -0
- package/dist/contracts/shared-types.js +3 -0
- package/dist/contracts/types.d.ts +1 -130
- package/dist/contracts/types.js +5 -0
- package/dist/entities/auto-assignment.d.ts +36 -0
- package/dist/entities/auto-assignment.js +115 -0
- package/dist/entity-comment-store.js +5 -25
- package/dist/hash-utils.d.ts +2 -0
- package/dist/hash-utils.js +12 -0
- package/dist/http/helpers/activity-headline.d.ts +10 -0
- package/dist/http/helpers/activity-headline.js +192 -0
- package/dist/http/helpers/artifact-fallback.d.ts +13 -0
- package/dist/http/helpers/artifact-fallback.js +148 -0
- package/dist/http/helpers/auto-continue-engine.d.ts +298 -0
- package/dist/http/helpers/auto-continue-engine.js +1218 -0
- package/dist/http/helpers/autopilot-operations.d.ts +157 -0
- package/dist/http/helpers/autopilot-operations.js +403 -0
- package/dist/http/helpers/autopilot-runtime.d.ts +42 -0
- package/dist/http/helpers/autopilot-runtime.js +319 -0
- package/dist/http/helpers/autopilot-slice-utils.d.ts +38 -0
- package/dist/http/helpers/autopilot-slice-utils.js +476 -0
- package/dist/http/helpers/decision-mapper.d.ts +12 -0
- package/dist/http/helpers/decision-mapper.js +44 -0
- package/dist/http/helpers/dispatch-lifecycle.d.ts +102 -0
- package/dist/http/helpers/dispatch-lifecycle.js +604 -0
- package/dist/http/helpers/hash-utils.d.ts +1 -0
- package/dist/http/helpers/hash-utils.js +1 -0
- package/dist/http/helpers/kickoff-context.d.ts +12 -0
- package/dist/http/helpers/kickoff-context.js +154 -0
- package/dist/http/helpers/mission-control.d.ts +94 -0
- package/dist/http/helpers/mission-control.js +894 -0
- package/dist/http/helpers/openclaw-cli.d.ts +37 -0
- package/dist/http/helpers/openclaw-cli.js +283 -0
- package/dist/http/helpers/runtime-sse.d.ts +20 -0
- package/dist/http/helpers/runtime-sse.js +110 -0
- package/dist/http/helpers/value-utils.d.ts +6 -0
- package/dist/http/helpers/value-utils.js +67 -0
- package/dist/http/index.d.ts +88 -0
- package/dist/http/index.js +2353 -0
- package/dist/http/router.d.ts +23 -0
- package/dist/http/router.js +23 -0
- package/dist/http/routes/agent-control.d.ts +79 -0
- package/dist/http/routes/agent-control.js +684 -0
- package/dist/http/routes/agent-suite.d.ts +29 -0
- package/dist/http/routes/agent-suite.js +198 -0
- package/dist/http/routes/agents-catalog.d.ts +40 -0
- package/dist/http/routes/agents-catalog.js +83 -0
- package/dist/http/routes/billing.d.ts +23 -0
- package/dist/http/routes/billing.js +55 -0
- package/dist/http/routes/debug.d.ts +14 -0
- package/dist/http/routes/debug.js +21 -0
- package/dist/http/routes/decision-actions.d.ts +13 -0
- package/dist/http/routes/decision-actions.js +66 -0
- package/dist/http/routes/delegation.d.ts +19 -0
- package/dist/http/routes/delegation.js +32 -0
- package/dist/http/routes/entities.d.ts +47 -0
- package/dist/http/routes/entities.js +152 -0
- package/dist/http/routes/entity-dynamic.d.ts +25 -0
- package/dist/http/routes/entity-dynamic.js +191 -0
- package/dist/http/routes/health.d.ts +22 -0
- package/dist/http/routes/health.js +49 -0
- package/dist/http/routes/live-legacy.d.ts +110 -0
- package/dist/http/routes/live-legacy.js +598 -0
- package/dist/http/routes/live-misc.d.ts +69 -0
- package/dist/http/routes/live-misc.js +206 -0
- package/dist/http/routes/live-snapshot.d.ts +90 -0
- package/dist/http/routes/live-snapshot.js +297 -0
- package/dist/http/routes/mission-control-actions.d.ts +83 -0
- package/dist/http/routes/mission-control-actions.js +541 -0
- package/dist/http/routes/mission-control-read.d.ts +28 -0
- package/dist/http/routes/mission-control-read.js +67 -0
- package/dist/http/routes/onboarding.d.ts +34 -0
- package/dist/http/routes/onboarding.js +101 -0
- package/dist/http/routes/run-control.d.ts +24 -0
- package/dist/http/routes/run-control.js +86 -0
- package/dist/http/routes/runtime-hooks.d.ts +69 -0
- package/dist/http/routes/runtime-hooks.js +437 -0
- package/dist/http/routes/settings-byok.d.ts +23 -0
- package/dist/http/routes/settings-byok.js +163 -0
- package/dist/http/routes/summary.d.ts +18 -0
- package/dist/http/routes/summary.js +42 -0
- package/dist/http/routes/work-artifacts.d.ts +9 -0
- package/dist/http/routes/work-artifacts.js +36 -0
- package/dist/http/shared-state.d.ts +16 -0
- package/dist/http/shared-state.js +1 -0
- package/dist/http-handler.d.ts +1 -88
- package/dist/http-handler.js +1 -9664
- package/dist/index.js +122 -2121
- package/dist/json-utils.d.ts +1 -0
- package/dist/json-utils.js +8 -0
- package/dist/local-openclaw.js +8 -0
- package/dist/mcp-client-setup.js +75 -90
- package/dist/next-up-queue-store.js +4 -18
- package/dist/runtime-instance-store.js +8 -34
- package/dist/services/background.d.ts +23 -0
- package/dist/services/background.js +23 -0
- package/dist/services/instrumentation.d.ts +29 -0
- package/dist/services/instrumentation.js +136 -0
- package/dist/snapshot-store.js +5 -25
- package/dist/stores/json-store.d.ts +11 -0
- package/dist/stores/json-store.js +42 -0
- package/dist/sync/outbox-replay.d.ts +55 -0
- package/dist/sync/outbox-replay.js +514 -0
- package/dist/tools/core-tools.d.ts +76 -0
- package/dist/tools/core-tools.js +1005 -0
- package/dist/worker-supervisor.js +15 -0
- package/package.json +6 -1
- package/dashboard/dist/assets/0tOC3wSN.js +0 -214
- package/dashboard/dist/assets/Bm8QnMJ_.js +0 -1
- package/dashboard/dist/assets/CyxZio4Y.js +0 -1
- package/dashboard/dist/assets/DaAIOik3.css +0 -1
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { type ResolvedConfig } from "../config/resolution.js";
|
|
2
|
+
import type { OnboardingState } from "../types.js";
|
|
3
|
+
type LoggerLike = {
|
|
4
|
+
info?: (msg: string, meta?: Record<string, unknown>) => void;
|
|
5
|
+
warn?: (msg: string, meta?: Record<string, unknown>) => void;
|
|
6
|
+
debug?: (msg: string, meta?: Record<string, unknown>) => void;
|
|
7
|
+
};
|
|
8
|
+
type RuntimeConfigState = Pick<ResolvedConfig, "apiKey" | "apiKeySource" | "userId" | "baseUrl" | "installationId">;
|
|
9
|
+
export declare function applyRuntimeApiKey(input: {
|
|
10
|
+
config: RuntimeConfigState;
|
|
11
|
+
apiKey: string;
|
|
12
|
+
source: "manual" | "browser_pairing";
|
|
13
|
+
workspaceName?: string | null;
|
|
14
|
+
keyPrefix?: string | null;
|
|
15
|
+
userId?: string | null;
|
|
16
|
+
currentWorkspaceName: string | null;
|
|
17
|
+
updateOnboardingState: (updates: Partial<OnboardingState>) => unknown;
|
|
18
|
+
setCredentials: (credentials: {
|
|
19
|
+
apiKey: string;
|
|
20
|
+
userId: string;
|
|
21
|
+
baseUrl: string;
|
|
22
|
+
}) => void;
|
|
23
|
+
logger?: LoggerLike;
|
|
24
|
+
}): void;
|
|
25
|
+
export declare function isAuthRequiredError(result: {
|
|
26
|
+
status: number;
|
|
27
|
+
error: string;
|
|
28
|
+
}): boolean;
|
|
29
|
+
export declare function buildManualKeyConnectUrl(baseApiUrl: string): string;
|
|
30
|
+
export declare function fetchOrgxJson<T>(input: {
|
|
31
|
+
baseApiUrl: string;
|
|
32
|
+
method: "GET" | "POST";
|
|
33
|
+
path: string;
|
|
34
|
+
body?: unknown;
|
|
35
|
+
options?: {
|
|
36
|
+
timeoutMs?: number;
|
|
37
|
+
};
|
|
38
|
+
toErrorMessage: (err: unknown) => string;
|
|
39
|
+
}): Promise<{
|
|
40
|
+
ok: true;
|
|
41
|
+
data: T;
|
|
42
|
+
} | {
|
|
43
|
+
ok: false;
|
|
44
|
+
status: number;
|
|
45
|
+
error: string;
|
|
46
|
+
}>;
|
|
47
|
+
export {};
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { saveAuthStore } from "../auth-store.js";
|
|
2
|
+
import { resolveRuntimeUserId, } from "../config/resolution.js";
|
|
3
|
+
import { autoConfigureDetectedMcpClients } from "../mcp-client-setup.js";
|
|
4
|
+
import { readOpenClawGatewayPort, readOpenClawSettingsSnapshot, } from "../openclaw-settings.js";
|
|
5
|
+
export function applyRuntimeApiKey(input) {
|
|
6
|
+
const nextApiKey = input.apiKey.trim();
|
|
7
|
+
input.config.apiKey = nextApiKey;
|
|
8
|
+
input.config.apiKeySource = "persisted";
|
|
9
|
+
input.config.userId = resolveRuntimeUserId(nextApiKey, [input.userId, input.config.userId]);
|
|
10
|
+
input.setCredentials({
|
|
11
|
+
apiKey: input.config.apiKey,
|
|
12
|
+
userId: input.config.userId,
|
|
13
|
+
baseUrl: input.config.baseUrl,
|
|
14
|
+
});
|
|
15
|
+
saveAuthStore({
|
|
16
|
+
installationId: input.config.installationId,
|
|
17
|
+
apiKey: nextApiKey,
|
|
18
|
+
userId: input.config.userId || null,
|
|
19
|
+
workspaceName: input.workspaceName ?? null,
|
|
20
|
+
keyPrefix: input.keyPrefix ?? null,
|
|
21
|
+
source: input.source,
|
|
22
|
+
});
|
|
23
|
+
input.updateOnboardingState({
|
|
24
|
+
hasApiKey: true,
|
|
25
|
+
keySource: "persisted",
|
|
26
|
+
installationId: input.config.installationId,
|
|
27
|
+
workspaceName: input.workspaceName ?? input.currentWorkspaceName,
|
|
28
|
+
});
|
|
29
|
+
if (input.source === "browser_pairing" &&
|
|
30
|
+
process.env.ORGX_DISABLE_MCP_CLIENT_AUTOCONFIG !== "1") {
|
|
31
|
+
try {
|
|
32
|
+
const snapshot = readOpenClawSettingsSnapshot();
|
|
33
|
+
const port = readOpenClawGatewayPort(snapshot.raw);
|
|
34
|
+
const localMcpUrl = `http://127.0.0.1:${port}/orgx/mcp`;
|
|
35
|
+
void autoConfigureDetectedMcpClients({
|
|
36
|
+
localMcpUrl,
|
|
37
|
+
logger: input.logger ?? {},
|
|
38
|
+
}).catch(() => {
|
|
39
|
+
// best effort
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
// best effort
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
export function isAuthRequiredError(result) {
|
|
48
|
+
if (result.status !== 401) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
return /auth|unauthorized|token/i.test(result.error);
|
|
52
|
+
}
|
|
53
|
+
export function buildManualKeyConnectUrl(baseApiUrl) {
|
|
54
|
+
try {
|
|
55
|
+
// Deep-link into the Security section where API keys live.
|
|
56
|
+
return new URL("/settings#security", baseApiUrl).toString();
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return "https://www.useorgx.com/settings#security";
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
export async function fetchOrgxJson(input) {
|
|
63
|
+
try {
|
|
64
|
+
const controller = new AbortController();
|
|
65
|
+
const timeoutMs = typeof input.options?.timeoutMs === "number" &&
|
|
66
|
+
Number.isFinite(input.options.timeoutMs)
|
|
67
|
+
? Math.max(1_000, Math.floor(input.options.timeoutMs))
|
|
68
|
+
: 12_000;
|
|
69
|
+
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
70
|
+
let response;
|
|
71
|
+
let rawText = "";
|
|
72
|
+
try {
|
|
73
|
+
response = await fetch(`${input.baseApiUrl}${input.path}`, {
|
|
74
|
+
method: input.method,
|
|
75
|
+
signal: controller.signal,
|
|
76
|
+
headers: {
|
|
77
|
+
Accept: "application/json",
|
|
78
|
+
"Content-Type": "application/json",
|
|
79
|
+
},
|
|
80
|
+
body: input.body ? JSON.stringify(input.body) : undefined,
|
|
81
|
+
});
|
|
82
|
+
rawText = await response.text().catch(() => "");
|
|
83
|
+
}
|
|
84
|
+
finally {
|
|
85
|
+
clearTimeout(timeout);
|
|
86
|
+
}
|
|
87
|
+
const payload = (() => {
|
|
88
|
+
if (!rawText)
|
|
89
|
+
return null;
|
|
90
|
+
try {
|
|
91
|
+
return JSON.parse(rawText);
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
})();
|
|
97
|
+
if (!response.ok) {
|
|
98
|
+
const rawError = payload?.error ?? payload?.message;
|
|
99
|
+
let errorMessage;
|
|
100
|
+
if (typeof rawError === "string") {
|
|
101
|
+
errorMessage = rawError;
|
|
102
|
+
}
|
|
103
|
+
else if (rawError &&
|
|
104
|
+
typeof rawError === "object" &&
|
|
105
|
+
"message" in rawError &&
|
|
106
|
+
typeof rawError.message === "string") {
|
|
107
|
+
errorMessage = rawError.message;
|
|
108
|
+
}
|
|
109
|
+
else if (rawText && rawText.trim().length > 0) {
|
|
110
|
+
// Avoid dumping HTML (Cloudflare / Next.js error pages) into UI; keep it short.
|
|
111
|
+
const sanitized = rawText
|
|
112
|
+
.replace(/\s+/g, " ")
|
|
113
|
+
.replace(/<[^>]+>/g, "")
|
|
114
|
+
.trim();
|
|
115
|
+
errorMessage =
|
|
116
|
+
sanitized.length > 0
|
|
117
|
+
? sanitized.slice(0, 180)
|
|
118
|
+
: `OrgX request failed (${response.status})`;
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
errorMessage = `OrgX request failed (${response.status})`;
|
|
122
|
+
}
|
|
123
|
+
const statusToken = `HTTP ${response.status}`;
|
|
124
|
+
if (response.status &&
|
|
125
|
+
!errorMessage.toLowerCase().includes(statusToken.toLowerCase()) &&
|
|
126
|
+
!errorMessage.includes(`(${response.status})`)) {
|
|
127
|
+
errorMessage = `${errorMessage} (HTTP ${response.status})`;
|
|
128
|
+
}
|
|
129
|
+
const debugParts = [];
|
|
130
|
+
const requestId = response.headers.get("x-request-id");
|
|
131
|
+
const vercelId = response.headers.get("x-vercel-id");
|
|
132
|
+
const cfRay = response.headers.get("cf-ray");
|
|
133
|
+
const clerkStatus = response.headers.get("x-clerk-auth-status");
|
|
134
|
+
const clerkReason = response.headers.get("x-clerk-auth-reason");
|
|
135
|
+
if (requestId)
|
|
136
|
+
debugParts.push(`req=${requestId}`);
|
|
137
|
+
if (vercelId && vercelId !== requestId)
|
|
138
|
+
debugParts.push(`vercel=${vercelId}`);
|
|
139
|
+
if (cfRay)
|
|
140
|
+
debugParts.push(`cf-ray=${cfRay}`);
|
|
141
|
+
if (clerkStatus)
|
|
142
|
+
debugParts.push(`clerk=${clerkStatus}`);
|
|
143
|
+
if (clerkReason)
|
|
144
|
+
debugParts.push(`clerk_reason=${clerkReason}`);
|
|
145
|
+
const debugSuffix = debugParts.length > 0 ? ` (${debugParts.join(", ")})` : "";
|
|
146
|
+
return {
|
|
147
|
+
ok: false,
|
|
148
|
+
status: response.status,
|
|
149
|
+
error: `${errorMessage}${debugSuffix}`,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
if (payload?.data !== undefined) {
|
|
153
|
+
return { ok: true, data: payload.data };
|
|
154
|
+
}
|
|
155
|
+
if (payload !== null) {
|
|
156
|
+
return { ok: true, data: payload };
|
|
157
|
+
}
|
|
158
|
+
return { ok: true, data: rawText };
|
|
159
|
+
}
|
|
160
|
+
catch (err) {
|
|
161
|
+
const message = err &&
|
|
162
|
+
typeof err === "object" &&
|
|
163
|
+
"name" in err &&
|
|
164
|
+
err.name === "AbortError"
|
|
165
|
+
? `OrgX request timed out (method=${input.method}, path=${input.path})`
|
|
166
|
+
: input.toErrorMessage(err);
|
|
167
|
+
return { ok: false, status: 0, error: message };
|
|
168
|
+
}
|
|
169
|
+
}
|
package/dist/auth-store.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
2
|
import { randomUUID } from 'node:crypto';
|
|
3
3
|
import { getOrgxPluginConfigDir, getOrgxPluginConfigPath } from './paths.js';
|
|
4
4
|
import { backupCorruptFileSync, writeJsonFileAtomicSync } from './fs-utils.js';
|
|
5
|
+
import { clearStoreFileSync, ensureStoreDirSync, parseJsonSafe, } from "./stores/json-store.js";
|
|
5
6
|
function authDir() {
|
|
6
7
|
return getOrgxPluginConfigDir();
|
|
7
8
|
}
|
|
@@ -14,23 +15,11 @@ function installationFile() {
|
|
|
14
15
|
function isUserScopedApiKey(apiKey) {
|
|
15
16
|
return apiKey.trim().toLowerCase().startsWith('oxk_');
|
|
16
17
|
}
|
|
17
|
-
function
|
|
18
|
-
|
|
19
|
-
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
20
|
-
try {
|
|
21
|
-
chmodSync(dir, 0o700);
|
|
22
|
-
}
|
|
23
|
-
catch {
|
|
24
|
-
// best effort
|
|
25
|
-
}
|
|
18
|
+
function isUuid(value) {
|
|
19
|
+
return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);
|
|
26
20
|
}
|
|
27
|
-
function
|
|
28
|
-
|
|
29
|
-
return JSON.parse(value);
|
|
30
|
-
}
|
|
31
|
-
catch {
|
|
32
|
-
return null;
|
|
33
|
-
}
|
|
21
|
+
function ensureAuthDir() {
|
|
22
|
+
ensureStoreDirSync(authDir());
|
|
34
23
|
}
|
|
35
24
|
export function getAuthFilePath() {
|
|
36
25
|
return authFile();
|
|
@@ -41,7 +30,7 @@ export function readPersistedAuth() {
|
|
|
41
30
|
if (!existsSync(file))
|
|
42
31
|
return null;
|
|
43
32
|
const raw = readFileSync(file, 'utf8');
|
|
44
|
-
const parsed =
|
|
33
|
+
const parsed = parseJsonSafe(raw);
|
|
45
34
|
if (!parsed) {
|
|
46
35
|
backupCorruptFileSync(file);
|
|
47
36
|
return null;
|
|
@@ -49,17 +38,6 @@ export function readPersistedAuth() {
|
|
|
49
38
|
if (!parsed || typeof parsed.apiKey !== 'string' || parsed.apiKey.trim().length === 0) {
|
|
50
39
|
return null;
|
|
51
40
|
}
|
|
52
|
-
if (isUserScopedApiKey(parsed.apiKey) &&
|
|
53
|
-
typeof parsed.userId === 'string' &&
|
|
54
|
-
parsed.userId.trim().length > 0) {
|
|
55
|
-
const sanitized = {
|
|
56
|
-
...parsed,
|
|
57
|
-
userId: null,
|
|
58
|
-
updatedAt: new Date().toISOString(),
|
|
59
|
-
};
|
|
60
|
-
writeJsonFileAtomicSync(file, sanitized, 0o600);
|
|
61
|
-
return sanitized;
|
|
62
|
-
}
|
|
63
41
|
return parsed;
|
|
64
42
|
}
|
|
65
43
|
catch {
|
|
@@ -70,9 +48,12 @@ export function writePersistedAuth(input) {
|
|
|
70
48
|
ensureAuthDir();
|
|
71
49
|
const now = new Date().toISOString();
|
|
72
50
|
const existing = readPersistedAuth();
|
|
73
|
-
const
|
|
51
|
+
const rawUserId = typeof input.userId === 'string' ? input.userId.trim() : '';
|
|
52
|
+
const normalizedUserId = rawUserId.length === 0
|
|
74
53
|
? null
|
|
75
|
-
: input.
|
|
54
|
+
: isUserScopedApiKey(input.apiKey)
|
|
55
|
+
? (isUuid(rawUserId) ? rawUserId : null)
|
|
56
|
+
: rawUserId;
|
|
76
57
|
const next = {
|
|
77
58
|
apiKey: input.apiKey,
|
|
78
59
|
source: input.source,
|
|
@@ -88,13 +69,7 @@ export function writePersistedAuth(input) {
|
|
|
88
69
|
return next;
|
|
89
70
|
}
|
|
90
71
|
export function clearPersistedAuth() {
|
|
91
|
-
|
|
92
|
-
try {
|
|
93
|
-
rmSync(file, { force: true });
|
|
94
|
-
}
|
|
95
|
-
catch {
|
|
96
|
-
// best effort
|
|
97
|
-
}
|
|
72
|
+
clearStoreFileSync(authFile());
|
|
98
73
|
}
|
|
99
74
|
function readInstallationRecord() {
|
|
100
75
|
const file = installationFile();
|
|
@@ -102,7 +77,7 @@ function readInstallationRecord() {
|
|
|
102
77
|
if (!existsSync(file))
|
|
103
78
|
return null;
|
|
104
79
|
const raw = readFileSync(file, 'utf8');
|
|
105
|
-
const parsed =
|
|
80
|
+
const parsed = parseJsonSafe(raw);
|
|
106
81
|
if (!parsed) {
|
|
107
82
|
backupCorruptFileSync(file);
|
|
108
83
|
return null;
|
package/dist/byok-store.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { getOpenClawDir } from "./paths.js";
|
|
4
4
|
import { backupCorruptFileSync, writeJsonFileAtomicSync } from "./fs-utils.js";
|
|
5
|
+
import { ensureStoreDirSync, parseJsonSafe, } from "./stores/json-store.js";
|
|
5
6
|
const PROVIDER_PROFILE_MAP = {
|
|
6
7
|
openaiApiKey: { profileId: "openai-codex", provider: "openai-codex" },
|
|
7
8
|
anthropicApiKey: { profileId: "anthropic", provider: "anthropic" },
|
|
@@ -18,14 +19,6 @@ function isSafePathSegment(value) {
|
|
|
18
19
|
return false;
|
|
19
20
|
return true;
|
|
20
21
|
}
|
|
21
|
-
function parseJson(value) {
|
|
22
|
-
try {
|
|
23
|
-
return JSON.parse(value);
|
|
24
|
-
}
|
|
25
|
-
catch {
|
|
26
|
-
return null;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
22
|
function readObject(value) {
|
|
30
23
|
return value && typeof value === "object" && !Array.isArray(value)
|
|
31
24
|
? value
|
|
@@ -36,7 +29,7 @@ function resolveDefaultAgentId() {
|
|
|
36
29
|
const configPath = join(getOpenClawDir(), "openclaw.json");
|
|
37
30
|
if (!existsSync(configPath))
|
|
38
31
|
return "main";
|
|
39
|
-
const raw =
|
|
32
|
+
const raw = parseJsonSafe(readFileSync(configPath, "utf8"));
|
|
40
33
|
const agents = readObject(raw?.agents);
|
|
41
34
|
const list = Array.isArray(agents.list) ? agents.list : [];
|
|
42
35
|
for (const entry of list) {
|
|
@@ -70,14 +63,7 @@ function authProfilesFile() {
|
|
|
70
63
|
return join(authProfilesDir(), "auth-profiles.json");
|
|
71
64
|
}
|
|
72
65
|
function ensureAuthProfilesDir() {
|
|
73
|
-
|
|
74
|
-
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
75
|
-
try {
|
|
76
|
-
chmodSync(dir, 0o700);
|
|
77
|
-
}
|
|
78
|
-
catch {
|
|
79
|
-
// best effort
|
|
80
|
-
}
|
|
66
|
+
ensureStoreDirSync(authProfilesDir());
|
|
81
67
|
}
|
|
82
68
|
function normalizeAuthProfileEntry(value) {
|
|
83
69
|
if (!value || typeof value !== "object")
|
|
@@ -96,7 +82,7 @@ function readAuthProfiles() {
|
|
|
96
82
|
if (!existsSync(file))
|
|
97
83
|
return { file, parsed: null };
|
|
98
84
|
const raw = readFileSync(file, "utf8");
|
|
99
|
-
const parsed =
|
|
85
|
+
const parsed = parseJsonSafe(raw);
|
|
100
86
|
if (!parsed || typeof parsed !== "object") {
|
|
101
87
|
backupCorruptFileSync(file);
|
|
102
88
|
return { file, parsed: null };
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { OrgXClient } from "../api.js";
|
|
2
|
+
import type { OnboardingState, OrgSnapshot } from "../types.js";
|
|
3
|
+
import type { ResolvedConfig } from "../config/resolution.js";
|
|
4
|
+
type DoctorCheckStatus = "pass" | "warn" | "fail";
|
|
5
|
+
type ReplayStatus = "idle" | "running" | "success" | "error";
|
|
6
|
+
interface DoctorCheck {
|
|
7
|
+
id: string;
|
|
8
|
+
status: DoctorCheckStatus;
|
|
9
|
+
message: string;
|
|
10
|
+
}
|
|
11
|
+
export interface HealthReport {
|
|
12
|
+
ok: boolean;
|
|
13
|
+
status: "ok" | "degraded" | "error";
|
|
14
|
+
generatedAt: string;
|
|
15
|
+
checks: DoctorCheck[];
|
|
16
|
+
plugin: {
|
|
17
|
+
version: string;
|
|
18
|
+
installationId: string;
|
|
19
|
+
enabled: boolean;
|
|
20
|
+
dashboardEnabled: boolean;
|
|
21
|
+
baseUrl: string;
|
|
22
|
+
};
|
|
23
|
+
auth: {
|
|
24
|
+
hasApiKey: boolean;
|
|
25
|
+
keySource: ResolvedConfig["apiKeySource"];
|
|
26
|
+
userIdConfigured: boolean;
|
|
27
|
+
onboardingStatus: OnboardingState["status"];
|
|
28
|
+
};
|
|
29
|
+
sync: {
|
|
30
|
+
serviceRunning: boolean;
|
|
31
|
+
inFlight: boolean;
|
|
32
|
+
lastSnapshotAt: string | null;
|
|
33
|
+
};
|
|
34
|
+
outbox: {
|
|
35
|
+
pendingTotal: number;
|
|
36
|
+
pendingByQueue: Record<string, number>;
|
|
37
|
+
oldestEventAt: string | null;
|
|
38
|
+
newestEventAt: string | null;
|
|
39
|
+
replayStatus: ReplayStatus;
|
|
40
|
+
lastReplayAttemptAt: string | null;
|
|
41
|
+
lastReplaySuccessAt: string | null;
|
|
42
|
+
lastReplayFailureAt: string | null;
|
|
43
|
+
lastReplayError: string | null;
|
|
44
|
+
};
|
|
45
|
+
remote: {
|
|
46
|
+
enabled: boolean;
|
|
47
|
+
reachable: boolean | null;
|
|
48
|
+
latencyMs: number | null;
|
|
49
|
+
error: string | null;
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
export interface RegisterOrgxCliDeps {
|
|
53
|
+
registerCli: (fn: (ctx: {
|
|
54
|
+
program: any;
|
|
55
|
+
}) => void, options?: {
|
|
56
|
+
commands?: string[];
|
|
57
|
+
}) => void;
|
|
58
|
+
client: OrgXClient;
|
|
59
|
+
formatSnapshot: (snapshot: OrgSnapshot) => string;
|
|
60
|
+
buildHealthReport: (input?: {
|
|
61
|
+
probeRemote?: boolean;
|
|
62
|
+
}) => Promise<HealthReport>;
|
|
63
|
+
apiKeySourceLabel: (source: ResolvedConfig["apiKeySource"]) => string;
|
|
64
|
+
}
|
|
65
|
+
export declare function registerOrgxCli(deps: RegisterOrgxCliDeps): void;
|
|
66
|
+
export {};
|
package/dist/cli/orgx.js
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
export function registerOrgxCli(deps) {
|
|
2
|
+
deps.registerCli(({ program }) => {
|
|
3
|
+
const cmd = program.command("orgx").description("OrgX integration commands");
|
|
4
|
+
cmd
|
|
5
|
+
.command("status")
|
|
6
|
+
.description("Show current OrgX org status")
|
|
7
|
+
.action(async () => {
|
|
8
|
+
try {
|
|
9
|
+
const snap = await deps.client.getOrgSnapshot();
|
|
10
|
+
console.log(deps.formatSnapshot(snap));
|
|
11
|
+
}
|
|
12
|
+
catch (err) {
|
|
13
|
+
console.error(`Error: ${err instanceof Error ? err.message : err}`);
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
cmd
|
|
18
|
+
.command("sync")
|
|
19
|
+
.description("Trigger manual memory sync")
|
|
20
|
+
.option("--memory <text>", "Memory to push")
|
|
21
|
+
.option("--daily-log <text>", "Daily log to push")
|
|
22
|
+
.action(async (opts = {}) => {
|
|
23
|
+
try {
|
|
24
|
+
const resp = await deps.client.syncMemory({
|
|
25
|
+
memory: opts.memory,
|
|
26
|
+
dailyLog: opts.dailyLog,
|
|
27
|
+
});
|
|
28
|
+
console.log("Sync complete:");
|
|
29
|
+
console.log(` Initiatives: ${resp.initiatives?.length ?? 0}`);
|
|
30
|
+
console.log(` Active tasks: ${resp.activeTasks?.length ?? 0}`);
|
|
31
|
+
console.log(` Pending decisions: ${resp.pendingDecisions?.length ?? 0}`);
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
console.error(`Sync failed: ${err instanceof Error ? err.message : err}`);
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
cmd
|
|
39
|
+
.command("doctor")
|
|
40
|
+
.description("Run plugin diagnostics and connectivity checks")
|
|
41
|
+
.option("--json", "Print the report as JSON")
|
|
42
|
+
.option("--no-remote", "Skip remote OrgX API reachability probe")
|
|
43
|
+
.action(async (opts = {}) => {
|
|
44
|
+
try {
|
|
45
|
+
const report = await deps.buildHealthReport({
|
|
46
|
+
probeRemote: opts.remote !== false,
|
|
47
|
+
});
|
|
48
|
+
if (opts.json) {
|
|
49
|
+
console.log(JSON.stringify(report, null, 2));
|
|
50
|
+
if (!report.ok)
|
|
51
|
+
process.exit(1);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
console.log("OrgX Doctor");
|
|
55
|
+
console.log(` Status: ${report.status.toUpperCase()}`);
|
|
56
|
+
console.log(` Plugin: v${report.plugin.version}`);
|
|
57
|
+
console.log(` Base URL: ${report.plugin.baseUrl}`);
|
|
58
|
+
console.log(` API Key Source: ${deps.apiKeySourceLabel(report.auth.keySource)}`);
|
|
59
|
+
console.log(` Outbox Pending: ${report.outbox.pendingTotal}`);
|
|
60
|
+
console.log("");
|
|
61
|
+
console.log("Checks:");
|
|
62
|
+
for (const check of report.checks) {
|
|
63
|
+
const prefix = check.status === "pass"
|
|
64
|
+
? "[PASS]"
|
|
65
|
+
: check.status === "warn"
|
|
66
|
+
? "[WARN]"
|
|
67
|
+
: "[FAIL]";
|
|
68
|
+
console.log(` ${prefix} ${check.message}`);
|
|
69
|
+
}
|
|
70
|
+
if (report.remote.enabled) {
|
|
71
|
+
if (report.remote.reachable === true) {
|
|
72
|
+
console.log(` Remote probe latency: ${report.remote.latencyMs ?? "?"}ms`);
|
|
73
|
+
}
|
|
74
|
+
else if (report.remote.reachable === false) {
|
|
75
|
+
console.log(` Remote probe error: ${report.remote.error ?? "Unknown error"}`);
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
console.log(" Remote probe: skipped");
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (!report.ok) {
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
console.error(`Doctor failed: ${err instanceof Error ? err.message : err}`);
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
}, { commands: ["orgx"] });
|
|
91
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { OnboardingState } from "../types.js";
|
|
2
|
+
import type { PluginApiLike, ResolvedConfig } from "./resolution.js";
|
|
3
|
+
type AuthStoreState = {
|
|
4
|
+
apiKey?: string | null;
|
|
5
|
+
userId?: string | null;
|
|
6
|
+
} | null;
|
|
7
|
+
type RefreshInput = {
|
|
8
|
+
reason?: string;
|
|
9
|
+
allowApiKeyChanges?: boolean;
|
|
10
|
+
};
|
|
11
|
+
type RefreshDeps = {
|
|
12
|
+
api: PluginApiLike;
|
|
13
|
+
config: ResolvedConfig;
|
|
14
|
+
loadAuthStore: () => AuthStoreState;
|
|
15
|
+
resolveConfig: (api: PluginApiLike, input: {
|
|
16
|
+
installationId: string;
|
|
17
|
+
persistedApiKey: string | null;
|
|
18
|
+
persistedUserId: string | null;
|
|
19
|
+
}) => ResolvedConfig;
|
|
20
|
+
updateOnboardingState: (updates: Partial<OnboardingState>) => unknown;
|
|
21
|
+
setCredentials: (input: {
|
|
22
|
+
apiKey: string;
|
|
23
|
+
userId: string;
|
|
24
|
+
baseUrl: string;
|
|
25
|
+
}) => void;
|
|
26
|
+
logInfo?: (message: string, meta?: Record<string, unknown>) => void;
|
|
27
|
+
};
|
|
28
|
+
export declare function refreshResolvedConfig(deps: RefreshDeps, input?: RefreshInput): {
|
|
29
|
+
changed: boolean;
|
|
30
|
+
baseApiUrl: string;
|
|
31
|
+
};
|
|
32
|
+
export {};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export function refreshResolvedConfig(deps, input) {
|
|
2
|
+
const allowApiKeyChanges = input?.allowApiKeyChanges !== false;
|
|
3
|
+
const previousApiKey = deps.config.apiKey;
|
|
4
|
+
const previousBaseUrl = deps.config.baseUrl;
|
|
5
|
+
const previousUserId = deps.config.userId;
|
|
6
|
+
const previousDocsUrl = deps.config.docsUrl;
|
|
7
|
+
const previousKeySource = deps.config.apiKeySource;
|
|
8
|
+
const latestPersisted = deps.loadAuthStore();
|
|
9
|
+
const next = deps.resolveConfig(deps.api, {
|
|
10
|
+
installationId: deps.config.installationId,
|
|
11
|
+
persistedApiKey: latestPersisted?.apiKey ?? null,
|
|
12
|
+
persistedUserId: latestPersisted?.userId ?? null,
|
|
13
|
+
});
|
|
14
|
+
const nextApiKey = allowApiKeyChanges ? next.apiKey : previousApiKey;
|
|
15
|
+
const nextUserId = allowApiKeyChanges ? next.userId : previousUserId;
|
|
16
|
+
const changed = nextApiKey !== previousApiKey ||
|
|
17
|
+
next.baseUrl !== previousBaseUrl ||
|
|
18
|
+
nextUserId !== previousUserId ||
|
|
19
|
+
next.docsUrl !== previousDocsUrl ||
|
|
20
|
+
next.apiKeySource !== previousKeySource;
|
|
21
|
+
if (!changed) {
|
|
22
|
+
return {
|
|
23
|
+
changed: false,
|
|
24
|
+
baseApiUrl: deps.config.baseUrl.replace(/\/+$/, ""),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
if (allowApiKeyChanges) {
|
|
28
|
+
deps.config.apiKey = nextApiKey;
|
|
29
|
+
deps.config.userId = nextUserId;
|
|
30
|
+
deps.config.apiKeySource = next.apiKeySource;
|
|
31
|
+
}
|
|
32
|
+
deps.config.baseUrl = next.baseUrl;
|
|
33
|
+
deps.config.docsUrl = next.docsUrl;
|
|
34
|
+
deps.setCredentials({
|
|
35
|
+
apiKey: deps.config.apiKey,
|
|
36
|
+
userId: deps.config.userId,
|
|
37
|
+
baseUrl: deps.config.baseUrl,
|
|
38
|
+
});
|
|
39
|
+
deps.updateOnboardingState({
|
|
40
|
+
hasApiKey: Boolean(deps.config.apiKey),
|
|
41
|
+
keySource: deps.config.apiKeySource,
|
|
42
|
+
docsUrl: deps.config.docsUrl,
|
|
43
|
+
installationId: deps.config.installationId,
|
|
44
|
+
});
|
|
45
|
+
deps.logInfo?.("[orgx] Config refreshed", {
|
|
46
|
+
reason: input?.reason ?? "runtime_refresh",
|
|
47
|
+
baseUrl: deps.config.baseUrl,
|
|
48
|
+
hasApiKey: Boolean(deps.config.apiKey),
|
|
49
|
+
apiKeySource: deps.config.apiKeySource,
|
|
50
|
+
});
|
|
51
|
+
return {
|
|
52
|
+
changed: true,
|
|
53
|
+
baseApiUrl: deps.config.baseUrl.replace(/\/+$/, ""),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { OrgXConfig } from "../types.js";
|
|
2
|
+
export interface ResolvedConfig extends OrgXConfig {
|
|
3
|
+
dashboardEnabled: boolean;
|
|
4
|
+
installationId: string;
|
|
5
|
+
pluginVersion: string;
|
|
6
|
+
docsUrl: string;
|
|
7
|
+
apiKeySource: "config" | "environment" | "persisted" | "openclaw-config-file" | "legacy-dev" | "none";
|
|
8
|
+
}
|
|
9
|
+
export interface PluginApiLike {
|
|
10
|
+
config?: {
|
|
11
|
+
plugins?: {
|
|
12
|
+
entries?: {
|
|
13
|
+
orgx?: {
|
|
14
|
+
config?: Partial<OrgXConfig & {
|
|
15
|
+
dashboardEnabled: boolean;
|
|
16
|
+
}>;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export declare function isUserScopedApiKey(apiKey: string): boolean;
|
|
23
|
+
export declare function resolveRuntimeUserId(apiKey: string, candidates: Array<string | null | undefined>): string;
|
|
24
|
+
export declare function normalizeBaseUrl(raw: string | undefined): string;
|
|
25
|
+
export declare function readLegacyEnvValue(keyPattern: RegExp): string;
|
|
26
|
+
export declare function readOpenClawOrgxConfig(): {
|
|
27
|
+
apiKey: string;
|
|
28
|
+
userId: string;
|
|
29
|
+
baseUrl: string;
|
|
30
|
+
};
|
|
31
|
+
export declare function resolvePluginVersion(): string;
|
|
32
|
+
export declare function resolveDocsUrl(baseUrl: string): string;
|
|
33
|
+
export declare function resolveConfig(api: PluginApiLike, input: {
|
|
34
|
+
installationId: string;
|
|
35
|
+
persistedApiKey: string | null;
|
|
36
|
+
persistedUserId: string | null;
|
|
37
|
+
}): ResolvedConfig;
|