@useorgx/openclaw-plugin 0.4.8 → 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/dashboard/dist/assets/B5NEElEI.css +1 -0
- package/dashboard/dist/assets/BhapSNAs.js +215 -0
- package/dashboard/dist/assets/{BNeJ0kpF.js → iFdvE7lx.js} +1 -1
- package/dashboard/dist/assets/{CUV9IHHi.js → jRJsmpYM.js} +1 -1
- package/dashboard/dist/index.html +2 -2
- package/dist/activity-store.js +4 -18
- 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/auth/flows.d.ts +47 -0
- package/dist/auth/flows.js +169 -0
- package/dist/auth-store.js +6 -26
- 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/shared-types.d.ts +147 -0
- package/dist/contracts/shared-types.js +3 -0
- package/dist/contracts/types.d.ts +1 -134
- 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 -10605
- package/dist/index.js +108 -2243
- package/dist/json-utils.d.ts +1 -0
- package/dist/json-utils.js +8 -0
- package/dist/next-up-queue-store.js +4 -18
- package/dist/runtime-instance-store.js +5 -31
- 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/package.json +1 -1
- package/dashboard/dist/assets/BzkiMPmM.js +0 -215
- package/dashboard/dist/assets/Ie7d9Iq2.css +0 -1
|
@@ -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;
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
const DEFAULT_BASE_URL = "https://www.useorgx.com";
|
|
6
|
+
const DEFAULT_DOCS_URL = "https://orgx.mintlify.site/guides/openclaw-plugin-setup";
|
|
7
|
+
export function isUserScopedApiKey(apiKey) {
|
|
8
|
+
return apiKey.trim().toLowerCase().startsWith("oxk_");
|
|
9
|
+
}
|
|
10
|
+
export function resolveRuntimeUserId(apiKey, candidates) {
|
|
11
|
+
if (isUserScopedApiKey(apiKey)) {
|
|
12
|
+
// For oxk_ keys, the OrgX API ignores X-Orgx-User-Id, but we still keep a UUID
|
|
13
|
+
// around for created_by_id on certain entity writes (e.g., work_artifacts).
|
|
14
|
+
for (const candidate of candidates) {
|
|
15
|
+
if (typeof candidate !== "string")
|
|
16
|
+
continue;
|
|
17
|
+
const trimmed = candidate.trim();
|
|
18
|
+
if (/^[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(trimmed)) {
|
|
19
|
+
return trimmed;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return "";
|
|
23
|
+
}
|
|
24
|
+
for (const candidate of candidates) {
|
|
25
|
+
if (typeof candidate === "string") {
|
|
26
|
+
const trimmed = candidate.trim();
|
|
27
|
+
if (trimmed.length > 0)
|
|
28
|
+
return trimmed;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return "";
|
|
32
|
+
}
|
|
33
|
+
function normalizeHost(value) {
|
|
34
|
+
return value.trim().toLowerCase().replace(/^\[|\]$/g, "");
|
|
35
|
+
}
|
|
36
|
+
function isLoopbackHostname(hostname) {
|
|
37
|
+
const normalized = normalizeHost(hostname);
|
|
38
|
+
return normalized === "localhost" || normalized === "127.0.0.1" || normalized === "::1";
|
|
39
|
+
}
|
|
40
|
+
export function normalizeBaseUrl(raw) {
|
|
41
|
+
const candidate = raw?.trim() ?? "";
|
|
42
|
+
if (!candidate) {
|
|
43
|
+
return DEFAULT_BASE_URL;
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
const parsed = new URL(candidate);
|
|
47
|
+
if (parsed.protocol !== "https:" && parsed.protocol !== "http:") {
|
|
48
|
+
return DEFAULT_BASE_URL;
|
|
49
|
+
}
|
|
50
|
+
// Do not allow credential-bearing URLs.
|
|
51
|
+
if (parsed.username || parsed.password) {
|
|
52
|
+
return DEFAULT_BASE_URL;
|
|
53
|
+
}
|
|
54
|
+
// Plain HTTP is only allowed for local loopback development.
|
|
55
|
+
if (parsed.protocol === "http:" && !isLoopbackHostname(parsed.hostname)) {
|
|
56
|
+
return DEFAULT_BASE_URL;
|
|
57
|
+
}
|
|
58
|
+
parsed.search = "";
|
|
59
|
+
parsed.hash = "";
|
|
60
|
+
const normalizedPath = parsed.pathname.replace(/\/+$/, "");
|
|
61
|
+
parsed.pathname = normalizedPath;
|
|
62
|
+
const normalized = parsed.toString().replace(/\/+$/, "");
|
|
63
|
+
return normalized.length > 0 ? normalized : DEFAULT_BASE_URL;
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return DEFAULT_BASE_URL;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
export function readLegacyEnvValue(keyPattern) {
|
|
70
|
+
try {
|
|
71
|
+
const envPath = join(homedir(), "Code", "orgx", "orgx", ".env.local");
|
|
72
|
+
const envContent = readFileSync(envPath, "utf-8");
|
|
73
|
+
const match = envContent.match(keyPattern);
|
|
74
|
+
return match?.[1]?.trim() ?? "";
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return "";
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
export function readOpenClawOrgxConfig() {
|
|
81
|
+
try {
|
|
82
|
+
const configPath = join(homedir(), ".openclaw", "openclaw.json");
|
|
83
|
+
const raw = readFileSync(configPath, "utf8");
|
|
84
|
+
const parsed = JSON.parse(raw);
|
|
85
|
+
const plugins = parsed.plugins && typeof parsed.plugins === "object"
|
|
86
|
+
? parsed.plugins
|
|
87
|
+
: {};
|
|
88
|
+
const entries = plugins.entries && typeof plugins.entries === "object"
|
|
89
|
+
? plugins.entries
|
|
90
|
+
: {};
|
|
91
|
+
const orgx = entries.orgx && typeof entries.orgx === "object"
|
|
92
|
+
? entries.orgx
|
|
93
|
+
: {};
|
|
94
|
+
const config = orgx.config && typeof orgx.config === "object"
|
|
95
|
+
? orgx.config
|
|
96
|
+
: {};
|
|
97
|
+
const apiKey = typeof config.apiKey === "string" ? config.apiKey.trim() : "";
|
|
98
|
+
const userId = typeof config.userId === "string" ? config.userId.trim() : "";
|
|
99
|
+
const baseUrl = typeof config.baseUrl === "string" ? config.baseUrl.trim() : "";
|
|
100
|
+
return { apiKey, userId, baseUrl };
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return { apiKey: "", userId: "", baseUrl: "" };
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function resolveApiKey(pluginConf, persistedApiKey) {
|
|
107
|
+
if (pluginConf.apiKey && pluginConf.apiKey.trim().length > 0) {
|
|
108
|
+
return { value: pluginConf.apiKey.trim(), source: "config" };
|
|
109
|
+
}
|
|
110
|
+
if (process.env.ORGX_API_KEY && process.env.ORGX_API_KEY.trim().length > 0) {
|
|
111
|
+
return { value: process.env.ORGX_API_KEY.trim(), source: "environment" };
|
|
112
|
+
}
|
|
113
|
+
if (persistedApiKey && persistedApiKey.trim().length > 0) {
|
|
114
|
+
return { value: persistedApiKey.trim(), source: "persisted" };
|
|
115
|
+
}
|
|
116
|
+
const openclaw = readOpenClawOrgxConfig();
|
|
117
|
+
if (openclaw.apiKey) {
|
|
118
|
+
return { value: openclaw.apiKey, source: "openclaw-config-file" };
|
|
119
|
+
}
|
|
120
|
+
// For local dev convenience we read `ORGX_API_KEY` from `~/Code/orgx/orgx/.env.local`.
|
|
121
|
+
// Do not auto-consume `ORGX_SERVICE_KEY` because service keys often require `X-Orgx-User-Id`,
|
|
122
|
+
// and the dashboard/client flows are intended to run on user-scoped keys (`oxk_...`).
|
|
123
|
+
const legacy = readLegacyEnvValue(/^ORGX_API_KEY=["']?([^"'\n]+)["']?$/m);
|
|
124
|
+
if (legacy) {
|
|
125
|
+
return { value: legacy, source: "legacy-dev" };
|
|
126
|
+
}
|
|
127
|
+
return { value: "", source: "none" };
|
|
128
|
+
}
|
|
129
|
+
export function resolvePluginVersion() {
|
|
130
|
+
try {
|
|
131
|
+
const packagePath = fileURLToPath(new URL("../../package.json", import.meta.url));
|
|
132
|
+
const parsed = JSON.parse(readFileSync(packagePath, "utf8"));
|
|
133
|
+
return parsed.version && parsed.version.trim().length > 0 ? parsed.version : "dev";
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
return "dev";
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
export function resolveDocsUrl(baseUrl) {
|
|
140
|
+
const normalized = baseUrl.replace(/\/+$/, "");
|
|
141
|
+
try {
|
|
142
|
+
const parsed = new URL(normalized);
|
|
143
|
+
if (isLoopbackHostname(parsed.hostname)) {
|
|
144
|
+
return `${normalized}/docs/mintlify/guides/openclaw-plugin-setup`;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
return DEFAULT_DOCS_URL;
|
|
149
|
+
}
|
|
150
|
+
return DEFAULT_DOCS_URL;
|
|
151
|
+
}
|
|
152
|
+
export function resolveConfig(api, input) {
|
|
153
|
+
const pluginConf = api.config?.plugins?.entries?.orgx?.config ?? {};
|
|
154
|
+
const openclaw = readOpenClawOrgxConfig();
|
|
155
|
+
const apiKeyResolution = resolveApiKey(pluginConf, input.persistedApiKey);
|
|
156
|
+
const apiKey = apiKeyResolution.value;
|
|
157
|
+
const userId = resolveRuntimeUserId(apiKey, [
|
|
158
|
+
pluginConf.userId,
|
|
159
|
+
process.env.ORGX_USER_ID,
|
|
160
|
+
input.persistedUserId,
|
|
161
|
+
openclaw.userId,
|
|
162
|
+
readLegacyEnvValue(/^ORGX_USER_ID=["']?([^"'\n]+)["']?$/m),
|
|
163
|
+
]);
|
|
164
|
+
const baseUrl = normalizeBaseUrl(pluginConf.baseUrl || process.env.ORGX_BASE_URL || openclaw.baseUrl || DEFAULT_BASE_URL);
|
|
165
|
+
return {
|
|
166
|
+
apiKey,
|
|
167
|
+
userId,
|
|
168
|
+
baseUrl,
|
|
169
|
+
syncIntervalMs: pluginConf.syncIntervalMs ?? 300_000,
|
|
170
|
+
enabled: pluginConf.enabled ?? true,
|
|
171
|
+
autoInstallAgentSuiteOnConnect: pluginConf.autoInstallAgentSuiteOnConnect ?? true,
|
|
172
|
+
dashboardEnabled: pluginConf.dashboardEnabled ?? true,
|
|
173
|
+
installationId: input.installationId,
|
|
174
|
+
pluginVersion: resolvePluginVersion(),
|
|
175
|
+
docsUrl: resolveDocsUrl(baseUrl),
|
|
176
|
+
apiKeySource: apiKeyResolution.source,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
export type OnboardingStatus = 'idle' | 'starting' | 'awaiting_browser_auth' | 'pairing' | 'connected' | 'error' | 'manual_key';
|
|
2
|
+
export type OnboardingNextAction = 'connect' | 'wait_for_browser' | 'open_dashboard' | 'retry' | 'start_pairing' | 'open_browser' | 'poll' | 'enter_manual_key' | 'reconnect' | 'none';
|
|
3
|
+
export type OnboardingKeySource = 'config' | 'environment' | 'persisted' | 'openclaw-config-file' | 'legacy-dev' | 'none';
|
|
4
|
+
export interface OnboardingState {
|
|
5
|
+
status: OnboardingStatus;
|
|
6
|
+
hasApiKey: boolean;
|
|
7
|
+
connectionVerified: boolean;
|
|
8
|
+
workspaceName: string | null;
|
|
9
|
+
lastError: string | null;
|
|
10
|
+
nextAction: OnboardingNextAction;
|
|
11
|
+
docsUrl: string;
|
|
12
|
+
keySource?: OnboardingKeySource;
|
|
13
|
+
installationId?: string | null;
|
|
14
|
+
connectUrl: string | null;
|
|
15
|
+
pairingId?: string | null;
|
|
16
|
+
expiresAt: string | null;
|
|
17
|
+
pollIntervalMs: number | null;
|
|
18
|
+
}
|
|
19
|
+
export type RunPhase = 'intent' | 'execution' | 'blocked' | 'review' | 'handoff' | 'completed';
|
|
20
|
+
export type RuntimeSourceClient = 'openclaw' | 'codex' | 'claude-code' | 'api' | 'unknown';
|
|
21
|
+
export type RuntimeProviderLogo = 'codex' | 'openai' | 'anthropic' | 'openclaw' | 'orgx' | 'unknown';
|
|
22
|
+
export type RuntimeInstanceState = 'active' | 'stale' | 'stopped' | 'error';
|
|
23
|
+
export interface RuntimeInstance {
|
|
24
|
+
id: string;
|
|
25
|
+
sourceClient: RuntimeSourceClient;
|
|
26
|
+
displayName: string;
|
|
27
|
+
providerLogo: RuntimeProviderLogo;
|
|
28
|
+
state: RuntimeInstanceState;
|
|
29
|
+
runId: string | null;
|
|
30
|
+
correlationId: string | null;
|
|
31
|
+
initiativeId: string | null;
|
|
32
|
+
workstreamId: string | null;
|
|
33
|
+
taskId: string | null;
|
|
34
|
+
agentId: string | null;
|
|
35
|
+
agentName: string | null;
|
|
36
|
+
phase: string | null;
|
|
37
|
+
progressPct: number | null;
|
|
38
|
+
currentTask: string | null;
|
|
39
|
+
lastHeartbeatAt: string | null;
|
|
40
|
+
lastEventAt: string;
|
|
41
|
+
lastMessage: string | null;
|
|
42
|
+
metadata: Record<string, unknown> | null;
|
|
43
|
+
}
|
|
44
|
+
export type LiveActivityType = 'run_started' | 'run_completed' | 'run_failed' | 'artifact_created' | 'decision_requested' | 'decision_resolved' | 'handoff_requested' | 'handoff_claimed' | 'handoff_fulfilled' | 'blocker_created' | 'milestone_completed' | 'delegation';
|
|
45
|
+
export interface LiveActivityItem {
|
|
46
|
+
id: string;
|
|
47
|
+
type: LiveActivityType;
|
|
48
|
+
title: string;
|
|
49
|
+
description: string | null;
|
|
50
|
+
agentId: string | null;
|
|
51
|
+
agentName: string | null;
|
|
52
|
+
requesterAgentId: string | null;
|
|
53
|
+
requesterAgentName: string | null;
|
|
54
|
+
executorAgentId: string | null;
|
|
55
|
+
executorAgentName: string | null;
|
|
56
|
+
runId: string | null;
|
|
57
|
+
initiativeId: string | null;
|
|
58
|
+
timestamp: string;
|
|
59
|
+
phase?: RunPhase | null;
|
|
60
|
+
state?: string | null;
|
|
61
|
+
kind?: string | null;
|
|
62
|
+
summary?: string | null;
|
|
63
|
+
decisionRequired?: boolean;
|
|
64
|
+
costDelta?: number | null;
|
|
65
|
+
runtimeClient?: RuntimeSourceClient | null;
|
|
66
|
+
runtimeLabel?: string | null;
|
|
67
|
+
runtimeProvider?: RuntimeProviderLogo | null;
|
|
68
|
+
instanceId?: string | null;
|
|
69
|
+
lastHeartbeatAt?: string | null;
|
|
70
|
+
metadata?: Record<string, unknown>;
|
|
71
|
+
}
|
|
72
|
+
export interface LiveDecision {
|
|
73
|
+
id: string;
|
|
74
|
+
title: string;
|
|
75
|
+
context: string | null;
|
|
76
|
+
status: string;
|
|
77
|
+
agentName: string | null;
|
|
78
|
+
requestedAt: string | null;
|
|
79
|
+
updatedAt: string | null;
|
|
80
|
+
waitingMinutes: number;
|
|
81
|
+
metadata?: Record<string, unknown>;
|
|
82
|
+
}
|
|
83
|
+
export interface SessionTreeNode {
|
|
84
|
+
id: string;
|
|
85
|
+
parentId: string | null;
|
|
86
|
+
runId: string;
|
|
87
|
+
title: string;
|
|
88
|
+
agentId: string | null;
|
|
89
|
+
agentName: string | null;
|
|
90
|
+
status: string;
|
|
91
|
+
progress: number | null;
|
|
92
|
+
initiativeId: string | null;
|
|
93
|
+
workstreamId: string | null;
|
|
94
|
+
groupId: string;
|
|
95
|
+
groupLabel: string;
|
|
96
|
+
startedAt: string | null;
|
|
97
|
+
updatedAt: string | null;
|
|
98
|
+
lastEventAt: string | null;
|
|
99
|
+
lastEventSummary: string | null;
|
|
100
|
+
blockers: string[];
|
|
101
|
+
phase?: RunPhase | null;
|
|
102
|
+
state?: string | null;
|
|
103
|
+
eta?: string | null;
|
|
104
|
+
cost?: number | null;
|
|
105
|
+
checkpointCount?: number | null;
|
|
106
|
+
blockerReason?: string | null;
|
|
107
|
+
runtimeClient?: RuntimeSourceClient | null;
|
|
108
|
+
runtimeLabel?: string | null;
|
|
109
|
+
runtimeProvider?: RuntimeProviderLogo | null;
|
|
110
|
+
instanceId?: string | null;
|
|
111
|
+
lastHeartbeatAt?: string | null;
|
|
112
|
+
}
|
|
113
|
+
export interface SessionTreeEdge {
|
|
114
|
+
parentId: string;
|
|
115
|
+
childId: string;
|
|
116
|
+
}
|
|
117
|
+
export interface SessionTreeGroup {
|
|
118
|
+
id: string;
|
|
119
|
+
label: string;
|
|
120
|
+
status: string | null;
|
|
121
|
+
}
|
|
122
|
+
export interface SessionTreeResponse {
|
|
123
|
+
nodes: SessionTreeNode[];
|
|
124
|
+
edges: SessionTreeEdge[];
|
|
125
|
+
groups: SessionTreeGroup[];
|
|
126
|
+
}
|
|
127
|
+
export interface HandoffEvent {
|
|
128
|
+
id: string;
|
|
129
|
+
handoffId: string;
|
|
130
|
+
eventType: string;
|
|
131
|
+
actorType: string | null;
|
|
132
|
+
actorId: string | null;
|
|
133
|
+
payload: Record<string, unknown> | null;
|
|
134
|
+
createdAt: string;
|
|
135
|
+
}
|
|
136
|
+
export interface HandoffSummary {
|
|
137
|
+
id: string;
|
|
138
|
+
title: string;
|
|
139
|
+
status: string;
|
|
140
|
+
priority: string | null;
|
|
141
|
+
summary: string | null;
|
|
142
|
+
currentActorType: string | null;
|
|
143
|
+
currentActorId: string | null;
|
|
144
|
+
createdAt: string;
|
|
145
|
+
updatedAt: string;
|
|
146
|
+
events: HandoffEvent[];
|
|
147
|
+
}
|