@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,169 @@
1
+ import { chmodSync, existsSync, mkdirSync, readFileSync, } from "node:fs";
2
+ import { getOrgxPluginConfigDir, getOrgxPluginConfigPath } from "./paths.js";
3
+ import { backupCorruptFileSync, writeJsonFileAtomicSync } from "./fs-utils.js";
4
+ const MAX_PINS = 240;
5
+ function storeDir() {
6
+ return getOrgxPluginConfigDir();
7
+ }
8
+ function storeFile() {
9
+ return getOrgxPluginConfigPath("next-up-queue.json");
10
+ }
11
+ function ensureStoreDir() {
12
+ const dir = storeDir();
13
+ mkdirSync(dir, { recursive: true, mode: 0o700 });
14
+ try {
15
+ chmodSync(dir, 0o700);
16
+ }
17
+ catch {
18
+ // best effort
19
+ }
20
+ }
21
+ function parseJson(value) {
22
+ try {
23
+ return JSON.parse(value);
24
+ }
25
+ catch {
26
+ return null;
27
+ }
28
+ }
29
+ function normalizeNullableString(value) {
30
+ if (typeof value !== "string")
31
+ return null;
32
+ const trimmed = value.trim();
33
+ return trimmed.length > 0 ? trimmed : null;
34
+ }
35
+ function normalizeEntry(input) {
36
+ return {
37
+ initiativeId: input.initiativeId.trim(),
38
+ workstreamId: input.workstreamId.trim(),
39
+ preferredTaskId: normalizeNullableString(input.preferredTaskId),
40
+ preferredMilestoneId: normalizeNullableString(input.preferredMilestoneId),
41
+ createdAt: input.createdAt,
42
+ updatedAt: input.updatedAt,
43
+ };
44
+ }
45
+ export function readNextUpQueuePins() {
46
+ const file = storeFile();
47
+ try {
48
+ if (!existsSync(file)) {
49
+ return { version: 1, updatedAt: new Date().toISOString(), pins: [] };
50
+ }
51
+ const raw = readFileSync(file, "utf8");
52
+ const parsed = parseJson(raw);
53
+ if (!parsed || typeof parsed !== "object") {
54
+ backupCorruptFileSync(file);
55
+ return { version: 1, updatedAt: new Date().toISOString(), pins: [] };
56
+ }
57
+ const pins = Array.isArray(parsed.pins) ? parsed.pins : [];
58
+ return {
59
+ version: 1,
60
+ updatedAt: typeof parsed.updatedAt === "string"
61
+ ? parsed.updatedAt
62
+ : new Date().toISOString(),
63
+ pins: pins
64
+ .filter((entry) => Boolean(entry && typeof entry === "object"))
65
+ .map((entry) => normalizeEntry(entry)),
66
+ };
67
+ }
68
+ catch {
69
+ return { version: 1, updatedAt: new Date().toISOString(), pins: [] };
70
+ }
71
+ }
72
+ export function upsertNextUpQueuePin(input) {
73
+ const initiativeId = input.initiativeId.trim();
74
+ const workstreamId = input.workstreamId.trim();
75
+ if (!initiativeId || !workstreamId) {
76
+ return readNextUpQueuePins();
77
+ }
78
+ ensureStoreDir();
79
+ const now = new Date().toISOString();
80
+ const next = readNextUpQueuePins();
81
+ const key = `${initiativeId}:${workstreamId}`;
82
+ const existing = next.pins.find((pin) => `${pin.initiativeId}:${pin.workstreamId}` === key);
83
+ const updated = normalizeEntry({
84
+ initiativeId,
85
+ workstreamId,
86
+ preferredTaskId: input.preferredTaskId ?? existing?.preferredTaskId ?? null,
87
+ preferredMilestoneId: input.preferredMilestoneId ?? existing?.preferredMilestoneId ?? null,
88
+ createdAt: existing?.createdAt ?? now,
89
+ updatedAt: now,
90
+ });
91
+ next.pins = [updated, ...next.pins.filter((pin) => `${pin.initiativeId}:${pin.workstreamId}` !== key)].slice(0, MAX_PINS);
92
+ next.updatedAt = now;
93
+ try {
94
+ writeJsonFileAtomicSync(storeFile(), next, 0o600);
95
+ }
96
+ catch {
97
+ // best effort
98
+ }
99
+ return next;
100
+ }
101
+ export function removeNextUpQueuePin(input) {
102
+ const initiativeId = input.initiativeId.trim();
103
+ const workstreamId = input.workstreamId.trim();
104
+ if (!initiativeId || !workstreamId) {
105
+ return readNextUpQueuePins();
106
+ }
107
+ ensureStoreDir();
108
+ const next = readNextUpQueuePins();
109
+ const key = `${initiativeId}:${workstreamId}`;
110
+ const filtered = next.pins.filter((pin) => `${pin.initiativeId}:${pin.workstreamId}` !== key);
111
+ if (filtered.length === next.pins.length)
112
+ return next;
113
+ next.pins = filtered;
114
+ next.updatedAt = new Date().toISOString();
115
+ try {
116
+ writeJsonFileAtomicSync(storeFile(), next, 0o600);
117
+ }
118
+ catch {
119
+ // best effort
120
+ }
121
+ return next;
122
+ }
123
+ export function setNextUpQueuePinOrder(input) {
124
+ ensureStoreDir();
125
+ const next = readNextUpQueuePins();
126
+ const now = new Date().toISOString();
127
+ const byKey = new Map(next.pins.map((pin) => [`${pin.initiativeId}:${pin.workstreamId}`, pin]));
128
+ const ordered = [];
129
+ const seen = new Set();
130
+ for (const entry of input.order) {
131
+ const initiativeId = (entry.initiativeId ?? "").trim();
132
+ const workstreamId = (entry.workstreamId ?? "").trim();
133
+ if (!initiativeId || !workstreamId)
134
+ continue;
135
+ const key = `${initiativeId}:${workstreamId}`;
136
+ if (seen.has(key))
137
+ continue;
138
+ seen.add(key);
139
+ const pin = byKey.get(key);
140
+ if (pin) {
141
+ ordered.push(pin);
142
+ }
143
+ else {
144
+ ordered.push({
145
+ initiativeId,
146
+ workstreamId,
147
+ preferredTaskId: null,
148
+ preferredMilestoneId: null,
149
+ createdAt: now,
150
+ updatedAt: now,
151
+ });
152
+ }
153
+ }
154
+ for (const pin of next.pins) {
155
+ const key = `${pin.initiativeId}:${pin.workstreamId}`;
156
+ if (seen.has(key))
157
+ continue;
158
+ ordered.push(pin);
159
+ }
160
+ next.pins = ordered.slice(0, MAX_PINS);
161
+ next.updatedAt = now;
162
+ try {
163
+ writeJsonFileAtomicSync(storeFile(), next, 0o600);
164
+ }
165
+ catch {
166
+ // best effort
167
+ }
168
+ return next;
169
+ }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "id": "orgx",
3
3
  "name": "OrgX Integration",
