@useorgx/openclaw-plugin 0.1.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/README.md +125 -0
- package/dashboard/dist/assets/index-BJj_VPzn.css +1 -0
- package/dashboard/dist/assets/index-DqHqHn4Z.js +103 -0
- package/dashboard/dist/index.html +15 -0
- package/dist/api.d.ts +47 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +162 -0
- package/dist/api.js.map +1 -0
- package/dist/dashboard-api.d.ts +50 -0
- package/dist/dashboard-api.d.ts.map +1 -0
- package/dist/dashboard-api.js +107 -0
- package/dist/dashboard-api.js.map +1 -0
- package/dist/http-handler.d.ts +28 -0
- package/dist/http-handler.d.ts.map +1 -0
- package/dist/http-handler.js +215 -0
- package/dist/http-handler.js.map +1 -0
- package/dist/index.d.ts +67 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +459 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +182 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/openclaw.plugin.json +73 -0
- package/package.json +74 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
|
|
6
|
+
<meta name="apple-mobile-web-app-capable" content="yes" />
|
|
7
|
+
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
|
8
|
+
<title>OrgX Live Dashboard</title>
|
|
9
|
+
<script type="module" crossorigin src="/orgx/live/assets/index-DqHqHn4Z.js"></script>
|
|
10
|
+
<link rel="stylesheet" crossorigin href="/orgx/live/assets/index-BJj_VPzn.css">
|
|
11
|
+
</head>
|
|
12
|
+
<body class="bg-[#080808] text-white antialiased">
|
|
13
|
+
<div id="root"></div>
|
|
14
|
+
</body>
|
|
15
|
+
</html>
|
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OrgX API Client
|
|
3
|
+
*
|
|
4
|
+
* Communicates with the OrgX server for org snapshots, memory sync,
|
|
5
|
+
* quality gates, model routing, and entity CRUD.
|
|
6
|
+
*
|
|
7
|
+
* Uses native fetch — no external dependencies.
|
|
8
|
+
*/
|
|
9
|
+
import type { OrgSnapshot, SyncPayload, SyncResponse, SpawnGuardResult, QualityScore, Entity, EntityListFilters } from "./types.js";
|
|
10
|
+
export declare class OrgXClient {
|
|
11
|
+
private apiKey;
|
|
12
|
+
private baseUrl;
|
|
13
|
+
private userId;
|
|
14
|
+
constructor(apiKey: string, baseUrl: string, userId?: string);
|
|
15
|
+
private request;
|
|
16
|
+
private get;
|
|
17
|
+
private post;
|
|
18
|
+
private patch;
|
|
19
|
+
getOrgSnapshot(): Promise<OrgSnapshot>;
|
|
20
|
+
syncMemory(payload: SyncPayload): Promise<SyncResponse>;
|
|
21
|
+
checkSpawnGuard(domain: string, taskId?: string): Promise<SpawnGuardResult>;
|
|
22
|
+
recordQuality(score: QualityScore): Promise<{
|
|
23
|
+
success: boolean;
|
|
24
|
+
}>;
|
|
25
|
+
/**
|
|
26
|
+
* Create an OrgX entity.
|
|
27
|
+
* POST /api/entities { type, title, summary, status, initiative_id, ... }
|
|
28
|
+
*/
|
|
29
|
+
createEntity(type: string, data: Record<string, unknown>): Promise<Entity>;
|
|
30
|
+
/**
|
|
31
|
+
* Update an OrgX entity.
|
|
32
|
+
* PATCH /api/entities { type, id, ...updates }
|
|
33
|
+
*/
|
|
34
|
+
updateEntity(type: string, id: string, updates: Record<string, unknown>): Promise<Entity>;
|
|
35
|
+
/**
|
|
36
|
+
* List OrgX entities.
|
|
37
|
+
* GET /api/entities?type={type}&status={status}&limit={n}
|
|
38
|
+
*/
|
|
39
|
+
listEntities(type: string, filters?: EntityListFilters): Promise<{
|
|
40
|
+
data: Entity[];
|
|
41
|
+
pagination: {
|
|
42
|
+
total: number;
|
|
43
|
+
has_more: boolean;
|
|
44
|
+
};
|
|
45
|
+
}>;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EACV,WAAW,EACX,WAAW,EACX,YAAY,EACZ,gBAAgB,EAChB,YAAY,EACZ,MAAM,EACN,iBAAiB,EAClB,MAAM,YAAY,CAAC;AAKpB,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,MAAM,CAAS;gBAEX,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM;YAU9C,OAAO;IAmDrB,OAAO,CAAC,GAAG;IAIX,OAAO,CAAC,IAAI;IAIZ,OAAO,CAAC,KAAK;IAQP,cAAc,IAAI,OAAO,CAAC,WAAW,CAAC;IAiCtC,UAAU,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IAQvD,eAAe,CACnB,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,gBAAgB,CAAC;IAWtB,aAAa,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;IASvE;;;OAGG;IACG,YAAY,CAChB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,OAAO,CAAC,MAAM,CAAC;IAQlB;;;OAGG;IACG,YAAY,CAChB,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,OAAO,CAAC,MAAM,CAAC;IASlB;;;OAGG;IACG,YAAY,CAChB,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QAAC,UAAU,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,OAAO,CAAA;SAAE,CAAA;KAAE,CAAC;CAMjF"}
|
package/dist/api.js
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OrgX API Client
|
|
3
|
+
*
|
|
4
|
+
* Communicates with the OrgX server for org snapshots, memory sync,
|
|
5
|
+
* quality gates, model routing, and entity CRUD.
|
|
6
|
+
*
|
|
7
|
+
* Uses native fetch — no external dependencies.
|
|
8
|
+
*/
|
|
9
|
+
const REQUEST_TIMEOUT_MS = 10_000;
|
|
10
|
+
const USER_AGENT = "OrgX-Clawdbot-Plugin/1.0";
|
|
11
|
+
export class OrgXClient {
|
|
12
|
+
apiKey;
|
|
13
|
+
baseUrl;
|
|
14
|
+
userId;
|
|
15
|
+
constructor(apiKey, baseUrl, userId) {
|
|
16
|
+
this.apiKey = apiKey;
|
|
17
|
+
this.baseUrl = baseUrl.replace(/\/+$/, "");
|
|
18
|
+
this.userId = userId || "";
|
|
19
|
+
}
|
|
20
|
+
// ===========================================================================
|
|
21
|
+
// HTTP helpers
|
|
22
|
+
// ===========================================================================
|
|
23
|
+
async request(method, path, body) {
|
|
24
|
+
const url = `${this.baseUrl}${path}`;
|
|
25
|
+
const controller = new AbortController();
|
|
26
|
+
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
27
|
+
try {
|
|
28
|
+
const headers = {
|
|
29
|
+
"Content-Type": "application/json",
|
|
30
|
+
"User-Agent": USER_AGENT,
|
|
31
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
32
|
+
};
|
|
33
|
+
if (this.userId) {
|
|
34
|
+
headers["X-Orgx-User-Id"] = this.userId;
|
|
35
|
+
}
|
|
36
|
+
const response = await fetch(url, {
|
|
37
|
+
method,
|
|
38
|
+
headers,
|
|
39
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
40
|
+
signal: controller.signal,
|
|
41
|
+
});
|
|
42
|
+
if (!response.ok) {
|
|
43
|
+
const text = await response.text().catch(() => "");
|
|
44
|
+
throw new Error(`OrgX API ${method} ${path}: ${response.status} ${response.statusText}${text ? ` — ${text.slice(0, 200)}` : ""}`);
|
|
45
|
+
}
|
|
46
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
47
|
+
if (contentType.includes("application/json")) {
|
|
48
|
+
return (await response.json());
|
|
49
|
+
}
|
|
50
|
+
return (await response.text());
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
if (err instanceof DOMException && err.name === "AbortError") {
|
|
54
|
+
throw new Error(`OrgX API ${method} ${path} timed out after ${REQUEST_TIMEOUT_MS}ms`);
|
|
55
|
+
}
|
|
56
|
+
throw err;
|
|
57
|
+
}
|
|
58
|
+
finally {
|
|
59
|
+
clearTimeout(timeout);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
get(path) {
|
|
63
|
+
return this.request("GET", path);
|
|
64
|
+
}
|
|
65
|
+
post(path, body) {
|
|
66
|
+
return this.request("POST", path, body);
|
|
67
|
+
}
|
|
68
|
+
patch(path, body) {
|
|
69
|
+
return this.request("PATCH", path, body);
|
|
70
|
+
}
|
|
71
|
+
// ===========================================================================
|
|
72
|
+
// Org Snapshot
|
|
73
|
+
// ===========================================================================
|
|
74
|
+
async getOrgSnapshot() {
|
|
75
|
+
// Use the sync endpoint with POST (empty body = pull only)
|
|
76
|
+
const resp = await this.post("/api/client/sync", {});
|
|
77
|
+
const data = resp.data;
|
|
78
|
+
// Transform SyncResponse to OrgSnapshot format
|
|
79
|
+
return {
|
|
80
|
+
initiatives: data.initiatives.map(i => ({
|
|
81
|
+
id: i.id,
|
|
82
|
+
title: i.title,
|
|
83
|
+
status: i.status,
|
|
84
|
+
})),
|
|
85
|
+
agents: [], // Not returned by sync endpoint
|
|
86
|
+
activeTasks: data.activeTasks.map(t => ({
|
|
87
|
+
id: t.id,
|
|
88
|
+
title: t.title,
|
|
89
|
+
status: t.status,
|
|
90
|
+
domain: t.domain,
|
|
91
|
+
modelTier: t.modelTier,
|
|
92
|
+
})),
|
|
93
|
+
pendingDecisions: data.pendingDecisions.map(d => ({
|
|
94
|
+
id: d.id,
|
|
95
|
+
title: d.title,
|
|
96
|
+
urgency: d.urgency,
|
|
97
|
+
})),
|
|
98
|
+
syncedAt: data.syncedAt,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
// ===========================================================================
|
|
102
|
+
// Memory Sync
|
|
103
|
+
// ===========================================================================
|
|
104
|
+
async syncMemory(payload) {
|
|
105
|
+
return this.post("/api/client/sync", payload);
|
|
106
|
+
}
|
|
107
|
+
// ===========================================================================
|
|
108
|
+
// Spawn Guard (Quality Gate + Model Routing)
|
|
109
|
+
// ===========================================================================
|
|
110
|
+
async checkSpawnGuard(domain, taskId) {
|
|
111
|
+
return this.post("/api/client/spawn", {
|
|
112
|
+
domain,
|
|
113
|
+
taskId,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
// ===========================================================================
|
|
117
|
+
// Quality Scores
|
|
118
|
+
// ===========================================================================
|
|
119
|
+
async recordQuality(score) {
|
|
120
|
+
return this.post("/api/client/quality", score);
|
|
121
|
+
}
|
|
122
|
+
// ===========================================================================
|
|
123
|
+
// Entity CRUD
|
|
124
|
+
// Uses /api/entities with type in body (NOT per-type REST paths)
|
|
125
|
+
// ===========================================================================
|
|
126
|
+
/**
|
|
127
|
+
* Create an OrgX entity.
|
|
128
|
+
* POST /api/entities { type, title, summary, status, initiative_id, ... }
|
|
129
|
+
*/
|
|
130
|
+
async createEntity(type, data) {
|
|
131
|
+
const resp = await this.post("/api/entities", {
|
|
132
|
+
type,
|
|
133
|
+
...data,
|
|
134
|
+
});
|
|
135
|
+
return resp.data ?? resp;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Update an OrgX entity.
|
|
139
|
+
* PATCH /api/entities { type, id, ...updates }
|
|
140
|
+
*/
|
|
141
|
+
async updateEntity(type, id, updates) {
|
|
142
|
+
const resp = await this.patch("/api/entities", {
|
|
143
|
+
type,
|
|
144
|
+
id,
|
|
145
|
+
...updates,
|
|
146
|
+
});
|
|
147
|
+
return resp.data ?? resp;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* List OrgX entities.
|
|
151
|
+
* GET /api/entities?type={type}&status={status}&limit={n}
|
|
152
|
+
*/
|
|
153
|
+
async listEntities(type, filters) {
|
|
154
|
+
const params = new URLSearchParams({ type });
|
|
155
|
+
if (filters?.status)
|
|
156
|
+
params.set("status", filters.status);
|
|
157
|
+
if (filters?.limit)
|
|
158
|
+
params.set("limit", String(filters.limit));
|
|
159
|
+
return this.get(`/api/entities?${params.toString()}`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=api.js.map
|
package/dist/api.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dashboard API — Formats OrgX data for the React dashboard SPA.
|
|
3
|
+
*
|
|
4
|
+
* Transforms the cached OrgSnapshot into the shapes the dashboard components
|
|
5
|
+
* expect, and exposes an onboarding check (is the API key configured?).
|
|
6
|
+
*/
|
|
7
|
+
import type { OrgXConfig, OrgSnapshot } from "./types.js";
|
|
8
|
+
export interface DashboardStatus {
|
|
9
|
+
connected: boolean;
|
|
10
|
+
syncedAt: string | null;
|
|
11
|
+
initiativeCount: number;
|
|
12
|
+
activeAgentCount: number;
|
|
13
|
+
activeTaskCount: number;
|
|
14
|
+
pendingDecisionCount: number;
|
|
15
|
+
}
|
|
16
|
+
export interface DashboardAgent {
|
|
17
|
+
id: string;
|
|
18
|
+
name: string;
|
|
19
|
+
domain: string;
|
|
20
|
+
status: "active" | "idle" | "throttled";
|
|
21
|
+
currentTask: string | null;
|
|
22
|
+
lastActive: string | null;
|
|
23
|
+
}
|
|
24
|
+
export interface DashboardActivityItem {
|
|
25
|
+
id: string;
|
|
26
|
+
type: "task" | "decision" | "agent";
|
|
27
|
+
title: string;
|
|
28
|
+
status: string;
|
|
29
|
+
domain?: string;
|
|
30
|
+
urgency?: string;
|
|
31
|
+
timestamp: string | null;
|
|
32
|
+
}
|
|
33
|
+
export interface DashboardInitiative {
|
|
34
|
+
id: string;
|
|
35
|
+
title: string;
|
|
36
|
+
status: string;
|
|
37
|
+
progress: number | null;
|
|
38
|
+
workstreams: string[];
|
|
39
|
+
}
|
|
40
|
+
export interface OnboardingState {
|
|
41
|
+
hasApiKey: boolean;
|
|
42
|
+
baseUrl: string;
|
|
43
|
+
dashboardEnabled: boolean;
|
|
44
|
+
}
|
|
45
|
+
export declare function formatStatus(snapshot: OrgSnapshot | null): DashboardStatus;
|
|
46
|
+
export declare function formatAgents(snapshot: OrgSnapshot | null): DashboardAgent[];
|
|
47
|
+
export declare function formatActivity(snapshot: OrgSnapshot | null): DashboardActivityItem[];
|
|
48
|
+
export declare function formatInitiatives(snapshot: OrgSnapshot | null): DashboardInitiative[];
|
|
49
|
+
export declare function getOnboardingState(config: OrgXConfig, dashboardEnabled: boolean): OnboardingState;
|
|
50
|
+
//# sourceMappingURL=dashboard-api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard-api.d.ts","sourceRoot":"","sources":["../src/dashboard-api.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAM1D,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,QAAQ,GAAG,MAAM,GAAG,WAAW,CAAC;IACxC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,OAAO,CAAC;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAMD,wBAAgB,YAAY,CAAC,QAAQ,EAAE,WAAW,GAAG,IAAI,GAAG,eAAe,CAqB1E;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,WAAW,GAAG,IAAI,GAAG,cAAc,EAAE,CAW3E;AAED,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,WAAW,GAAG,IAAI,GAC3B,qBAAqB,EAAE,CAkDzB;AAED,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,WAAW,GAAG,IAAI,GAC3B,mBAAmB,EAAE,CAUvB;AAED,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,UAAU,EAClB,gBAAgB,EAAE,OAAO,GACxB,eAAe,CAMjB"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dashboard API — Formats OrgX data for the React dashboard SPA.
|
|
3
|
+
*
|
|
4
|
+
* Transforms the cached OrgSnapshot into the shapes the dashboard components
|
|
5
|
+
* expect, and exposes an onboarding check (is the API key configured?).
|
|
6
|
+
*/
|
|
7
|
+
// =============================================================================
|
|
8
|
+
// Formatting helpers
|
|
9
|
+
// =============================================================================
|
|
10
|
+
export function formatStatus(snapshot) {
|
|
11
|
+
if (!snapshot) {
|
|
12
|
+
return {
|
|
13
|
+
connected: false,
|
|
14
|
+
syncedAt: null,
|
|
15
|
+
initiativeCount: 0,
|
|
16
|
+
activeAgentCount: 0,
|
|
17
|
+
activeTaskCount: 0,
|
|
18
|
+
pendingDecisionCount: 0,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
return {
|
|
22
|
+
connected: true,
|
|
23
|
+
syncedAt: snapshot.syncedAt ?? null,
|
|
24
|
+
initiativeCount: snapshot.initiatives?.length ?? 0,
|
|
25
|
+
activeAgentCount: snapshot.agents?.filter((a) => a.status === "active").length ?? 0,
|
|
26
|
+
activeTaskCount: snapshot.activeTasks?.length ?? 0,
|
|
27
|
+
pendingDecisionCount: snapshot.pendingDecisions?.length ?? 0,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export function formatAgents(snapshot) {
|
|
31
|
+
if (!snapshot?.agents)
|
|
32
|
+
return [];
|
|
33
|
+
return snapshot.agents.map((a) => ({
|
|
34
|
+
id: a.id,
|
|
35
|
+
name: a.name,
|
|
36
|
+
domain: a.domain,
|
|
37
|
+
status: a.status,
|
|
38
|
+
currentTask: a.currentTask ?? null,
|
|
39
|
+
lastActive: a.lastActive ?? null,
|
|
40
|
+
}));
|
|
41
|
+
}
|
|
42
|
+
export function formatActivity(snapshot) {
|
|
43
|
+
if (!snapshot)
|
|
44
|
+
return [];
|
|
45
|
+
const items = [];
|
|
46
|
+
// Active tasks → activity items
|
|
47
|
+
if (snapshot.activeTasks) {
|
|
48
|
+
for (const t of snapshot.activeTasks) {
|
|
49
|
+
items.push({
|
|
50
|
+
id: t.id,
|
|
51
|
+
type: "task",
|
|
52
|
+
title: t.title,
|
|
53
|
+
status: t.status,
|
|
54
|
+
domain: t.domain,
|
|
55
|
+
timestamp: snapshot.syncedAt ?? null,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// Pending decisions → activity items
|
|
60
|
+
if (snapshot.pendingDecisions) {
|
|
61
|
+
for (const d of snapshot.pendingDecisions) {
|
|
62
|
+
items.push({
|
|
63
|
+
id: d.id,
|
|
64
|
+
type: "decision",
|
|
65
|
+
title: d.title,
|
|
66
|
+
status: "pending",
|
|
67
|
+
urgency: d.urgency,
|
|
68
|
+
timestamp: snapshot.syncedAt ?? null,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// Agent state changes → activity items
|
|
73
|
+
if (snapshot.agents) {
|
|
74
|
+
for (const a of snapshot.agents) {
|
|
75
|
+
if (a.status === "active" && a.currentTask) {
|
|
76
|
+
items.push({
|
|
77
|
+
id: a.id,
|
|
78
|
+
type: "agent",
|
|
79
|
+
title: `${a.name} working on: ${a.currentTask}`,
|
|
80
|
+
status: a.status,
|
|
81
|
+
domain: a.domain,
|
|
82
|
+
timestamp: a.lastActive ?? snapshot.syncedAt ?? null,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return items;
|
|
88
|
+
}
|
|
89
|
+
export function formatInitiatives(snapshot) {
|
|
90
|
+
if (!snapshot?.initiatives)
|
|
91
|
+
return [];
|
|
92
|
+
return snapshot.initiatives.map((i) => ({
|
|
93
|
+
id: i.id,
|
|
94
|
+
title: i.title,
|
|
95
|
+
status: i.status,
|
|
96
|
+
progress: i.progress ?? null,
|
|
97
|
+
workstreams: i.workstreams ?? [],
|
|
98
|
+
}));
|
|
99
|
+
}
|
|
100
|
+
export function getOnboardingState(config, dashboardEnabled) {
|
|
101
|
+
return {
|
|
102
|
+
hasApiKey: !!config.apiKey,
|
|
103
|
+
baseUrl: config.baseUrl,
|
|
104
|
+
dashboardEnabled,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=dashboard-api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard-api.js","sourceRoot":"","sources":["../src/dashboard-api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP Handler — Serves the React dashboard SPA and API proxy endpoints.
|
|
3
|
+
*
|
|
4
|
+
* Registered at the `/orgx` prefix. Handles:
|
|
5
|
+
* /orgx/live → dashboard SPA (index.html)
|
|
6
|
+
* /orgx/live/assets/* → static assets (JS, CSS, images)
|
|
7
|
+
* /orgx/api/status → org status summary
|
|
8
|
+
* /orgx/api/agents → agent states
|
|
9
|
+
* /orgx/api/activity → activity feed
|
|
10
|
+
* /orgx/api/initiatives → initiative data
|
|
11
|
+
* /orgx/api/onboarding → onboarding / config state
|
|
12
|
+
*/
|
|
13
|
+
import type { OrgXClient } from "./api.js";
|
|
14
|
+
import type { OrgXConfig, OrgSnapshot } from "./types.js";
|
|
15
|
+
interface PluginRequest {
|
|
16
|
+
method?: string;
|
|
17
|
+
url?: string;
|
|
18
|
+
headers: Record<string, string | string[] | undefined>;
|
|
19
|
+
body?: unknown;
|
|
20
|
+
}
|
|
21
|
+
interface PluginResponse {
|
|
22
|
+
writeHead(status: number, headers?: Record<string, string>): void;
|
|
23
|
+
end(body?: string | Buffer): void;
|
|
24
|
+
write?(chunk: string | Buffer): void;
|
|
25
|
+
}
|
|
26
|
+
export declare function createHttpHandler(config: OrgXConfig, client: OrgXClient, getSnapshot: () => OrgSnapshot | null): (req: PluginRequest, res: PluginResponse) => Promise<boolean>;
|
|
27
|
+
export {};
|
|
28
|
+
//# sourceMappingURL=http-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-handler.d.ts","sourceRoot":"","sources":["../src/http-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAc1D,UAAU,aAAa;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC;IACvD,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,UAAU,cAAc;IACtB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;IAClE,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAClC,KAAK,CAAC,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;CACtC;AA8GD,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,UAAU,EAClB,MAAM,EAAE,UAAU,EAClB,WAAW,EAAE,MAAM,WAAW,GAAG,IAAI,IAOnC,KAAK,aAAa,EAClB,KAAK,cAAc,KAClB,OAAO,CAAC,OAAO,CAAC,CAkIpB"}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP Handler — Serves the React dashboard SPA and API proxy endpoints.
|
|
3
|
+
*
|
|
4
|
+
* Registered at the `/orgx` prefix. Handles:
|
|
5
|
+
* /orgx/live → dashboard SPA (index.html)
|
|
6
|
+
* /orgx/live/assets/* → static assets (JS, CSS, images)
|
|
7
|
+
* /orgx/api/status → org status summary
|
|
8
|
+
* /orgx/api/agents → agent states
|
|
9
|
+
* /orgx/api/activity → activity feed
|
|
10
|
+
* /orgx/api/initiatives → initiative data
|
|
11
|
+
* /orgx/api/onboarding → onboarding / config state
|
|
12
|
+
*/
|
|
13
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
14
|
+
import { join, extname } from "node:path";
|
|
15
|
+
import { fileURLToPath } from "node:url";
|
|
16
|
+
import { formatStatus, formatAgents, formatActivity, formatInitiatives, getOnboardingState, } from "./dashboard-api.js";
|
|
17
|
+
// =============================================================================
|
|
18
|
+
// Content-Type mapping
|
|
19
|
+
// =============================================================================
|
|
20
|
+
const MIME_TYPES = {
|
|
21
|
+
".html": "text/html; charset=utf-8",
|
|
22
|
+
".js": "application/javascript; charset=utf-8",
|
|
23
|
+
".mjs": "application/javascript; charset=utf-8",
|
|
24
|
+
".css": "text/css; charset=utf-8",
|
|
25
|
+
".json": "application/json; charset=utf-8",
|
|
26
|
+
".png": "image/png",
|
|
27
|
+
".jpg": "image/jpeg",
|
|
28
|
+
".jpeg": "image/jpeg",
|
|
29
|
+
".gif": "image/gif",
|
|
30
|
+
".svg": "image/svg+xml",
|
|
31
|
+
".ico": "image/x-icon",
|
|
32
|
+
".woff": "font/woff",
|
|
33
|
+
".woff2": "font/woff2",
|
|
34
|
+
".ttf": "font/ttf",
|
|
35
|
+
".map": "application/json",
|
|
36
|
+
};
|
|
37
|
+
function contentType(filePath) {
|
|
38
|
+
return MIME_TYPES[extname(filePath).toLowerCase()] ?? "application/octet-stream";
|
|
39
|
+
}
|
|
40
|
+
// =============================================================================
|
|
41
|
+
// CORS headers (for local dev)
|
|
42
|
+
// =============================================================================
|
|
43
|
+
const CORS_HEADERS = {
|
|
44
|
+
"Access-Control-Allow-Origin": "*",
|
|
45
|
+
"Access-Control-Allow-Methods": "GET, POST, OPTIONS",
|
|
46
|
+
"Access-Control-Allow-Headers": "Content-Type, Authorization",
|
|
47
|
+
};
|
|
48
|
+
// =============================================================================
|
|
49
|
+
// Resolve the dashboard/dist/ directory relative to this file
|
|
50
|
+
// =============================================================================
|
|
51
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
52
|
+
// src/http-handler.ts → up to plugin root → dashboard/dist
|
|
53
|
+
const DIST_DIR = join(__filename, "..", "..", "dashboard", "dist");
|
|
54
|
+
// =============================================================================
|
|
55
|
+
// Helpers
|
|
56
|
+
// =============================================================================
|
|
57
|
+
function sendJson(res, status, data) {
|
|
58
|
+
const body = JSON.stringify(data);
|
|
59
|
+
res.writeHead(status, {
|
|
60
|
+
"Content-Type": "application/json; charset=utf-8",
|
|
61
|
+
...CORS_HEADERS,
|
|
62
|
+
});
|
|
63
|
+
res.end(body);
|
|
64
|
+
}
|
|
65
|
+
function sendFile(res, filePath, cacheControl) {
|
|
66
|
+
try {
|
|
67
|
+
const content = readFileSync(filePath);
|
|
68
|
+
res.writeHead(200, {
|
|
69
|
+
"Content-Type": contentType(filePath),
|
|
70
|
+
"Cache-Control": cacheControl,
|
|
71
|
+
...CORS_HEADERS,
|
|
72
|
+
});
|
|
73
|
+
res.end(content);
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
send404(res);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
function send404(res) {
|
|
80
|
+
res.writeHead(404, {
|
|
81
|
+
"Content-Type": "text/plain; charset=utf-8",
|
|
82
|
+
...CORS_HEADERS,
|
|
83
|
+
});
|
|
84
|
+
res.end("Not Found");
|
|
85
|
+
}
|
|
86
|
+
function sendIndexHtml(res) {
|
|
87
|
+
const indexPath = join(DIST_DIR, "index.html");
|
|
88
|
+
if (existsSync(indexPath)) {
|
|
89
|
+
sendFile(res, indexPath, "no-cache, no-store, must-revalidate");
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
res.writeHead(503, {
|
|
93
|
+
"Content-Type": "text/html; charset=utf-8",
|
|
94
|
+
...CORS_HEADERS,
|
|
95
|
+
});
|
|
96
|
+
res.end("<html><body><h1>Dashboard not built</h1>" +
|
|
97
|
+
"<p>Run <code>cd dashboard && npm run build</code> to build the SPA.</p>" +
|
|
98
|
+
"</body></html>");
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// =============================================================================
|
|
102
|
+
// Factory
|
|
103
|
+
// =============================================================================
|
|
104
|
+
export function createHttpHandler(config, client, getSnapshot) {
|
|
105
|
+
const dashboardEnabled = config.dashboardEnabled ??
|
|
106
|
+
true;
|
|
107
|
+
return async function handler(req, res) {
|
|
108
|
+
const method = (req.method ?? "GET").toUpperCase();
|
|
109
|
+
const rawUrl = req.url ?? "/";
|
|
110
|
+
// Strip query string for routing
|
|
111
|
+
const url = rawUrl.split("?")[0];
|
|
112
|
+
// Only handle /orgx paths — return false for everything else
|
|
113
|
+
if (!url.startsWith("/orgx")) {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
// Handle CORS preflight
|
|
117
|
+
if (method === "OPTIONS") {
|
|
118
|
+
res.writeHead(204, CORS_HEADERS);
|
|
119
|
+
res.end();
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
// ── API endpoints ──────────────────────────────────────────────────────
|
|
123
|
+
if (url.startsWith("/orgx/api/")) {
|
|
124
|
+
if (method !== "GET") {
|
|
125
|
+
res.writeHead(405, {
|
|
126
|
+
"Content-Type": "text/plain",
|
|
127
|
+
...CORS_HEADERS,
|
|
128
|
+
});
|
|
129
|
+
res.end("Method Not Allowed");
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
const route = url.replace("/orgx/api/", "").replace(/\/+$/, "");
|
|
133
|
+
switch (route) {
|
|
134
|
+
case "status": {
|
|
135
|
+
// Proxy-style: try live fetch, fall back to cache
|
|
136
|
+
let snapshot = getSnapshot();
|
|
137
|
+
if (!snapshot) {
|
|
138
|
+
try {
|
|
139
|
+
snapshot = await client.getOrgSnapshot();
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
// use null snapshot
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
sendJson(res, 200, formatStatus(snapshot));
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
case "agents":
|
|
149
|
+
sendJson(res, 200, formatAgents(getSnapshot()));
|
|
150
|
+
return true;
|
|
151
|
+
case "activity":
|
|
152
|
+
sendJson(res, 200, formatActivity(getSnapshot()));
|
|
153
|
+
return true;
|
|
154
|
+
case "initiatives":
|
|
155
|
+
sendJson(res, 200, formatInitiatives(getSnapshot()));
|
|
156
|
+
return true;
|
|
157
|
+
case "onboarding":
|
|
158
|
+
sendJson(res, 200, getOnboardingState(config, dashboardEnabled));
|
|
159
|
+
return true;
|
|
160
|
+
default:
|
|
161
|
+
sendJson(res, 404, { error: "Unknown API endpoint" });
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
// ── Dashboard SPA + static assets ──────────────────────────────────────
|
|
166
|
+
if (!dashboardEnabled) {
|
|
167
|
+
res.writeHead(404, {
|
|
168
|
+
"Content-Type": "text/plain",
|
|
169
|
+
...CORS_HEADERS,
|
|
170
|
+
});
|
|
171
|
+
res.end("Dashboard is disabled");
|
|
172
|
+
return true;
|
|
173
|
+
}
|
|
174
|
+
// Requests under /orgx/live
|
|
175
|
+
if (url === "/orgx/live" || url.startsWith("/orgx/live/")) {
|
|
176
|
+
const subPath = url.replace(/^\/orgx\/live\/?/, "");
|
|
177
|
+
// Static assets: /orgx/live/assets/* → dashboard/dist/assets/*
|
|
178
|
+
// Hashed filenames get long-lived cache
|
|
179
|
+
if (subPath.startsWith("assets/")) {
|
|
180
|
+
const assetPath = join(DIST_DIR, subPath);
|
|
181
|
+
if (existsSync(assetPath)) {
|
|
182
|
+
sendFile(res, assetPath, "public, max-age=31536000, immutable");
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
send404(res);
|
|
186
|
+
}
|
|
187
|
+
return true;
|
|
188
|
+
}
|
|
189
|
+
// Check for an exact file match (e.g. favicon, manifest)
|
|
190
|
+
if (subPath && !subPath.includes("..")) {
|
|
191
|
+
const filePath = join(DIST_DIR, subPath);
|
|
192
|
+
if (existsSync(filePath)) {
|
|
193
|
+
sendFile(res, filePath, "no-cache");
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
// SPA fallback: serve index.html for all other routes under /orgx/live
|
|
198
|
+
sendIndexHtml(res);
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
// Catch-all for /orgx but not /orgx/live or /orgx/api
|
|
202
|
+
if (url === "/orgx" || url === "/orgx/") {
|
|
203
|
+
// Redirect to dashboard
|
|
204
|
+
res.writeHead(302, {
|
|
205
|
+
Location: "/orgx/live",
|
|
206
|
+
...CORS_HEADERS,
|
|
207
|
+
});
|
|
208
|
+
res.end();
|
|
209
|
+
return true;
|
|
210
|
+
}
|
|
211
|
+
send404(res);
|
|
212
|
+
return true;
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
//# sourceMappingURL=http-handler.js.map
|