@useorgx/openclaw-plugin 0.4.5 → 0.4.8

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.
Files changed (60) hide show
  1. package/README.md +333 -26
  2. package/dashboard/dist/assets/B3ziCA02.js +8 -0
  3. package/dashboard/dist/assets/BNeJ0kpF.js +1 -0
  4. package/dashboard/dist/assets/BzkiMPmM.js +215 -0
  5. package/dashboard/dist/assets/CUV9IHHi.js +1 -0
  6. package/dashboard/dist/assets/CpJsfbXo.js +9 -0
  7. package/dashboard/dist/assets/Ie7d9Iq2.css +1 -0
  8. package/dashboard/dist/assets/sAhvFnpk.js +4 -0
  9. package/dashboard/dist/index.html +5 -5
  10. package/dist/activity-actor-fields.d.ts +3 -0
  11. package/dist/activity-actor-fields.js +128 -0
  12. package/dist/activity-store.d.ts +28 -0
  13. package/dist/activity-store.js +257 -0
  14. package/dist/agent-context-store.d.ts +19 -0
  15. package/dist/agent-context-store.js +60 -3
  16. package/dist/agent-suite.d.ts +83 -0
  17. package/dist/agent-suite.js +615 -0
  18. package/dist/artifacts/register-artifact.d.ts +47 -0
  19. package/dist/artifacts/register-artifact.js +271 -0
  20. package/dist/auth-store.js +8 -13
  21. package/dist/contracts/client.d.ts +23 -1
  22. package/dist/contracts/client.js +127 -8
  23. package/dist/contracts/types.d.ts +194 -1
  24. package/dist/entity-comment-store.d.ts +29 -0
  25. package/dist/entity-comment-store.js +190 -0
  26. package/dist/hooks/post-reporting-event.mjs +326 -0
  27. package/dist/http-handler.d.ts +7 -1
  28. package/dist/http-handler.js +4500 -534
  29. package/dist/index.js +1078 -68
  30. package/dist/local-openclaw.js +8 -0
  31. package/dist/mcp-client-setup.js +145 -28
  32. package/dist/mcp-http-handler.d.ts +17 -0
  33. package/dist/mcp-http-handler.js +144 -3
  34. package/dist/next-up-queue-store.d.ts +31 -0
  35. package/dist/next-up-queue-store.js +169 -0
  36. package/dist/openclaw.plugin.json +1 -1
  37. package/dist/outbox.d.ts +1 -1
  38. package/dist/runtime-instance-store.d.ts +1 -1
  39. package/dist/runtime-instance-store.js +19 -2
  40. package/dist/skill-pack-state.d.ts +69 -0
  41. package/dist/skill-pack-state.js +232 -0
  42. package/dist/worker-supervisor.d.ts +25 -0
  43. package/dist/worker-supervisor.js +77 -0
  44. package/openclaw.plugin.json +1 -1
  45. package/package.json +15 -1
  46. package/skills/orgx-design-agent/SKILL.md +38 -0
  47. package/skills/orgx-engineering-agent/SKILL.md +55 -0
  48. package/skills/orgx-marketing-agent/SKILL.md +40 -0
  49. package/skills/orgx-operations-agent/SKILL.md +40 -0
  50. package/skills/orgx-orchestrator-agent/SKILL.md +45 -0
  51. package/skills/orgx-product-agent/SKILL.md +39 -0
  52. package/skills/orgx-sales-agent/SKILL.md +40 -0
  53. package/skills/ship/SKILL.md +63 -0
  54. package/dashboard/dist/assets/B68j2crt.js +0 -1
  55. package/dashboard/dist/assets/BZZ-fiJx.js +0 -32
  56. package/dashboard/dist/assets/BoXlCHKa.js +0 -9
  57. package/dashboard/dist/assets/Bq9x_Xyh.css +0 -1
  58. package/dashboard/dist/assets/DBhrRVdp.js +0 -1
  59. package/dashboard/dist/assets/DD1jv1Hd.js +0 -8
  60. package/dashboard/dist/assets/DNjbmawF.js +0 -214