4
- "version": "1.0.1",
4
+ "version": "1.0.2",
5
5
  "description": "Connects Clawdbot to OrgX for agent orchestration, quality gates, and model routing",
6
6
  "entry": "./index.js",
7
7
  "author": "OrgX Team",
package/dist/outbox.d.ts CHANGED
@@ -6,7 +6,7 @@
6
6
  import type { LiveActivityItem } from "./types.js";
7
7
  export interface OutboxEvent {
8
8
  id: string;
9
- type: "progress" | "decision" | "artifact" | "changeset";
9
+ type: "progress" | "decision" | "artifact" | "changeset" | "retro" | "outcome";
10
10
  timestamp: string;
11
11
  payload: Record<string, unknown>;
12
12
  /** Converted to a LiveActivityItem for dashboard display. */
@@ -21,7 +21,7 @@ export type RuntimeInstanceRecord = {
21
21
  id: string;
22
22
  sourceClient: RuntimeSourceClient;
23
23
  displayName: string;
24
- providerLogo: "openai" | "anthropic" | "openclaw" | "orgx" | "unknown";
24
+ providerLogo: "codex" | "openai" | "anthropic" | "openclaw" | "orgx" | "unknown";
25
25
  state: RuntimeInstanceState;
26
26
  event: RuntimeHookEvent;
27
27
  runId: string | null;
@@ -94,6 +94,22 @@ function toProviderLogo(sourceClient) {
94
94
  return "orgx";
95
95
  return "unknown";
96
96
  }
97
+ function normalizeProviderLogo(value, sourceClient) {
98
+ const normalized = normalizeNullableString(value)?.toLowerCase();
99
+ if (normalized === "codex")
100
+ return sourceClient === "codex" ? "openai" : "codex";
101
+ if (normalized === "openai")
102
+ return "openai";
103
+ if (normalized === "anthropic")
104
+ return "anthropic";
105
+ if (normalized === "openclaw")
106
+ return "openclaw";
107
+ if (normalized === "orgx")
108
+ return "orgx";
109
+ if (normalized === "unknown")
110
+ return "unknown";
111
+ return toProviderLogo(sourceClient);
112
+ }
97
113
  function toDisplayName(sourceClient) {
98
114
  if (sourceClient === "codex")
99
115
  return "Codex";
@@ -152,11 +168,12 @@ function normalizeProgress(value) {
152
168
  return Math.max(0, Math.min(100, Math.round(value)));
153
169
  }
154
170
  function normalizeRecord(input) {
171
+ const sourceClient = normalizeSourceClient(input.sourceClient);
155
172
  return {
156
173
  id: normalizeNullableString(input.id) ?? input.id,
157
- sourceClient: normalizeSourceClient(input.sourceClient),
174
+ sourceClient,
158
175
  displayName: normalizeNullableString(input.displayName) ?? "Runtime",
159
- providerLogo: input.providerLogo,
176
+ providerLogo: normalizeProviderLogo(input.providerLogo, sourceClient),
160
177
  state: normalizeState(input.state),
161
178
  event: normalizeHookEvent(input.event),
162
179
  runId: normalizeNullableString(input.runId),
@@ -0,0 +1,69 @@
1
+ import type { SkillPack } from "./contracts/types.js";
2
+ import type { OrgxSkillPackOverrides } from "./agent-suite.js";
3
+ export type SkillPackState = {
4
+ version: 1;
5
+ updatedAt: string;
6
+ lastCheckedAt: string | null;
7
+ lastError: string | null;
8
+ etag: string | null;
9
+ policy: {
10
+ frozen: boolean;
11
+ pinnedChecksum: string | null;
12
+ };
13
+ pack: {
14
+ name: string;
15
+ version: string;
16
+ checksum: string;
17
+ updated_at: string | null;
18
+ } | null;
19
+ remote: {
20
+ name: string;
21
+ version: string;
22
+ checksum: string;
23
+ updated_at: string | null;
24
+ } | null;
25
+ overrides: OrgxSkillPackOverrides | null;
26
+ };
27
+ export declare function readSkillPackState(input?: {
28
+ openclawDir?: string;
29
+ }): SkillPackState;
30
+ export declare function writeSkillPackState(state: SkillPackState, input?: {
31
+ openclawDir?: string;
32
+ }): void;
33
+ export declare function updateSkillPackPolicy(input: {
34
+ openclawDir?: string;
35
+ frozen?: boolean;
36
+ pinnedChecksum?: string | null;
37
+ pinToCurrent?: boolean;
38
+ clearPin?: boolean;
39
+ }): SkillPackState;
40
+ export declare function toOrgxSkillPackOverrides(input: {
41
+ pack: SkillPack;
42
+ etag: string | null;
43
+ }): OrgxSkillPackOverrides;
44
+ export declare function refreshSkillPackState(input: {
45
+ getSkillPack: (args: {
46
+ name?: string;
47
+ ifNoneMatch?: string | null;
48
+ }) => Promise<{
49
+ ok: true;
50
+ notModified: true;
51
+ etag: string | null;
52
+ pack: null;
53
+ } | {
54
+ ok: true;
55
+ notModified: false;
56
+ etag: string | null;
57
+ pack: SkillPack;
58
+ } | {
59
+ ok: false;
60
+ status: number;
61
+ error: string;
62
+ }>;
63
+ packName?: string;
64
+ openclawDir?: string;
65
+ force?: boolean;
66
+ }): Promise<{
67
+ state: SkillPackState;
68
+ changed: boolean;
69
+ }>;
@@ -0,0 +1,232 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { writeFileAtomicSync } from "./fs-utils.js";
4
+ import { getOpenClawDir } from "./paths.js";
5
+ const STORE_VERSION = 1;
6
+ const STATE_FILENAME = "orgx-skill-pack-state.json";
7
+ function nowIso() {
8
+ return new Date().toISOString();
9
+ }
10
+ function isRecord(value) {
11
+ return Boolean(value && typeof value === "object" && !Array.isArray(value));
12
+ }
13
+ function coerceString(value) {
14
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
15
+ }
16
+ function statePath(openclawDir) {
17
+ return join(openclawDir, STATE_FILENAME);
18
+ }
19
+ export function readSkillPackState(input) {
20
+ const openclawDir = input?.openclawDir ?? getOpenClawDir();
21
+ const path = statePath(openclawDir);
22
+ const empty = {
23
+ version: STORE_VERSION,
24
+ updatedAt: nowIso(),
25
+ lastCheckedAt: null,
26
+ lastError: null,
27
+ etag: null,
28
+ policy: { frozen: false, pinnedChecksum: null },
29
+ pack: null,
30
+ remote: null,
31
+ overrides: null,
32
+ };
33
+ try {
34
+ if (!existsSync(path))
35
+ return empty;
36
+ const raw = readFileSync(path, "utf8");
37
+ const parsed = JSON.parse(raw);
38
+ if (!isRecord(parsed))
39
+ return empty;
40
+ if (parsed.version !== STORE_VERSION)
41
+ return empty;
42
+ const policy = isRecord(parsed.policy) ? parsed.policy : null;
43
+ const pack = isRecord(parsed.pack) ? parsed.pack : null;
44
+ const remote = isRecord(parsed.remote) ? parsed.remote : null;
45
+ const overrides = isRecord(parsed.overrides) ? parsed.overrides : null;
46
+ return {
47
+ version: STORE_VERSION,
48
+ updatedAt: coerceString(parsed.updatedAt) ?? nowIso(),
49
+ lastCheckedAt: coerceString(parsed.lastCheckedAt),
50
+ lastError: coerceString(parsed.lastError),
51
+ etag: coerceString(parsed.etag),
52
+ policy: {
53
+ frozen: Boolean(policy?.frozen),
54
+ pinnedChecksum: coerceString(policy?.pinnedChecksum),
55
+ },
56
+ pack: pack
57
+ ? {
58
+ name: coerceString(pack.name) ?? "",
59
+ version: coerceString(pack.version) ?? "",
60
+ checksum: coerceString(pack.checksum) ?? "",
61
+ updated_at: coerceString(pack.updated_at),
62
+ }
63
+ : null,
64
+ remote: remote
65
+ ? {
66
+ name: coerceString(remote.name) ?? "",
67
+ version: coerceString(remote.version) ?? "",
68
+ checksum: coerceString(remote.checksum) ?? "",
69
+ updated_at: coerceString(remote.updated_at),
70
+ }
71
+ : null,
72
+ overrides: overrides
73
+ ? overrides
74
+ : null,
75
+ };
76
+ }
77
+ catch {
78
+ return empty;
79
+ }
80
+ }
81
+ export function writeSkillPackState(state, input) {
82
+ const openclawDir = input?.openclawDir ?? getOpenClawDir();
83
+ const path = statePath(openclawDir);
84
+ writeFileAtomicSync(path, `${JSON.stringify(state, null, 2)}\n`, {
85
+ mode: 0o600,
86
+ encoding: "utf8",
87
+ });
88
+ }
89
+ export function updateSkillPackPolicy(input) {
90
+ const prev = readSkillPackState({ openclawDir: input.openclawDir });
91
+ const nextPolicy = { ...prev.policy };
92
+ if (typeof input.frozen === "boolean") {
93
+ nextPolicy.frozen = input.frozen;
94
+ }
95
+ if (input.clearPin) {
96
+ nextPolicy.pinnedChecksum = null;
97
+ }
98
+ else if (input.pinToCurrent) {
99
+ nextPolicy.pinnedChecksum = prev.pack?.checksum ?? prev.remote?.checksum ?? null;
100
+ }
101
+ else if (typeof input.pinnedChecksum === "string") {
102
+ nextPolicy.pinnedChecksum = input.pinnedChecksum.trim() || null;
103
+ }
104
+ else if (input.pinnedChecksum === null) {
105
+ nextPolicy.pinnedChecksum = null;
106
+ }
107
+ const next = {
108
+ ...prev,
109
+ updatedAt: nowIso(),
110
+ policy: nextPolicy,
111
+ };
112
+ writeSkillPackState(next, { openclawDir: input.openclawDir });
113
+ return next;
114
+ }
115
+ function asRecord(value) {
116
+ return isRecord(value) ? value : null;
117
+ }
118
+ function parseOpenclawSkillOverridesFromManifest(manifest) {
119
+ const root = manifest ?? {};
120
+ const candidates = [
121
+ asRecord(root.openclaw_skills),
122
+ asRecord(root.openclawSkills),
123
+ asRecord(asRecord(root.openclaw)?.skills),
124
+ ].filter(Boolean);
125
+ const out = {};
126
+ for (const candidate of candidates) {
127
+ for (const [k, v] of Object.entries(candidate)) {
128
+ if (typeof v !== "string")
129
+ continue;
130
+ const key = k.trim().toLowerCase();
131
+ if (!key)
132
+ continue;
133
+ out[key] = v;
134
+ }
135
+ }
136
+ return out;
137
+ }
138
+ export function toOrgxSkillPackOverrides(input) {
139
+ const manifest = asRecord(input.pack.manifest) ?? {};
140
+ const rawOverrides = parseOpenclawSkillOverridesFromManifest(manifest);
141
+ const openclaw_skills = {};
142
+ for (const [k, v] of Object.entries(rawOverrides)) {
143
+ // Domains are normalized to lowercase keys in the manifest.
144
+ openclaw_skills[k] = v;
145
+ }
146
+ return {
147
+ source: "server",
148
+ name: input.pack.name,
149
+ version: input.pack.version,
150
+ checksum: input.pack.checksum,
151
+ etag: input.etag,
152
+ updated_at: input.pack.updated_at ?? null,
153
+ openclaw_skills,
154
+ };
155
+ }
156
+ export async function refreshSkillPackState(input) {
157
+ const packName = (input.packName ?? "").trim() || "orgx-agent-suite";
158
+ const prev = readSkillPackState({ openclawDir: input.openclawDir });
159
+ if (!input.force && prev.policy.frozen) {
160
+ const next = {
161
+ ...prev,
162
+ updatedAt: nowIso(),
163
+ lastCheckedAt: nowIso(),
164
+ lastError: null,
165
+ };
166
+ writeSkillPackState(next, { openclawDir: input.openclawDir });
167
+ return { state: next, changed: false };
168
+ }
169
+ const result = await input.getSkillPack({
170
+ name: packName,
171
+ ifNoneMatch: input.force ? null : prev.etag,
172
+ });
173
+ if (result.ok && result.notModified) {
174
+ const next = {
175
+ ...prev,
176
+ updatedAt: nowIso(),
177
+ lastCheckedAt: nowIso(),
178
+ lastError: null,
179
+ etag: result.etag ?? prev.etag,
180
+ };
181
+ writeSkillPackState(next, { openclawDir: input.openclawDir });
182
+ return { state: next, changed: false };
183
+ }
184
+ if (result.ok && !result.notModified && result.pack) {
185
+ const remoteMeta = {
186
+ name: result.pack.name,
187
+ version: result.pack.version,
188
+ checksum: result.pack.checksum,
189
+ updated_at: result.pack.updated_at ?? null,
190
+ };
191
+ if (prev.policy.pinnedChecksum &&
192
+ prev.policy.pinnedChecksum !== result.pack.checksum) {
193
+ const next = {
194
+ ...prev,
195
+ updatedAt: nowIso(),
196
+ lastCheckedAt: nowIso(),
197
+ lastError: null,
198
+ etag: result.etag ?? prev.etag,
199
+ remote: remoteMeta,
200
+ };
201
+ writeSkillPackState(next, { openclawDir: input.openclawDir });
202
+ return { state: next, changed: false };
203
+ }
204
+ const overrides = toOrgxSkillPackOverrides({ pack: result.pack, etag: result.etag ?? null });
205
+ const next = {
206
+ version: STORE_VERSION,
207
+ updatedAt: nowIso(),
208
+ lastCheckedAt: nowIso(),
209
+ lastError: null,
210
+ etag: result.etag ?? null,
211
+ policy: prev.policy,
212
+ pack: {
213
+ name: result.pack.name,
214
+ version: result.pack.version,
215
+ checksum: result.pack.checksum,
216
+ updated_at: result.pack.updated_at ?? null,
217
+ },
218
+ remote: remoteMeta,
219
+ overrides,
220
+ };
221
+ writeSkillPackState(next, { openclawDir: input.openclawDir });
222
+ return { state: next, changed: prev.pack?.checksum !== next.pack?.checksum };
223
+ }
224
+ const next = {
225
+ ...prev,
226
+ updatedAt: nowIso(),
227
+ lastCheckedAt: nowIso(),
228
+ lastError: !result.ok ? result.error : prev.lastError,
229
+ };
230
+ writeSkillPackState(next, { openclawDir: input.openclawDir });
231
+ return { state: next, changed: false };
232
+ }
@@ -0,0 +1,25 @@
1
+ export type WorkerKillDecision = {
2
+ kill: false;
3
+ elapsedMs: number;
4
+ idleMs: number;
5
+ } | {
6
+ kill: true;
7
+ kind: "timeout" | "log_stall";
8
+ reason: string;
9
+ elapsedMs: number;
10
+ idleMs: number;
11
+ };
12
+ export type McpHandshakeFailure = {
13
+ kind: "mcp_handshake";
14
+ server: string | null;
15
+ line: string | null;
16
+ };
17
+ export declare function detectMcpHandshakeFailure(logText: unknown): McpHandshakeFailure | null;
18
+ export declare function shouldKillWorker(input: {
19
+ nowEpochMs: number;
20
+ startedAtEpochMs: number;
21
+ logUpdatedAtEpochMs: number;
22
+ }, limits: {
23
+ timeoutMs: number;
24
+ stallMs: number;
25
+ }): WorkerKillDecision;
@@ -0,0 +1,77 @@
1
+ function pickString(value) {
2
+ if (typeof value !== "string")
3
+ return null;
4
+ const trimmed = value.trim();
5
+ return trimmed.length > 0 ? trimmed : null;
6
+ }
7
+ function parseIgnoredMcpServers(raw) {
8
+ if (typeof raw !== "string")
9
+ return new Set(["codex_apps"]);
10
+ const trimmed = raw.trim();
11
+ if (!trimmed || trimmed.toLowerCase() === "none")
12
+ return new Set();
13
+ return new Set(trimmed
14
+ .split(",")
15
+ .map((entry) => entry.trim().toLowerCase())
16
+ .filter(Boolean));
17
+ }
18
+ export function detectMcpHandshakeFailure(logText) {
19
+ const text = String(logText ?? "");
20
+ const lower = text.toLowerCase();
21
+ const handshakeSignals = [
22
+ "mcp startup failed",
23
+ "handshaking with mcp server failed",
24
+ "initialize response",
25
+ "send message error transport",
26
+ ];
27
+ if (!handshakeSignals.some((needle) => lower.includes(needle))) {
28
+ return null;
29
+ }
30
+ const lines = text
31
+ .split("\n")
32
+ .map((line) => line.trim())
33
+ .filter(Boolean);
34
+ const signalLine = lines.find((line) => /mcp startup failed|handshaking with mcp server failed/i.test(line)) ??
35
+ lines.find((line) => /initialize response|send message error transport/i.test(line)) ??
36
+ null;
37
+ const serverMatch = signalLine?.match(/mcp(?:\s*:\s*)?\s*([a-z0-9_-]+)\s+failed:/i) ??
38
+ signalLine?.match(/mcp client for\s+`?([^`]+)`?\s+failed to start/i) ??
39
+ signalLine?.match(/mcp client for\s+\[?([^\]]+)\]?\s+failed to start/i) ??
40
+ null;
41
+ const server = serverMatch ? pickString(serverMatch[1]) ?? null : null;
42
+ const ignoredServers = parseIgnoredMcpServers(process.env.ORGX_AUTOPILOT_MCP_HANDSHAKE_IGNORE_SERVERS);
43
+ if (server && ignoredServers.has(server.toLowerCase())) {
44
+ return null;
45
+ }
46
+ return {
47
+ kind: "mcp_handshake",
48
+ server,
49
+ line: signalLine,
50
+ };
51
+ }
52
+ export function shouldKillWorker(input, limits) {
53
+ const now = Number(input.nowEpochMs) || Date.now();
54
+ const startedAt = Number(input.startedAtEpochMs) || now;
55
+ const logUpdatedAt = Number(input.logUpdatedAtEpochMs) || startedAt;
56
+ const elapsedMs = Math.max(0, now - startedAt);
57
+ const idleMs = Math.max(0, now - logUpdatedAt);
58
+ if (Number.isFinite(limits.timeoutMs) && limits.timeoutMs > 0 && elapsedMs > limits.timeoutMs) {
59
+ return {
60
+ kill: true,
61
+ kind: "timeout",
62
+ reason: `Worker exceeded timeout (${Math.round(limits.timeoutMs / 1_000)}s)`,
63
+ elapsedMs,
64
+ idleMs,
65
+ };
66
+ }
67
+ if (Number.isFinite(limits.stallMs) && limits.stallMs > 0 && idleMs > limits.stallMs) {
68
+ return {
69
+ kill: true,
70
+ kind: "log_stall",
71
+ reason: `Worker log stalled (${Math.round(limits.stallMs / 1_000)}s)`,
72
+ elapsedMs,
73
+ idleMs,
74
+ };
75
+ }
76
+ return { kill: false, elapsedMs, idleMs };
77
+ }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "id": "orgx",
3
3
  "name": "OrgX Integration",
4
- "version": "1.0.1",
4
+ "version": "1.0.2",
5
5
  "description": "Connects Clawdbot to OrgX for agent orchestration, quality gates, and model routing",
6
6
  "entry": "./dist/index.js",
7
7
  "author": "OrgX Team",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@useorgx/openclaw-plugin",
3
- "version": "0.4.5",
3
+ "version": "0.4.8",
4
4
  "description": "OrgX plugin for OpenClaw — agent orchestration, quality gates, model routing, and live dashboard",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -35,10 +35,24 @@
35
35
  "typecheck": "tsc --noEmit",
36
36
  "test:hooks": "npm run build:core && node --test --test-concurrency=1 tests/*.test.mjs tests/**/*.test.mjs",
37
37
  "job:dispatch": "npm run build:core && node ./scripts/run-codex-dispatch-job.mjs",
38
+ "agents:refresh": "node ./scripts/daily-agents-refresh.mjs",
39
+ "agents:install": "node ./scripts/install-daily-agents-refresh.mjs",
38
40
  "verify:clean-install": "node ./scripts/verify-clean-install.mjs",
41
+ "verify:agent-suite": "npm run build:core && node ./scripts/verify-agent-suite-install.mjs",
39
42
  "verify:billing": "npm run build:core && node ./scripts/verify-billing-scenarios.mjs",
43
+ "verify:autopilot-e2e:local": "npm run build:core && node ./scripts/verify-autopilot-e2e-local.mjs",
44
+ "verify:autopilot-e2e:matrix": "npm run build:core && node ./scripts/verify-autopilot-e2e-matrix.mjs",
45
+ "verify:autopilot-e2e:entities": "npm run build:core && node ./scripts/verify-autopilot-e2e-entities.mjs",
46
+ "verify:autopilot-e2e:entities-matrix": "npm run build:core && node ./scripts/verify-autopilot-e2e-entities-matrix.mjs",
47
+ "verify:iwmt-cascade": "npm run build:core && node ./scripts/verify-iwmt-cascade-e2e.mjs",
48
+ "e2e:auto-continue": "node ./scripts/e2e-auto-continue.mjs",
49
+ "e2e:agent-suite": "npm run build:core && node ./scripts/e2e-agent-suite-kickoff-3x.mjs",
50
+ "demo:record": "node ./scripts/record-demo.mjs",
40
51
  "qa:capture": "node ./scripts/capture-qa-evidence.mjs",
52
+ "ship": "node ./scripts/ship.mjs",
41
53
  "ops:launch-checklist": "node ./scripts/run-launch-checklist.mjs",
54
+ "seo:plan": "node ./scripts/apply-seo-plan-v1.mjs",
55
+ "seo:run": "node ./scripts/seo/run.mjs",
42
56
  "install:dashboard": "npm --prefix dashboard ci",
43
57
  "build:dashboard": "npm run install:dashboard && npm --prefix dashboard run build",
44
58
  "build:core": "rm -rf dist && tsc && node ./scripts/copy-manifest.mjs",