@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.
@@ -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
@@ -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":"AAAA;;;;;GAKG;AAkDH,gFAAgF;AAChF,qBAAqB;AACrB,gFAAgF;AAEhF,MAAM,UAAU,YAAY,CAAC,QAA4B;IACvD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO;YACL,SAAS,EAAE,KAAK;YAChB,QAAQ,EAAE,IAAI;YACd,eAAe,EAAE,CAAC;YAClB,gBAAgB,EAAE,CAAC;YACnB,eAAe,EAAE,CAAC;YAClB,oBAAoB,EAAE,CAAC;SACxB,CAAC;IACJ,CAAC;IAED,OAAO;QACL,SAAS,EAAE,IAAI;QACf,QAAQ,EAAE,QAAQ,CAAC,QAAQ,IAAI,IAAI;QACnC,eAAe,EAAE,QAAQ,CAAC,WAAW,EAAE,MAAM,IAAI,CAAC;QAClD,gBAAgB,EACd,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,MAAM,IAAI,CAAC;QACnE,eAAe,EAAE,QAAQ,CAAC,WAAW,EAAE,MAAM,IAAI,CAAC;QAClD,oBAAoB,EAAE,QAAQ,CAAC,gBAAgB,EAAE,MAAM,IAAI,CAAC;KAC7D,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,QAA4B;IACvD,IAAI,CAAC,QAAQ,EAAE,MAAM;QAAE,OAAO,EAAE,CAAC;IAEjC,OAAO,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACjC,EAAE,EAAE,CAAC,CAAC,EAAE;QACR,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,WAAW,EAAE,CAAC,CAAC,WAAW,IAAI,IAAI;QAClC,UAAU,EAAE,CAAC,CAAC,UAAU,IAAI,IAAI;KACjC,CAAC,CAAC,CAAC;AACN,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,QAA4B;IAE5B,IAAI,CAAC,QAAQ;QAAE,OAAO,EAAE,CAAC;IAEzB,MAAM,KAAK,GAA4B,EAAE,CAAC;IAE1C,gCAAgC;IAChC,IAAI,QAAQ,CAAC,WAAW,EAAE,CAAC;QACzB,KAAK,MAAM,CAAC,IAAI,QAAQ,CAAC,WAAW,EAAE,CAAC;YACrC,KAAK,CAAC,IAAI,CAAC;gBACT,EAAE,EAAE,CAAC,CAAC,EAAE;gBACR,IAAI,EAAE,MAAM;gBACZ,KAAK,EAAE,CAAC,CAAC,KAAK;gBACd,MAAM,EAAE,CAAC,CAAC,MAAM;gBAChB,MAAM,EAAE,CAAC,CAAC,MAAM;gBAChB,SAAS,EAAE,QAAQ,CAAC,QAAQ,IAAI,IAAI;aACrC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,qCAAqC;IACrC,IAAI,QAAQ,CAAC,gBAAgB,EAAE,CAAC;QAC9B,KAAK,MAAM,CAAC,IAAI,QAAQ,CAAC,gBAAgB,EAAE,CAAC;YAC1C,KAAK,CAAC,IAAI,CAAC;gBACT,EAAE,EAAE,CAAC,CAAC,EAAE;gBACR,IAAI,EAAE,UAAU;gBAChB,KAAK,EAAE,CAAC,CAAC,KAAK;gBACd,MAAM,EAAE,SAAS;gBACjB,OAAO,EAAE,CAAC,CAAC,OAAO;gBAClB,SAAS,EAAE,QAAQ,CAAC,QAAQ,IAAI,IAAI;aACrC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,uCAAuC;IACvC,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;QACpB,KAAK,MAAM,CAAC,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;YAChC,IAAI,CAAC,CAAC,MAAM,KAAK,QAAQ,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;gBAC3C,KAAK,CAAC,IAAI,CAAC;oBACT,EAAE,EAAE,CAAC,CAAC,EAAE;oBACR,IAAI,EAAE,OAAO;oBACb,KAAK,EAAE,GAAG,CAAC,CAAC,IAAI,gBAAgB,CAAC,CAAC,WAAW,EAAE;oBAC/C,MAAM,EAAE,CAAC,CAAC,MAAM;oBAChB,MAAM,EAAE,CAAC,CAAC,MAAM;oBAChB,SAAS,EAAE,CAAC,CAAC,UAAU,IAAI,QAAQ,CAAC,QAAQ,IAAI,IAAI;iBACrD,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,QAA4B;IAE5B,IAAI,CAAC,QAAQ,EAAE,WAAW;QAAE,OAAO,EAAE,CAAC;IAEtC,OAAO,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACtC,EAAE,EAAE,CAAC,CAAC,EAAE;QACR,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,QAAQ,EAAE,CAAC,CAAC,QAAQ,IAAI,IAAI;QAC5B,WAAW,EAAE,CAAC,CAAC,WAAW,IAAI,EAAE;KACjC,CAAC,CAAC,CAAC;AACN,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,MAAkB,EAClB,gBAAyB;IAEzB,OAAO;QACL,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM;QAC1B,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,gBAAgB;KACjB,CAAC;AACJ,CAAC"}
@@ -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 &amp;&amp; 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