@@ -0,0 +1,128 @@
1
+ function asRecord(value) {
2
+ if (!value || typeof value !== "object" || Array.isArray(value))
3
+ return null;
4
+ return value;
5
+ }
6
+ function nonEmptyString(value) {
7
+ if (typeof value !== "string")
8
+ return null;
9
+ const trimmed = value.trim();
10
+ return trimmed.length > 0 ? trimmed : null;
11
+ }
12
+ function firstString(record, keys) {
13
+ if (!record)
14
+ return null;
15
+ for (const key of keys) {
16
+ const candidate = nonEmptyString(record[key]);
17
+ if (candidate)
18
+ return candidate;
19
+ }
20
+ return null;
21
+ }
22
+ function normalizedMetadata(item) {
23
+ const metadata = asRecord(item.metadata);
24
+ if (!metadata)
25
+ return null;
26
+ const nested = asRecord(metadata.metadata);
27
+ if (!nested)
28
+ return metadata;
29
+ return { ...metadata, ...nested };
30
+ }
31
+ function hasActorValue(id, name) {
32
+ return Boolean((id && id.trim().length > 0) || (name && name.trim().length > 0));
33
+ }
34
+ export function enrichActivityActorFields(item) {
35
+ const metadata = normalizedMetadata(item);
36
+ let requesterAgentId = nonEmptyString(item.requesterAgentId) ??
37
+ firstString(metadata, [
38
+ "requested_by_agent_id",
39
+ "requestedByAgentId",
40
+ "requester_agent_id",
41
+ "requesterAgentId",
42
+ "requester_id",
43
+ "requesterId",
44
+ "runner_agent_id",
45
+ "runnerAgentId",
46
+ "handoff_from_agent_id",
47
+ "handoffFromAgentId",
48
+ "from_agent_id",
49
+ "fromAgentId",
50
+ "source_agent_id",
51
+ "sourceAgentId",
52
+ ]);
53
+ let requesterAgentName = nonEmptyString(item.requesterAgentName) ??
54
+ firstString(metadata, [
55
+ "requested_by_agent_name",
56
+ "requestedByAgentName",
57
+ "requester_agent_name",
58
+ "requesterAgentName",
59
+ "requester_name",
60
+ "requesterName",
61
+ "runner_agent_name",
62
+ "runnerAgentName",
63
+ "handoff_from_agent_name",
64
+ "handoffFromAgentName",
65
+ "from_agent_name",
66
+ "fromAgentName",
67
+ "source_agent_name",
68
+ "sourceAgentName",
69
+ ]);
70
+ const executorAgentId = nonEmptyString(item.executorAgentId) ??
71
+ firstString(metadata, [
72
+ "executed_by_agent_id",
73
+ "executedByAgentId",
74
+ "executor_agent_id",
75
+ "executorAgentId",
76
+ "executor_id",
77
+ "executorId",
78
+ "delegated_to_agent_id",
79
+ "delegatedToAgentId",
80
+ "handoff_to_agent_id",
81
+ "handoffToAgentId",
82
+ "target_agent_id",
83
+ "targetAgentId",
84
+ "agent_id",
85
+ "agentId",
86
+ ]) ??
87
+ nonEmptyString(item.agentId);
88
+ const executorAgentName = nonEmptyString(item.executorAgentName) ??
89
+ firstString(metadata, [
90
+ "executed_by_agent_name",
91
+ "executedByAgentName",
92
+ "executor_agent_name",
93
+ "executorAgentName",
94
+ "executor_name",
95
+ "executorName",
96
+ "delegated_to_agent_name",
97
+ "delegatedToAgentName",
98
+ "handoff_to_agent_name",
99
+ "handoffToAgentName",
100
+ "target_agent_name",
101
+ "targetAgentName",
102
+ "agent_name",
103
+ "agentName",
104
+ ]) ??
105
+ nonEmptyString(item.agentName);
106
+ if (!hasActorValue(requesterAgentId, requesterAgentName) && hasActorValue(executorAgentId, executorAgentName)) {
107
+ requesterAgentId = executorAgentId;
108
+ requesterAgentName = executorAgentName;
109
+ }
110
+ const unchanged = nonEmptyString(item.requesterAgentId) === requesterAgentId &&
111
+ nonEmptyString(item.requesterAgentName) === requesterAgentName &&
112
+ nonEmptyString(item.executorAgentId) === executorAgentId &&
113
+ nonEmptyString(item.executorAgentName) === executorAgentName;
114
+ if (unchanged)
115
+ return item;
116
+ return {
117
+ ...item,
118
+ requesterAgentId: requesterAgentId ?? null,
119
+ requesterAgentName: requesterAgentName ?? null,
120
+ executorAgentId: executorAgentId ?? null,
121
+ executorAgentName: executorAgentName ?? null,
122
+ };
123
+ }
124
+ export function enrichActivityActorFieldsList(items) {
125
+ if (!Array.isArray(items) || items.length === 0)
126
+ return [];
127
+ return items.map((item) => enrichActivityActorFields(item));
128
+ }
@@ -0,0 +1,28 @@
1
+ import type { LiveActivityItem } from "./contracts/types.js";
2
+ export type ActivityPageCursor = {
3
+ beforeEpoch: number;
4
+ beforeId: string;
5
+ };
6
+ export type ListActivityPageParams = {
7
+ limit: number;
8
+ runId?: string | null;
9
+ since?: string | null;
10
+ until?: string | null;
11
+ cursor?: string | null;
12
+ };
13
+ export type ListActivityPageResult = {
14
+ activities: LiveActivityItem[];
15
+ nextCursor: string | null;
16
+ total: number;
17
+ storeUpdatedAt: string;
18
+ };
19
+ export declare function appendActivityItems(items: LiveActivityItem[]): {
20
+ appended: number;
21
+ updated: number;
22
+ total: number;
23
+ };
24
+ export declare function listActivityPage(params: ListActivityPageParams): ListActivityPageResult;
25
+ export declare function getActivityStoreStats(): {
26
+ total: number;
27
+ updatedAt: string;
28
+ };
@@ -0,0 +1,257 @@
1
+ import { chmodSync, existsSync, mkdirSync, readFileSync, } from "node:fs";
2
+ import { Buffer } from "node:buffer";
3
+ import { enrichActivityActorFieldsList } from "./activity-actor-fields.js";
4
+ import { getOrgxPluginConfigDir, getOrgxPluginConfigPath } from "./paths.js";
5
+ import { backupCorruptFileSync, writeJsonFileAtomicSync } from "./fs-utils.js";
6
+ const STORE_VERSION = 1;
7
+ const STORE_FILENAME = "activity-store.json";
8
+ const MAX_ITEMS = 50_000;
9
+ const RETENTION_DAYS = 45;
10
+ const FLUSH_DEBOUNCE_MS = 1_250;
11
+ let cached = null;
12
+ function ensureDir() {
13
+ const dir = getOrgxPluginConfigDir();
14
+ mkdirSync(dir, { recursive: true, mode: 0o700 });
15
+ try {
16
+ chmodSync(dir, 0o700);
17
+ }
18
+ catch {
19
+ // best effort
20
+ }
21
+ }
22
+ function storePath() {
23
+ return getOrgxPluginConfigPath(STORE_FILENAME);
24
+ }
25
+ function parseJson(value) {
26
+ try {
27
+ return JSON.parse(value);
28
+ }
29
+ catch {
30
+ return null;
31
+ }
32
+ }
33
+ function toEpoch(value) {
34
+ if (!value)
35
+ return 0;
36
+ const parsed = Date.parse(value);
37
+ return Number.isFinite(parsed) ? parsed : 0;
38
+ }
39
+ function compareActivity(a, b) {
40
+ const delta = toEpoch(b.timestamp) - toEpoch(a.timestamp);
41
+ if (delta !== 0)
42
+ return delta;
43
+ // Deterministic tie-breaker for cursor paging.
44
+ return String(b.id).localeCompare(String(a.id));
45
+ }
46
+ function normalizeItems(source) {
47
+ const now = Date.now();
48
+ const cutoffEpoch = now - RETENTION_DAYS * 24 * 60 * 60_000;
49
+ const byId = new Map();
50
+ for (const item of source) {
51
+ if (!item || typeof item !== "object")
52
+ continue;
53
+ if (typeof item.id !== "string")
54
+ continue;
55
+ const id = item.id.trim();
56
+ if (!id)
57
+ continue;
58
+ const ts = typeof item.timestamp === "string" ? item.timestamp : null;
59
+ const epoch = toEpoch(ts);
60
+ if (!epoch)
61
+ continue;
62
+ if (epoch < cutoffEpoch)
63
+ continue;
64
+ byId.set(id, item);
65
+ }
66
+ return enrichActivityActorFieldsList(Array.from(byId.values()))
67
+ .sort(compareActivity)
68
+ .slice(0, MAX_ITEMS);
69
+ }
70
+ function readPersistedStore() {
71
+ ensureDir();
72
+ const file = storePath();
73
+ if (!existsSync(file)) {
74
+ return { version: STORE_VERSION, updatedAt: new Date().toISOString(), items: [] };
75
+ }
76
+ try {
77
+ const raw = readFileSync(file, "utf8");
78
+ const parsed = parseJson(raw);
79
+ if (!parsed || parsed.version !== STORE_VERSION || !Array.isArray(parsed.items)) {
80
+ backupCorruptFileSync(file);
81
+ return { version: STORE_VERSION, updatedAt: new Date().toISOString(), items: [] };
82
+ }
83
+ return {
84
+ version: STORE_VERSION,
85
+ updatedAt: typeof parsed.updatedAt === "string" ? parsed.updatedAt : new Date().toISOString(),
86
+ items: normalizeItems(parsed.items),
87
+ };
88
+ }
89
+ catch {
90
+ return { version: STORE_VERSION, updatedAt: new Date().toISOString(), items: [] };
91
+ }
92
+ }
93
+ function ensureCache() {
94
+ if (cached)
95
+ return cached;
96
+ const persisted = readPersistedStore();
97
+ const byId = new Map();
98
+ for (const item of persisted.items) {
99
+ byId.set(item.id, item);
100
+ }
101
+ cached = {
102
+ storeUpdatedAt: persisted.updatedAt,
103
+ items: persisted.items,
104
+ byId,
105
+ dirty: false,
106
+ flushTimer: null,
107
+ };
108
+ return cached;
109
+ }
110
+ function encodeCursor(cursor) {
111
+ const payload = JSON.stringify(cursor);
112
+ return Buffer.from(payload, "utf8")
113
+ .toString("base64")
114
+ .replaceAll("+", "-")
115
+ .replaceAll("/", "_")
116
+ .replaceAll("=", "");
117
+ }
118
+ function decodeCursor(raw) {
119
+ const value = (raw ?? "").trim();
120
+ if (!value)
121
+ return null;
122
+ try {
123
+ const padded = value.replaceAll("-", "+").replaceAll("_", "/") + "===".slice((value.length + 3) % 4);
124
+ const decoded = Buffer.from(padded, "base64").toString("utf8");
125
+ const parsed = JSON.parse(decoded);
126
+ if (!parsed || typeof parsed !== "object")
127
+ return null;
128
+ if (!Number.isFinite(parsed.beforeEpoch))
129
+ return null;
130
+ if (typeof parsed.beforeId !== "string" || !parsed.beforeId.trim())
131
+ return null;
132
+ return { beforeEpoch: parsed.beforeEpoch, beforeId: parsed.beforeId.trim() };
133
+ }
134
+ catch {
135
+ return null;
136
+ }
137
+ }
138
+ function scheduleFlush(state) {
139
+ if (!state.dirty)
140
+ return;
141
+ if (state.flushTimer)
142
+ return;
143
+ state.flushTimer = setTimeout(() => {
144
+ state.flushTimer = null;
145
+ if (!state.dirty)
146
+ return;
147
+ state.dirty = false;
148
+ state.storeUpdatedAt = new Date().toISOString();
149
+ const payload = {
150
+ version: STORE_VERSION,
151
+ updatedAt: state.storeUpdatedAt,
152
+ items: state.items,
153
+ };
154
+ writeJsonFileAtomicSync(storePath(), payload, 0o600);
155
+ }, FLUSH_DEBOUNCE_MS);
156
+ state.flushTimer.unref?.();
157
+ }
158
+ export function appendActivityItems(items) {
159
+ if (!Array.isArray(items) || items.length === 0) {
160
+ const state = ensureCache();
161
+ return { appended: 0, updated: 0, total: state.items.length };
162
+ }
163
+ const state = ensureCache();
164
+ let appended = 0;
165
+ let updated = 0;
166
+ for (const item of items) {
167
+ if (!item || typeof item !== "object")
168
+ continue;
169
+ if (typeof item.id !== "string" || !item.id.trim())
170
+ continue;
171
+ if (typeof item.timestamp !== "string" || !item.timestamp.trim())
172
+ continue;
173
+ if (!Number.isFinite(Date.parse(item.timestamp)))
174
+ continue;
175
+ const id = item.id.trim();
176
+ const existing = state.byId.get(id);
177
+ if (!existing) {
178
+ state.byId.set(id, item);
179
+ appended += 1;
180
+ continue;
181
+ }
182
+ // Replace if any key fields differ; metadata/summary changes are real updates.
183
+ if (existing.timestamp !== item.timestamp ||
184
+ existing.type !== item.type ||
185
+ existing.title !== item.title ||
186
+ existing.description !== item.description ||
187
+ (existing.requesterAgentId ?? null) !== (item.requesterAgentId ?? null) ||
188
+ (existing.requesterAgentName ?? null) !== (item.requesterAgentName ?? null) ||
189
+ (existing.executorAgentId ?? null) !== (item.executorAgentId ?? null) ||
190
+ (existing.executorAgentName ?? null) !== (item.executorAgentName ?? null) ||
191
+ existing.summary !== item.summary ||
192
+ JSON.stringify(existing.metadata ?? null) !== JSON.stringify(item.metadata ?? null)) {
193
+ state.byId.set(id, item);
194
+ updated += 1;
195
+ }
196
+ }
197
+ if (appended === 0 && updated === 0) {
198
+ return { appended: 0, updated: 0, total: state.items.length };
199
+ }
200
+ // Rebuild sorted list from map. This is O(n) but bounded by MAX_ITEMS.
201
+ state.items = normalizeItems(Array.from(state.byId.values()));
202
+ state.byId = new Map(state.items.map((item) => [item.id, item]));
203
+ state.dirty = true;
204
+ scheduleFlush(state);
205
+ return { appended, updated, total: state.items.length };
206
+ }
207
+ export function listActivityPage(params) {
208
+ const state = ensureCache();
209
+ const limit = Math.max(1, Math.min(500, Math.floor(params.limit || 100)));
210
+ const runId = typeof params.runId === "string" && params.runId.trim() ? params.runId.trim() : null;
211
+ const sinceEpoch = params.since ? toEpoch(params.since) : 0;
212
+ const untilEpoch = params.until ? toEpoch(params.until) : 0;
213
+ const cursor = decodeCursor(params.cursor ?? null);
214
+ const filtered = [];
215
+ for (const item of state.items) {
216
+ const epoch = toEpoch(item.timestamp);
217
+ if (!epoch)
218
+ continue;
219
+ if (sinceEpoch && epoch < sinceEpoch)
220
+ continue;
221
+ if (untilEpoch && epoch > untilEpoch)
222
+ continue;
223
+ if (runId) {
224
+ const matchRunId = item.runId ?? item.metadata?.runId ?? null;
225
+ if (matchRunId !== runId)
226
+ continue;
227
+ }
228
+ if (cursor) {
229
+ if (epoch > cursor.beforeEpoch)
230
+ continue;
231
+ if (epoch === cursor.beforeEpoch && String(item.id) >= cursor.beforeId)
232
+ continue;
233
+ }
234
+ filtered.push(item);
235
+ if (filtered.length >= limit)
236
+ break;
237
+ }
238
+ // Determine next cursor by checking if there is at least one more matching item after the last.
239
+ let nextCursor = null;
240
+ if (filtered.length === limit) {
241
+ const last = filtered[filtered.length - 1];
242
+ const beforeEpoch = toEpoch(last.timestamp);
243
+ if (beforeEpoch) {
244
+ nextCursor = encodeCursor({ beforeEpoch, beforeId: String(last.id) });
245
+ }
246
+ }
247
+ return {
248
+ activities: filtered,
249
+ nextCursor,
250
+ total: state.items.length,
251
+ storeUpdatedAt: state.storeUpdatedAt,
252
+ };
253
+ }
254
+ export function getActivityStoreStats() {
255
+ const state = ensureCache();
256
+ return { total: state.items.length, updatedAt: state.storeUpdatedAt };
257
+ }
@@ -6,12 +6,23 @@ export type AgentLaunchContext = {
6
6
  taskId: string | null;
7
7
  updatedAt: string;
8
8
  };
