@useorgx/openclaw-plugin 0.4.6 → 0.4.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. package/README.md +310 -24
  2. package/dashboard/dist/assets/B5NEElEI.css +1 -0
  3. package/dashboard/dist/assets/BhapSNAs.js +215 -0
  4. package/dashboard/dist/assets/iFdvE7lx.js +1 -0
  5. package/dashboard/dist/assets/jRJsmpYM.js +1 -0
  6. package/dashboard/dist/index.html +2 -2
  7. package/dist/activity-actor-fields.d.ts +3 -0
  8. package/dist/activity-actor-fields.js +128 -0
  9. package/dist/activity-store.js +12 -19
  10. package/dist/agent-context-store.js +5 -25
  11. package/dist/agent-run-store.js +5 -25
  12. package/dist/agent-suite.js +1 -8
  13. package/dist/artifacts/register-artifact.d.ts +47 -0
  14. package/dist/artifacts/register-artifact.js +271 -0
  15. package/dist/auth/flows.d.ts +47 -0
  16. package/dist/auth/flows.js +169 -0
  17. package/dist/auth-store.js +14 -39
  18. package/dist/byok-store.js +5 -19
  19. package/dist/cli/orgx.d.ts +66 -0
  20. package/dist/cli/orgx.js +91 -0
  21. package/dist/config/refresh.d.ts +32 -0
  22. package/dist/config/refresh.js +55 -0
  23. package/dist/config/resolution.d.ts +37 -0
  24. package/dist/config/resolution.js +178 -0
  25. package/dist/contracts/client.d.ts +1 -0
  26. package/dist/contracts/client.js +7 -5
  27. package/dist/contracts/shared-types.d.ts +147 -0
  28. package/dist/contracts/shared-types.js +3 -0
  29. package/dist/contracts/types.d.ts +1 -130
  30. package/dist/contracts/types.js +5 -0
  31. package/dist/entities/auto-assignment.d.ts +36 -0
  32. package/dist/entities/auto-assignment.js +115 -0
  33. package/dist/entity-comment-store.js +5 -25
  34. package/dist/hash-utils.d.ts +2 -0
  35. package/dist/hash-utils.js +12 -0
  36. package/dist/http/helpers/activity-headline.d.ts +10 -0
  37. package/dist/http/helpers/activity-headline.js +192 -0
  38. package/dist/http/helpers/artifact-fallback.d.ts +13 -0
  39. package/dist/http/helpers/artifact-fallback.js +148 -0
  40. package/dist/http/helpers/auto-continue-engine.d.ts +298 -0
  41. package/dist/http/helpers/auto-continue-engine.js +1218 -0
  42. package/dist/http/helpers/autopilot-operations.d.ts +157 -0
  43. package/dist/http/helpers/autopilot-operations.js +403 -0
  44. package/dist/http/helpers/autopilot-runtime.d.ts +42 -0
  45. package/dist/http/helpers/autopilot-runtime.js +319 -0
  46. package/dist/http/helpers/autopilot-slice-utils.d.ts +38 -0
  47. package/dist/http/helpers/autopilot-slice-utils.js +476 -0
  48. package/dist/http/helpers/decision-mapper.d.ts +12 -0
  49. package/dist/http/helpers/decision-mapper.js +44 -0
  50. package/dist/http/helpers/dispatch-lifecycle.d.ts +102 -0
  51. package/dist/http/helpers/dispatch-lifecycle.js +604 -0
  52. package/dist/http/helpers/hash-utils.d.ts +1 -0
  53. package/dist/http/helpers/hash-utils.js +1 -0
  54. package/dist/http/helpers/kickoff-context.d.ts +12 -0
  55. package/dist/http/helpers/kickoff-context.js +154 -0
  56. package/dist/http/helpers/mission-control.d.ts +94 -0
  57. package/dist/http/helpers/mission-control.js +894 -0
  58. package/dist/http/helpers/openclaw-cli.d.ts +37 -0
  59. package/dist/http/helpers/openclaw-cli.js +283 -0
  60. package/dist/http/helpers/runtime-sse.d.ts +20 -0
  61. package/dist/http/helpers/runtime-sse.js +110 -0
  62. package/dist/http/helpers/value-utils.d.ts +6 -0
  63. package/dist/http/helpers/value-utils.js +67 -0
  64. package/dist/http/index.d.ts +88 -0
  65. package/dist/http/index.js +2353 -0
  66. package/dist/http/router.d.ts +23 -0
  67. package/dist/http/router.js +23 -0
  68. package/dist/http/routes/agent-control.d.ts +79 -0
  69. package/dist/http/routes/agent-control.js +684 -0
  70. package/dist/http/routes/agent-suite.d.ts +29 -0
  71. package/dist/http/routes/agent-suite.js +198 -0
  72. package/dist/http/routes/agents-catalog.d.ts +40 -0
  73. package/dist/http/routes/agents-catalog.js +83 -0
  74. package/dist/http/routes/billing.d.ts +23 -0
  75. package/dist/http/routes/billing.js +55 -0
  76. package/dist/http/routes/debug.d.ts +14 -0
  77. package/dist/http/routes/debug.js +21 -0
  78. package/dist/http/routes/decision-actions.d.ts +13 -0
  79. package/dist/http/routes/decision-actions.js +66 -0
  80. package/dist/http/routes/delegation.d.ts +19 -0
  81. package/dist/http/routes/delegation.js +32 -0
  82. package/dist/http/routes/entities.d.ts +47 -0
  83. package/dist/http/routes/entities.js +152 -0
  84. package/dist/http/routes/entity-dynamic.d.ts +25 -0
  85. package/dist/http/routes/entity-dynamic.js +191 -0
  86. package/dist/http/routes/health.d.ts +22 -0
  87. package/dist/http/routes/health.js +49 -0
  88. package/dist/http/routes/live-legacy.d.ts +110 -0
  89. package/dist/http/routes/live-legacy.js +598 -0
  90. package/dist/http/routes/live-misc.d.ts +69 -0
  91. package/dist/http/routes/live-misc.js +206 -0
  92. package/dist/http/routes/live-snapshot.d.ts +90 -0
  93. package/dist/http/routes/live-snapshot.js +297 -0
  94. package/dist/http/routes/mission-control-actions.d.ts +83 -0
  95. package/dist/http/routes/mission-control-actions.js +541 -0
  96. package/dist/http/routes/mission-control-read.d.ts +28 -0
  97. package/dist/http/routes/mission-control-read.js +67 -0
  98. package/dist/http/routes/onboarding.d.ts +34 -0
  99. package/dist/http/routes/onboarding.js +101 -0
  100. package/dist/http/routes/run-control.d.ts +24 -0
  101. package/dist/http/routes/run-control.js +86 -0
  102. package/dist/http/routes/runtime-hooks.d.ts +69 -0
  103. package/dist/http/routes/runtime-hooks.js +437 -0
  104. package/dist/http/routes/settings-byok.d.ts +23 -0
  105. package/dist/http/routes/settings-byok.js +163 -0
  106. package/dist/http/routes/summary.d.ts +18 -0
  107. package/dist/http/routes/summary.js +42 -0
  108. package/dist/http/routes/work-artifacts.d.ts +9 -0
  109. package/dist/http/routes/work-artifacts.js +36 -0
  110. package/dist/http/shared-state.d.ts +16 -0
  111. package/dist/http/shared-state.js +1 -0
  112. package/dist/http-handler.d.ts +1 -88
  113. package/dist/http-handler.js +1 -9664
  114. package/dist/index.js +122 -2121
  115. package/dist/json-utils.d.ts +1 -0
  116. package/dist/json-utils.js +8 -0
  117. package/dist/local-openclaw.js +8 -0
  118. package/dist/mcp-client-setup.js +75 -90
  119. package/dist/next-up-queue-store.js +4 -18
  120. package/dist/runtime-instance-store.js +8 -34
  121. package/dist/services/background.d.ts +23 -0
  122. package/dist/services/background.js +23 -0
  123. package/dist/services/instrumentation.d.ts +29 -0
  124. package/dist/services/instrumentation.js +136 -0
  125. package/dist/snapshot-store.js +5 -25
  126. package/dist/stores/json-store.d.ts +11 -0
  127. package/dist/stores/json-store.js +42 -0
  128. package/dist/sync/outbox-replay.d.ts +55 -0
  129. package/dist/sync/outbox-replay.js +514 -0
  130. package/dist/tools/core-tools.d.ts +76 -0
  131. package/dist/tools/core-tools.js +1005 -0
  132. package/dist/worker-supervisor.js +15 -0
  133. package/package.json +6 -1
  134. package/dashboard/dist/assets/0tOC3wSN.js +0 -214
  135. package/dashboard/dist/assets/Bm8QnMJ_.js +0 -1
  136. package/dashboard/dist/assets/CyxZio4Y.js +0 -1
  137. package/dashboard/dist/assets/DaAIOik3.css +0 -1