9
+ export type RunLaunchContext = {
10
+ runId: string;
11
+ agentId: string;
12
+ initiativeId: string | null;
13
+ initiativeTitle: string | null;
14
+ workstreamId: string | null;
15
+ taskId: string | null;
16
+ updatedAt: string;
17
+ };
9
18
  type PersistedAgentContexts = {
10
19
  updatedAt: string;
11
20
  agents: Record<string, AgentLaunchContext>;
21
+ runs?: Record<string, RunLaunchContext>;
12
22
  };
13
23
  export declare function readAgentContexts(): PersistedAgentContexts;
14
24
  export declare function getAgentContext(agentId: string): AgentLaunchContext | null;
25
+ export declare function getRunContext(runId: string): RunLaunchContext | null;
15
26
  export declare function upsertAgentContext(input: {
16
27
  agentId: string;
17
28
  initiativeId?: string | null;
@@ -19,5 +30,13 @@ export declare function upsertAgentContext(input: {
19
30
  workstreamId?: string | null;
20
31
  taskId?: string | null;
21
32
  }): PersistedAgentContexts;
33
+ export declare function upsertRunContext(input: {
34
+ runId: string;
35
+ agentId: string;
36
+ initiativeId?: string | null;
37
+ initiativeTitle?: string | null;
38
+ workstreamId?: string | null;
39
+ taskId?: string | null;
40
+ }): PersistedAgentContexts;
22
41
  export declare function clearAgentContexts(): void;
23
42
  export {};
@@ -2,6 +2,7 @@ import { chmodSync, existsSync, mkdirSync, readFileSync, rmSync, } from "node:fs
2
2
  import { getOrgxPluginConfigDir, getOrgxPluginConfigPath } from "./paths.js";
3
3
  import { backupCorruptFileSync, writeJsonFileAtomicSync } from "./fs-utils.js";
4
4
  const MAX_AGENTS = 120;
5
+ const MAX_RUNS = 480;
5
6
  function contextDir() {
6
7
  return getOrgxPluginConfigDir();
7
8
  }
@@ -36,28 +37,41 @@ function normalizeContext(input) {
36
37
  updatedAt: input.updatedAt,
37
38
  };
38
39
  }
40
+ function normalizeRunContext(input) {
41
+ return {
42
+ runId: input.runId.trim(),
43
+ agentId: input.agentId.trim(),
44
+ initiativeId: input.initiativeId ?? null,
45
+ initiativeTitle: input.initiativeTitle ?? null,
46
+ workstreamId: input.workstreamId ?? null,
47
+ taskId: input.taskId ?? null,
48
+ updatedAt: input.updatedAt,
49
+ };
50
+ }
39
51
  export function readAgentContexts() {
40
52
  const file = contextFile();
41
53
  try {
42
54
  if (!existsSync(file)) {
43
- return { updatedAt: new Date().toISOString(), agents: {} };
55
+ return { updatedAt: new Date().toISOString(), agents: {}, runs: {} };
44
56
  }
45
57
  const raw = readFileSync(file, "utf8");
46
58
  const parsed = parseJson(raw);
47
59
  if (!parsed || typeof parsed !== "object") {
48
60
  backupCorruptFileSync(file);
49
- return { updatedAt: new Date().toISOString(), agents: {} };
61
+ return { updatedAt: new Date().toISOString(), agents: {}, runs: {} };
50
62
  }
51
63
  const agents = parsed.agents && typeof parsed.agents === "object" ? parsed.agents : {};
64
+ const runs = parsed.runs && typeof parsed.runs === "object" ? parsed.runs : {};
52
65
  return {
53
66
  updatedAt: typeof parsed.updatedAt === "string"
54
67
  ? parsed.updatedAt
55
68
  : new Date().toISOString(),
56
69
  agents: agents,
70
+ runs: runs,
57
71
  };
58
72
  }
59
73
  catch {
60
- return { updatedAt: new Date().toISOString(), agents: {} };
74
+ return { updatedAt: new Date().toISOString(), agents: {}, runs: {} };
61
75
  }
62
76
  }
63
77
  export function getAgentContext(agentId) {
@@ -68,6 +82,14 @@ export function getAgentContext(agentId) {
68
82
  const ctx = store.agents[id];
69
83
  return ctx ? normalizeContext(ctx) : null;
70
84
  }
85
+ export function getRunContext(runId) {
86
+ const id = runId.trim();
87
+ if (!id)
88
+ return null;
89
+ const store = readAgentContexts();
90
+ const ctx = store.runs?.[id];
91
+ return ctx ? normalizeRunContext(ctx) : null;
92
+ }
71
93
  export function upsertAgentContext(input) {
72
94
  const agentId = input.agentId.trim();
73
95
  if (!agentId) {
@@ -99,6 +121,41 @@ export function upsertAgentContext(input) {
99
121
  writeJsonFileAtomicSync(file, next, 0o600);
100
122
  return next;
101
123
  }
124
+ export function upsertRunContext(input) {
125
+ const runId = input.runId.trim();
126
+ const agentId = input.agentId.trim();
127
+ if (!runId || !agentId) {
128
+ return readAgentContexts();
129
+ }
130
+ ensureContextDir();
131
+ const next = readAgentContexts();
132
+ if (!next.runs || typeof next.runs !== "object") {
133
+ next.runs = {};
134
+ }
135
+ next.runs[runId] = normalizeRunContext({
136
+ runId,
137
+ agentId,
138
+ initiativeId: input.initiativeId ?? null,
139
+ initiativeTitle: input.initiativeTitle ?? null,
140
+ workstreamId: input.workstreamId ?? null,
141
+ taskId: input.taskId ?? null,
142
+ updatedAt: new Date().toISOString(),
143
+ });
144
+ next.updatedAt = new Date().toISOString();
145
+ const values = Object.values(next.runs);
146
+ if (values.length > MAX_RUNS) {
147
+ values.sort((a, b) => Date.parse(b.updatedAt) - Date.parse(a.updatedAt));
148
+ const keep = new Set(values.slice(0, MAX_RUNS).map((c) => c.runId));
149
+ for (const key of Object.keys(next.runs)) {
150
+ if (!keep.has(key)) {
151
+ delete next.runs[key];
152
+ }
153
+ }
154
+ }
155
+ const file = contextFile();
156
+ writeJsonFileAtomicSync(file, next, 0o600);
157
+ return next;
158
+ }
102
159
  export function clearAgentContexts() {
103
160
  const file = contextFile();
104
161
  try {
@@ -0,0 +1,83 @@
1
+ export type OrgxSuiteDomain = "engineering" | "product" | "design" | "marketing" | "sales" | "operations" | "orchestration";
2
+ export type OrgxSuiteAgentSpec = {
3
+ id: string;
4
+ name: string;
5
+ domain: OrgxSuiteDomain;
6
+ };
7
+ export declare const ORGX_AGENT_SUITE_PACK_ID = "orgx-agent-suite";
8
+ export declare const ORGX_AGENT_SUITE_AGENTS: OrgxSuiteAgentSpec[];
9
+ declare const SUITE_FILES: readonly ["AGENTS.md", "TOOLS.md", "IDENTITY.md", "SKILL.md", "SOUL.md", "USER.md", "HEARTBEAT.md"];
10
+ export type OrgxSkillPackOverrides = {
11
+ source: "builtin" | "server";
12
+ name: string;
13
+ version: string;
14
+ checksum: string;
15
+ etag?: string | null;
16
+ updated_at?: string | null;
17
+ openclaw_skills: Partial<Record<OrgxSuiteDomain, string>>;
18
+ };
19
+ export type OrgxAgentSuiteStatus = {
20
+ packId: string;
21
+ packVersion: string;
22
+ openclawConfigPath: string;
23
+ suiteWorkspaceRoot: string;
24
+ skillPack?: {
25
+ source: "builtin" | "server";
26
+ name: string;
27
+ version: string;
28
+ checksum: string;
29
+ etag?: string | null;
30
+ updated_at?: string | null;
31
+ } | null;
32
+ skillPackRemote?: {
33
+ name: string;
34
+ version: string;
35
+ checksum: string;
36
+ updated_at?: string | null;
37
+ } | null;
38
+ skillPackPolicy?: {
39
+ frozen: boolean;
40
+ pinnedChecksum: string | null;
41
+ } | null;
42
+ skillPackUpdateAvailable?: boolean;
43
+ agents: Array<{
44
+ id: string;
45
+ name: string;
46
+ domain: OrgxSuiteDomain;
47
+ workspace: string;
48
+ configuredInOpenclaw: boolean;
49
+ workspaceExists: boolean;
50
+ }>;
51
+ };
52
+ export type OrgxAgentSuitePlan = OrgxAgentSuiteStatus & {
53
+ openclawConfigWouldUpdate: boolean;
54
+ openclawConfigAddedAgents: string[];
55
+ workspaceFiles: Array<{
56
+ agentId: string;
57
+ file: typeof SUITE_FILES[number];
58
+ managedPath: string;
59
+ localPath: string;
60
+ compositePath: string;
61
+ action: "create" | "update" | "noop" | "conflict";
62
+ }>;
63
+ };
64
+ export declare function computeOrgxAgentSuitePlan(input: {
65
+ packVersion: string;
66
+ openclawDir?: string;
67
+ skillPack?: OrgxSkillPackOverrides | null;
68
+ skillPackRemote?: OrgxAgentSuiteStatus["skillPackRemote"] | null;
69
+ skillPackPolicy?: OrgxAgentSuiteStatus["skillPackPolicy"] | null;
70
+ skillPackUpdateAvailable?: boolean;
71
+ }): OrgxAgentSuitePlan;
72
+ export declare function applyOrgxAgentSuitePlan(input: {
73
+ plan: OrgxAgentSuitePlan;
74
+ dryRun?: boolean;
75
+ openclawDir?: string;
76
+ skillPack?: OrgxSkillPackOverrides | null;
77
+ }): {
78
+ ok: true;
79
+ applied: boolean;
80
+ plan: OrgxAgentSuitePlan;
81
+ };
82
+ export declare function generateAgentSuiteOperationId(): string;
83
+ export {};