@@ -0,0 +1,476 @@
1
+ import { chmodSync, existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync, } from "node:fs";
2
+ import { spawnSync } from "node:child_process";
3
+ import { homedir } from "node:os";
4
+ import { dirname, join, sep } from "node:path";
5
+ import { writeFileAtomicSync } from "../../fs-utils.js";
6
+ import { parseJsonSafe } from "../../json-utils.js";
7
+ import { getOrgxPluginConfigDir } from "../../paths.js";
8
+ function ensurePrivateDirForFile(pathname) {
9
+ const dir = dirname(pathname);
10
+ mkdirSync(dir, { recursive: true, mode: 0o700 });
11
+ try {
12
+ chmodSync(dir, 0o700);
13
+ }
14
+ catch {
15
+ // best effort
16
+ }
17
+ }
18
+ function autopilotSliceSchema() {
19
+ // Strict enough to keep outputs predictable, but tolerant of older agents.
20
+ return {
21
+ type: "object",
22
+ additionalProperties: false,
23
+ required: ["status", "summary", "workstream_id"],
24
+ properties: {
25
+ status: {
26
+ type: "string",
27
+ enum: ["completed", "blocked", "needs_decision", "error"],
28
+ },
29
+ summary: { type: "string", minLength: 1 },
30
+ workstream_id: { type: "string", minLength: 1 },
31
+ workstream_title: { type: ["string", "null"] },
32
+ slice_id: { type: ["string", "null"] },
33
+ artifacts: {
34
+ type: ["array", "null"],
35
+ items: {
36
+ type: "object",
37
+ additionalProperties: false,
38
+ required: ["name", "artifact_type"],
39
+ properties: {
40
+ name: { type: "string", minLength: 1 },
41
+ artifact_type: {
42
+ type: "string",
43
+ enum: ["pr", "commit", "document", "config", "report", "design", "other"],
44
+ },
45
+ description: { type: ["string", "null"] },
46
+ url: { type: ["string", "null"] },
47
+ verification_steps: { type: ["array", "null"], items: { type: "string" } },
48
+ milestone_id: { type: ["string", "null"] },
49
+ task_ids: { type: ["array", "null"], items: { type: "string" } },
50
+ },
51
+ },
52
+ },
53
+ decisions_needed: {
54
+ type: ["array", "null"],
55
+ items: {
56
+ type: "object",
57
+ additionalProperties: false,
58
+ required: ["question"],
59
+ properties: {
60
+ question: { type: "string", minLength: 1 },
61
+ summary: { type: ["string", "null"] },
62
+ options: { type: ["array", "null"], items: { type: "string" } },
63
+ urgency: {
64
+ type: ["string", "null"],
65
+ enum: ["low", "medium", "high", "urgent", null],
66
+ },
67
+ blocking: { type: ["boolean", "null"] },
68
+ },
69
+ },
70
+ },
71
+ task_updates: {
72
+ type: ["array", "null"],
73
+ items: {
74
+ type: "object",
75
+ additionalProperties: false,
76
+ required: ["task_id", "status"],
77
+ properties: {
78
+ task_id: { type: "string", minLength: 1 },
79
+ status: { type: "string", minLength: 1 },
80
+ reason: { type: ["string", "null"] },
81
+ },
82
+ },
83
+ },
84
+ milestone_updates: {
85
+ type: ["array", "null"],
86
+ items: {
87
+ type: "object",
88
+ additionalProperties: false,
89
+ required: ["milestone_id", "status"],
90
+ properties: {
91
+ milestone_id: { type: "string", minLength: 1 },
92
+ status: { type: "string", minLength: 1 },
93
+ reason: { type: ["string", "null"] },
94
+ },
95
+ },
96
+ },
97
+ next_actions: { type: ["array", "null"], items: { type: "string" } },
98
+ },
99
+ };
100
+ }
101
+ export function ensureAutopilotSliceSchemaPath(schemaFilename) {
102
+ const file = join(getOrgxPluginConfigDir(), schemaFilename);
103
+ try {
104
+ if (existsSync(file))
105
+ return file;
106
+ ensurePrivateDirForFile(file);
107
+ writeFileAtomicSync(file, JSON.stringify(autopilotSliceSchema(), null, 2), { mode: 0o600 });
108
+ return file;
109
+ }
110
+ catch {
111
+ // Fall back to best-effort write.
112
+ try {
113
+ ensurePrivateDirForFile(file);
114
+ writeFileSync(file, `${JSON.stringify(autopilotSliceSchema(), null, 2)}\n`, {
115
+ encoding: "utf8",
116
+ mode: 0o600,
117
+ });
118
+ }
119
+ catch {
120
+ // ignore
121
+ }
122
+ return file;
123
+ }
124
+ }
125
+ export function parseSliceResult(raw) {
126
+ const trimmed = raw.trim();
127
+ if (!trimmed)
128
+ return null;
129
+ const direct = parseJsonSafe(trimmed);
130
+ if (direct && typeof direct === "object")
131
+ return direct;
132
+ // Tolerant parse: extract the last complete top-level JSON object from mixed logs.
133
+ const extractLastTopLevelObject = (text) => {
134
+ let inString = false;
135
+ let escaped = false;
136
+ let depth = 0;
137
+ let start = -1;
138
+ let lastObject = null;
139
+ for (let i = 0; i < text.length; i += 1) {
140
+ const ch = text[i];
141
+ if (inString) {
142
+ if (escaped) {
143
+ escaped = false;
144
+ continue;
145
+ }
146
+ if (ch === "\\") {
147
+ escaped = true;
148
+ continue;
149
+ }
150
+ if (ch === "\"") {
151
+ inString = false;
152
+ }
153
+ continue;
154
+ }
155
+ if (ch === "\"") {
156
+ inString = true;
157
+ continue;
158
+ }
159
+ if (ch === "{") {
160
+ if (depth === 0)
161
+ start = i;
162
+ depth += 1;
163
+ continue;
164
+ }
165
+ if (ch === "}") {
166
+ if (depth <= 0)
167
+ continue;
168
+ depth -= 1;
169
+ if (depth === 0 && start >= 0) {
170
+ lastObject = text.slice(start, i + 1);
171
+ start = -1;
172
+ }
173
+ }
174
+ }
175
+ return lastObject;
176
+ };
177
+ const candidate = extractLastTopLevelObject(trimmed);
178
+ if (candidate) {
179
+ const parsed = parseJsonSafe(candidate);
180
+ if (parsed && typeof parsed === "object")
181
+ return parsed;
182
+ }
183
+ return null;
184
+ }
185
+ export function readSliceOutputFile(pathname) {
186
+ try {
187
+ if (!existsSync(pathname))
188
+ return null;
189
+ const raw = readFileSync(pathname, "utf8");
190
+ return raw.trim().length > 0 ? raw : null;
191
+ }
192
+ catch {
193
+ return null;
194
+ }
195
+ }
196
+ export function readFileTailSafe(pathname, maxChars = 64_000) {
197
+ try {
198
+ if (!existsSync(pathname))
199
+ return "";
200
+ const raw = readFileSync(pathname, "utf8");
201
+ if (raw.length <= maxChars)
202
+ return raw;
203
+ return raw.slice(raw.length - maxChars);
204
+ }
205
+ catch {
206
+ return "";
207
+ }
208
+ }
209
+ export function fileUpdatedAtEpochMs(pathname, fallbackEpochMs) {
210
+ try {
211
+ const st = statSync(pathname);
212
+ const mtimeMs = st.mtimeMs ?? 0;
213
+ return Number.isFinite(mtimeMs) && mtimeMs > 0 ? mtimeMs : fallbackEpochMs;
214
+ }
215
+ catch {
216
+ return fallbackEpochMs;
217
+ }
218
+ }
219
+ export function normalizeCodexArgs(args) {
220
+ const normalized = Array.isArray(args) ? [...args] : [];
221
+ const first = normalized[0];
222
+ const looksLikeFlag = typeof first === "string" && first.startsWith("-");
223
+ const looksLikeCommand = first === "exec" ||
224
+ first === "e" ||
225
+ first === "review" ||
226
+ first === "resume" ||
227
+ first === "help" ||
228
+ first === "features" ||
229
+ first === "mcp" ||
230
+ first === "mcp-server" ||
231
+ first === "app" ||
232
+ first === "app-server" ||
233
+ first === "debug" ||
234
+ first === "cloud";
235
+ // `codex` without a subcommand expects a TTY; autopilot is headless.
236
+ if (!looksLikeCommand || looksLikeFlag) {
237
+ normalized.unshift("exec");
238
+ }
239
+ if (!normalized.includes("--skip-git-repo-check")) {
240
+ normalized.push("--skip-git-repo-check");
241
+ }
242
+ return normalized;
243
+ }
244
+ function parseCodexVersion(text) {
245
+ const raw = (text ?? "").trim();
246
+ if (!raw)
247
+ return { version: null, raw: null };
248
+ const match = raw.match(/codex-cli\s+(\d+)\.(\d+)\.(\d+)/i);
249
+ if (!match)
250
+ return { version: null, raw };
251
+ return {
252
+ version: [Number(match[1]), Number(match[2]), Number(match[3])],
253
+ raw,
254
+ };
255
+ }
256
+ function compareSemver(a, b) {
257
+ if (a[0] !== b[0])
258
+ return a[0] - b[0];
259
+ if (a[1] !== b[1])
260
+ return a[1] - b[1];
261
+ return a[2] - b[2];
262
+ }
263
+ function probeCodexBin(bin) {
264
+ const trimmed = (bin ?? "").trim();
265
+ if (!trimmed)
266
+ return null;
267
+ try {
268
+ const env = { ...process.env };
269
+ // NVM-installed codex scripts commonly use `#!/usr/bin/env node`. LaunchAgent PATH may not
270
+ // include the corresponding node binary, so prefer the sibling bin dir for resolution.
271
+ if (trimmed.includes(sep)) {
272
+ const binDir = dirname(trimmed);
273
+ env.PATH = env.PATH ? `${binDir}:${env.PATH}` : binDir;
274
+ }
275
+ const result = spawnSync(trimmed, ["--version"], {
276
+ encoding: "utf8",
277
+ stdio: ["ignore", "pipe", "pipe"],
278
+ env,
279
+ });
280
+ const combined = `${result.stdout ?? ""}\n${result.stderr ?? ""}`.trim();
281
+ const parsed = parseCodexVersion(combined || String(result.stdout ?? "").trim());
282
+ return {
283
+ bin: trimmed,
284
+ version: parsed.version,
285
+ versionString: parsed.raw,
286
+ };
287
+ }
288
+ catch {
289
+ return null;
290
+ }
291
+ }
292
+ function listNvmCodexCandidates() {
293
+ try {
294
+ const bases = new Set();
295
+ bases.add(join(homedir(), ".nvm", "versions", "node"));
296
+ if (process.env.HOME && process.env.HOME.trim()) {
297
+ bases.add(join(process.env.HOME.trim(), ".nvm", "versions", "node"));
298
+ }
299
+ for (const base of bases) {
300
+ if (!existsSync(base))
301
+ continue;
302
+ const raw = readdirSync(base);
303
+ const versionNames = raw.filter((name) => /^v\d+\.\d+\.\d+$/.test(name));
304
+ const entries = [];
305
+ for (const name of versionNames) {
306
+ try {
307
+ if (statSync(join(base, name)).isDirectory())
308
+ entries.push(name);
309
+ }
310
+ catch {
311
+ // ignore
312
+ }
313
+ }
314
+ const summary = `base=${base} raw=${raw.length} versions=${versionNames.length} dirs=${entries.length}`;
315
+ if (entries.length === 0)
316
+ return { candidates: [], summary };
317
+ const parsed = entries
318
+ .map((name) => {
319
+ const m = name.match(/^v(\d+)\.(\d+)\.(\d+)$/);
320
+ if (!m)
321
+ return null;
322
+ return {
323
+ name,
324
+ ver: [Number(m[1]), Number(m[2]), Number(m[3])],
325
+ };
326
+ })
327
+ .filter((x) => Boolean(x));
328
+ parsed.sort((a, b) => compareSemver(b.ver, a.ver));
329
+ return {
330
+ candidates: parsed
331
+ .slice(0, 8)
332
+ .map((entry) => join(base, entry.name, "bin", "codex")),
333
+ summary,
334
+ };
335
+ }
336
+ return { candidates: [], summary: null };
337
+ }
338
+ catch {
339
+ return { candidates: [], summary: null };
340
+ }
341
+ }
342
+ export function createCodexBinResolver() {
343
+ let cachedCodexBinInfo = null;
344
+ let cachedCodexProbeSummary = null;
345
+ function resolveCodexBinInfo() {
346
+ if (cachedCodexBinInfo)
347
+ return cachedCodexBinInfo;
348
+ const candidates = [];
349
+ const explicit = (process.env.ORGX_CODEX_BIN ?? "").trim();
350
+ if (explicit)
351
+ candidates.push(explicit);
352
+ const nvmBin = (process.env.NVM_BIN ?? "").trim();
353
+ if (nvmBin)
354
+ candidates.push(join(nvmBin, "codex"));
355
+ // Whatever is on PATH for the gateway process.
356
+ candidates.push("codex");
357
+ // LaunchAgents often miss shell init (nvm), so check common per-user installs.
358
+ const nvmScan = listNvmCodexCandidates();
359
+ candidates.push(...nvmScan.candidates);
360
+ // Homebrew / legacy paths.
361
+ candidates.push("/opt/homebrew/bin/codex");
362
+ candidates.push("/usr/local/bin/codex");
363
+ const seen = new Set();
364
+ const unique = candidates.filter((candidate) => {
365
+ const key = (candidate ?? "").trim();
366
+ if (!key)
367
+ return false;
368
+ if (seen.has(key))
369
+ return false;
370
+ seen.add(key);
371
+ return true;
372
+ });
373
+ const probeSummary = [];
374
+ try {
375
+ const nvmBase = join(homedir(), ".nvm", "versions", "node");
376
+ const nvmExists = existsSync(nvmBase);
377
+ let nvmEntries = "";
378
+ if (nvmExists) {
379
+ try {
380
+ nvmEntries = readdirSync(nvmBase).slice(0, 6).join(",");
381
+ }
382
+ catch {
383
+ nvmEntries = "(readdir_failed)";
384
+ }
385
+ }
386
+ probeSummary.push(`nvm_base=${nvmBase} exists=${nvmExists}${nvmEntries ? ` entries=${nvmEntries}` : ""}`);
387
+ }
388
+ catch {
389
+ // best effort
390
+ }
391
+ probeSummary.push(`nvm_codex_candidates=${nvmScan.candidates.length}${nvmScan.candidates.length > 0 ? ` first=${nvmScan.candidates[0]}` : ""}`);
392
+ if (nvmScan.summary) {
393
+ probeSummary.push(`nvm_scan=${nvmScan.summary}`);
394
+ }
395
+ let best = null;
396
+ for (const candidate of unique) {
397
+ const probed = probeCodexBin(candidate);
398
+ probeSummary.push(`${candidate} => ${probed?.versionString ? probed.versionString.replace(/\s+/g, " ") : "unavailable"}`);
399
+ if (!probed)
400
+ continue;
401
+ if (!best) {
402
+ best = probed;
403
+ continue;
404
+ }
405
+ if (probed.version && !best.version) {
406
+ best = probed;
407
+ continue;
408
+ }
409
+ if (!probed.version || !best.version)
410
+ continue;
411
+ if (compareSemver(probed.version, best.version) > 0)
412
+ best = probed;
413
+ }
414
+ cachedCodexBinInfo = best ?? { bin: explicit || "codex", version: null, versionString: null };
415
+ cachedCodexProbeSummary = probeSummary.slice(0, 14).join(" | ");
416
+ return cachedCodexBinInfo;
417
+ }
418
+ function getCachedCodexProbeSummary() {
419
+ return cachedCodexProbeSummary;
420
+ }
421
+ return {
422
+ resolveCodexBinInfo,
423
+ getCachedCodexProbeSummary,
424
+ };
425
+ }
426
+ export function buildWorkstreamSlicePrompt(input) {
427
+ const milestones = input.milestoneSummaries
428
+ .map((m) => `- ${m.title} (${m.status}) [${m.id}]`)
429
+ .slice(0, 10)
430
+ .join("\n");
431
+ const tasks = input.taskSummaries
432
+ .map((t) => {
433
+ const milestone = t.milestoneId ? ` milestone=${t.milestoneId}` : "";
434
+ return `- ${t.title} (${t.status}) [${t.id}]${milestone}`;
435
+ })
436
+ .slice(0, 18)
437
+ .join("\n");
438
+ return [
439
+ "You are an OrgX execution agent running ONE workstream slice in a background codex session.",
440
+ "",
441
+ `Execution policy: ${input.executionPolicy.domain}`,
442
+ `Required skills: ${input.executionPolicy.requiredSkills.map((s) => (s.startsWith("$") ? s : `$${s}`)).join(", ")}`,
443
+ "",
444
+ `Initiative: ${input.initiativeTitle} [${input.initiativeId}]`,
445
+ `Workstream: ${input.workstreamTitle} [${input.workstreamId}]`,
446
+ `Slice run: ${input.runId}`,
447
+ "",
448
+ "Milestones (context):",
449
+ milestones || "- (none found)",
450
+ "",
451
+ "Candidate tasks (context only; do NOT assume status is updated unless you explicitly request it in output):",
452
+ tasks || "- (none found)",
453
+ "",
454
+ "Reporting:",
455
+ "- Prefer using the MCP tool orgx_report_progress for progress updates (if it is available in your tool list).",
456
+ "- Do NOT hunt for OrgX mutation tools to mark tasks done. Instead, request status changes in your FINAL JSON via task_updates/milestone_updates; the coordinator will apply them.",
457
+ "",
458
+ "What to do:",
459
+ "- Choose a coherent slice of work you can complete end-to-end in this run.",
460
+ "- Execute the work (code/docs/config) and produce verifiable outcomes.",
461
+ "- If blocked, be explicit about what decision/info is required.",
462
+ "",
463
+ "Output requirements:",
464
+ "- Print ONLY a single JSON object as the final output.",
465
+ `- Your JSON MUST conform to this schema file: ${input.schemaPath}`,
466
+ "- Artifacts must be verifiable: include URLs or local paths, plus verification steps.",
467
+ "- If you need a human decision, include it in decisions_needed.",
468
+ "- For every decisions_needed entry, ALWAYS set blocking explicitly (true or false).",
469
+ "- Status/decision consistency is strict:",
470
+ " - If any decision is blocking=true, status MUST be needs_decision or blocked (never completed).",
471
+ " - Only use status=completed when all listed decisions are non-blocking follow-ups.",
472
+ "- If you are confident OrgX statuses should change, include task_updates and/or milestone_updates (with a short reason).",
473
+ " - task_updates.status must be one of: todo, in_progress, done, blocked",
474
+ " - milestone_updates.status must be one of: planned, in_progress, completed, at_risk, cancelled",
475
+ ].join("\n");
476
+ }
@@ -0,0 +1,12 @@
1
+ import type { Entity } from "../../types.js";
2
+ export declare function mapDecisionEntity(entity: Entity): {
3
+ id: string;
4
+ title: string;
5
+ context: string | null;
6
+ status: string;
7
+ agentName: string | null;
8
+ requestedAt: string | null;
9
+ updatedAt: string | null;
10
+ waitingMinutes: number;
11
+ metadata: Record<string, unknown>;
12
+ };
@@ -0,0 +1,44 @@
1
+ import { pickNumber, pickString, toIsoString } from "./value-utils.js";
2
+ export function mapDecisionEntity(entity) {
3
+ const record = entity;
4
+ const requestedAt = toIsoString(pickString(record, [
5
+ "requestedAt",
6
+ "requested_at",
7
+ "createdAt",
8
+ "created_at",
9
+ "updatedAt",
10
+ "updated_at",
11
+ ]));
12
+ const updatedAt = toIsoString(pickString(record, ["updatedAt", "updated_at", "createdAt", "created_at"]));
13
+ const waitingMinutesFromEntity = pickNumber(record, [
14
+ "waitingMinutes",
15
+ "waiting_minutes",
16
+ "ageMinutes",
17
+ "age_minutes",
18
+ ]);
19
+ const waitingMinutes = waitingMinutesFromEntity ??
20
+ (requestedAt
21
+ ? Math.max(0, Math.floor((Date.now() - Date.parse(requestedAt)) / 60_000))
22
+ : 0);
23
+ return {
24
+ id: String(record.id ?? ""),
25
+ title: pickString(record, ["title", "name"]) ?? "Decision",
26
+ context: pickString(record, ["context", "summary", "description", "details"]),
27
+ status: pickString(record, ["status", "decision_status"]) ?? "pending",
28
+ agentName: pickString(record, [
29
+ "agentName",
30
+ "agent_name",
31
+ "requestedBy",
32
+ "requested_by",
33
+ "ownerName",
34
+ "owner_name",
35
+ "assignee",
36
+ "createdBy",
37
+ "created_by",
38
+ ]),
39
+ requestedAt,
40
+ updatedAt,
41
+ waitingMinutes,
42
+ metadata: record,
43
+ };
44
+ }
@@ -0,0 +1,102 @@
1
+ import type { OrgXClient } from "../../api.js";
2
+ type ActivityBucket = "message" | "artifact" | "decision";
3
+ type DispatchLifecycleDeps = {
4
+ client: OrgXClient;
5
+ pluginVersion: string | undefined;
6
+ randomUUID: () => string;
7
+ safeErrorMessage: (err: unknown) => string;
8
+ stableHash: (value: string) => string;
9
+ idempotencyKey: (parts: Array<string | null | undefined>) => string;
10
+ pickString: (record: Record<string, unknown>, keys: string[]) => string | null;
11
+ deriveStructuredActivityBucket: (input: {
12
+ phase: "intent" | "execution" | "blocked" | "review" | "handoff" | "completed";
13
+ metadata?: Record<string, unknown>;
14
+ explicitBucket?: ActivityBucket | null;
15
+ }) => ActivityBucket;
16
+ };
17
+ export declare function createDispatchLifecycle(deps: DispatchLifecycleDeps): {
18
+ withProvenanceMetadata: (metadata?: Record<string, unknown>) => Record<string, unknown> | undefined;
19
+ emitActivitySafe: (input: {
20
+ initiativeId: string | null;
21
+ runId?: string | null;
22
+ correlationId?: string | null;
23
+ phase: "intent" | "execution" | "blocked" | "review" | "handoff" | "completed";
24
+ message: string;
25
+ level?: "info" | "warn" | "error";
26
+ progressPct?: number;
27
+ nextStep?: string;
28
+ activityBucket?: ActivityBucket | null;
29
+ metadata?: Record<string, unknown>;
30
+ }) => Promise<void>;
31
+ requestDecisionSafe: (input: {
32
+ initiativeId: string | null;
33
+ correlationId?: string | null;
34
+ title: string;
35
+ summary?: string | null;
36
+ urgency?: "low" | "medium" | "high" | "urgent";
37
+ options?: string[];
38
+ blocking?: boolean;
39
+ }) => Promise<void>;
40
+ checkSpawnGuardSafe: (input: {
41
+ domain: string;
42
+ taskId?: string | null;
43
+ initiativeId: string | null;
44
+ correlationId: string;
45
+ runId?: string | null;
46
+ targetLabel?: string | null;
47
+ }) => Promise<unknown | null>;
48
+ extractSpawnGuardModelTier: (result: unknown) => string | null;
49
+ buildPolicyEnforcedMessage: (input: {
50
+ baseMessage: string;
51
+ executionPolicy: {
52
+ domain: string;
53
+ requiredSkills: string[];
54
+ };
55
+ spawnGuardResult?: unknown | null;
56
+ }) => string;
57
+ resolveDispatchExecutionPolicy: (input: {
58
+ initiativeId: string | null;
59
+ initiativeTitle?: string | null;
60
+ workstreamId?: string | null;
61
+ workstreamTitle?: string | null;
62
+ taskId?: string | null;
63
+ taskTitle?: string | null;
64
+ message?: string | null;
65
+ }) => Promise<{
66
+ executionPolicy: {
67
+ domain: string;
68
+ requiredSkills: string[];
69
+ };
70
+ taskTitle: string | null;
71
+ workstreamTitle: string | null;
72
+ }>;
73
+ enforceSpawnGuardForDispatch: (input: {
74
+ sourceEventPrefix: string;
75
+ initiativeId: string | null;
76
+ correlationId: string;
77
+ runId?: string | null;
78
+ executionPolicy: {
79
+ domain: string;
80
+ requiredSkills: string[];
81
+ };
82
+ agentId?: string | null;
83
+ taskId?: string | null;
84
+ taskTitle?: string | null;
85
+ workstreamId?: string | null;
86
+ workstreamTitle?: string | null;
87
+ milestoneId?: string | null;
88
+ }) => Promise<{
89
+ allowed: boolean;
90
+ retryable: boolean;
91
+ blockedReason: string | null;
92
+ spawnGuardResult: unknown | null;
93
+ }>;
94
+ syncParentRollupsForTask: (input: {
95
+ initiativeId: string | null;
96
+ taskId: string | null;
97
+ workstreamId?: string | null;
98
+ milestoneId?: string | null;
99
+ correlationId?: string | null;
100
+ }) => Promise<void>;
101
+ };
102
+ export {};