@useorgx/openclaw-plugin 0.4.8 → 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 (125) hide show
  1. package/dashboard/dist/assets/B5NEElEI.css +1 -0
  2. package/dashboard/dist/assets/BhapSNAs.js +215 -0
  3. package/dashboard/dist/assets/{BNeJ0kpF.js → iFdvE7lx.js} +1 -1
  4. package/dashboard/dist/assets/{CUV9IHHi.js → jRJsmpYM.js} +1 -1
  5. package/dashboard/dist/index.html +2 -2
  6. package/dist/activity-store.js +4 -18
  7. package/dist/agent-context-store.js +5 -25
  8. package/dist/agent-run-store.js +5 -25
  9. package/dist/agent-suite.js +1 -8
  10. package/dist/auth/flows.d.ts +47 -0
  11. package/dist/auth/flows.js +169 -0
  12. package/dist/auth-store.js +6 -26
  13. package/dist/byok-store.js +5 -19
  14. package/dist/cli/orgx.d.ts +66 -0
  15. package/dist/cli/orgx.js +91 -0
  16. package/dist/config/refresh.d.ts +32 -0
  17. package/dist/config/refresh.js +55 -0
  18. package/dist/config/resolution.d.ts +37 -0
  19. package/dist/config/resolution.js +178 -0
  20. package/dist/contracts/shared-types.d.ts +147 -0
  21. package/dist/contracts/shared-types.js +3 -0
  22. package/dist/contracts/types.d.ts +1 -134
  23. package/dist/contracts/types.js +5 -0
  24. package/dist/entities/auto-assignment.d.ts +36 -0
  25. package/dist/entities/auto-assignment.js +115 -0
  26. package/dist/entity-comment-store.js +5 -25
  27. package/dist/hash-utils.d.ts +2 -0
  28. package/dist/hash-utils.js +12 -0
  29. package/dist/http/helpers/activity-headline.d.ts +10 -0
  30. package/dist/http/helpers/activity-headline.js +192 -0
  31. package/dist/http/helpers/artifact-fallback.d.ts +13 -0
  32. package/dist/http/helpers/artifact-fallback.js +148 -0
  33. package/dist/http/helpers/auto-continue-engine.d.ts +298 -0
  34. package/dist/http/helpers/auto-continue-engine.js +1218 -0
  35. package/dist/http/helpers/autopilot-operations.d.ts +157 -0
  36. package/dist/http/helpers/autopilot-operations.js +403 -0
  37. package/dist/http/helpers/autopilot-runtime.d.ts +42 -0
  38. package/dist/http/helpers/autopilot-runtime.js +319 -0
  39. package/dist/http/helpers/autopilot-slice-utils.d.ts +38 -0
  40. package/dist/http/helpers/autopilot-slice-utils.js +476 -0
  41. package/dist/http/helpers/decision-mapper.d.ts +12 -0
  42. package/dist/http/helpers/decision-mapper.js +44 -0
  43. package/dist/http/helpers/dispatch-lifecycle.d.ts +102 -0
  44. package/dist/http/helpers/dispatch-lifecycle.js +604 -0
  45. package/dist/http/helpers/hash-utils.d.ts +1 -0
  46. package/dist/http/helpers/hash-utils.js +1 -0
  47. package/dist/http/helpers/kickoff-context.d.ts +12 -0
  48. package/dist/http/helpers/kickoff-context.js +154 -0
  49. package/dist/http/helpers/mission-control.d.ts +94 -0
  50. package/dist/http/helpers/mission-control.js +894 -0
  51. package/dist/http/helpers/openclaw-cli.d.ts +37 -0
  52. package/dist/http/helpers/openclaw-cli.js +283 -0
  53. package/dist/http/helpers/runtime-sse.d.ts +20 -0
  54. package/dist/http/helpers/runtime-sse.js +110 -0
  55. package/dist/http/helpers/value-utils.d.ts +6 -0
  56. package/dist/http/helpers/value-utils.js +67 -0
  57. package/dist/http/index.d.ts +88 -0
  58. package/dist/http/index.js +2353 -0
  59. package/dist/http/router.d.ts +23 -0
  60. package/dist/http/router.js +23 -0
  61. package/dist/http/routes/agent-control.d.ts +79 -0
  62. package/dist/http/routes/agent-control.js +684 -0
  63. package/dist/http/routes/agent-suite.d.ts +29 -0
  64. package/dist/http/routes/agent-suite.js +198 -0
  65. package/dist/http/routes/agents-catalog.d.ts +40 -0
  66. package/dist/http/routes/agents-catalog.js +83 -0
  67. package/dist/http/routes/billing.d.ts +23 -0
  68. package/dist/http/routes/billing.js +55 -0
  69. package/dist/http/routes/debug.d.ts +14 -0
  70. package/dist/http/routes/debug.js +21 -0
  71. package/dist/http/routes/decision-actions.d.ts +13 -0
  72. package/dist/http/routes/decision-actions.js +66 -0
  73. package/dist/http/routes/delegation.d.ts +19 -0
  74. package/dist/http/routes/delegation.js +32 -0
  75. package/dist/http/routes/entities.d.ts +47 -0
  76. package/dist/http/routes/entities.js +152 -0
  77. package/dist/http/routes/entity-dynamic.d.ts +25 -0
  78. package/dist/http/routes/entity-dynamic.js +191 -0
  79. package/dist/http/routes/health.d.ts +22 -0
  80. package/dist/http/routes/health.js +49 -0
  81. package/dist/http/routes/live-legacy.d.ts +110 -0
  82. package/dist/http/routes/live-legacy.js +598 -0
  83. package/dist/http/routes/live-misc.d.ts +69 -0
  84. package/dist/http/routes/live-misc.js +206 -0
  85. package/dist/http/routes/live-snapshot.d.ts +90 -0
  86. package/dist/http/routes/live-snapshot.js +297 -0
  87. package/dist/http/routes/mission-control-actions.d.ts +83 -0
  88. package/dist/http/routes/mission-control-actions.js +541 -0
  89. package/dist/http/routes/mission-control-read.d.ts +28 -0
  90. package/dist/http/routes/mission-control-read.js +67 -0
  91. package/dist/http/routes/onboarding.d.ts +34 -0
  92. package/dist/http/routes/onboarding.js +101 -0
  93. package/dist/http/routes/run-control.d.ts +24 -0
  94. package/dist/http/routes/run-control.js +86 -0
  95. package/dist/http/routes/runtime-hooks.d.ts +69 -0
  96. package/dist/http/routes/runtime-hooks.js +437 -0
  97. package/dist/http/routes/settings-byok.d.ts +23 -0
  98. package/dist/http/routes/settings-byok.js +163 -0
  99. package/dist/http/routes/summary.d.ts +18 -0
  100. package/dist/http/routes/summary.js +42 -0
  101. package/dist/http/routes/work-artifacts.d.ts +9 -0
  102. package/dist/http/routes/work-artifacts.js +36 -0
  103. package/dist/http/shared-state.d.ts +16 -0
  104. package/dist/http/shared-state.js +1 -0
  105. package/dist/http-handler.d.ts +1 -88
  106. package/dist/http-handler.js +1 -10605
  107. package/dist/index.js +108 -2243
  108. package/dist/json-utils.d.ts +1 -0
  109. package/dist/json-utils.js +8 -0
  110. package/dist/next-up-queue-store.js +4 -18
  111. package/dist/runtime-instance-store.js +5 -31
  112. package/dist/services/background.d.ts +23 -0
  113. package/dist/services/background.js +23 -0
  114. package/dist/services/instrumentation.d.ts +29 -0
  115. package/dist/services/instrumentation.js +136 -0
  116. package/dist/snapshot-store.js +5 -25
  117. package/dist/stores/json-store.d.ts +11 -0
  118. package/dist/stores/json-store.js +42 -0
  119. package/dist/sync/outbox-replay.d.ts +55 -0
  120. package/dist/sync/outbox-replay.js +514 -0
  121. package/dist/tools/core-tools.d.ts +76 -0
  122. package/dist/tools/core-tools.js +1005 -0
  123. package/package.json +1 -1
  124. package/dashboard/dist/assets/BzkiMPmM.js +0 -215
  125. package/dashboard/dist/assets/Ie7d9Iq2.css +0 -1
@@ -0,0 +1,157 @@
1
+ import type { OrgXClient } from "../../api.js";
2
+ import type { upsertAgentRun as upsertAgentRunType } from "../../agent-run-store.js";
3
+ type AutopilotSliceArtifact = {
4
+ name: string;
5
+ artifact_type?: string | null;
6
+ description?: string | null;
7
+ url?: string | null;
8
+ verification_steps?: string[] | null;
9
+ milestone_id?: string | null;
10
+ task_ids?: string[] | null;
11
+ };
12
+ type CreateAutopilotOperationsDeps = {
13
+ client: OrgXClient;
14
+ randomUUID: () => string;
15
+ safeErrorMessage: (err: unknown) => string;
16
+ idempotencyKey: (parts: Array<string | null | undefined>) => string;
17
+ resolveDispatchExecutionPolicy: (input: {
18
+ initiativeId: string | null;
19
+ initiativeTitle?: string | null;
20
+ workstreamId?: string | null;
21
+ workstreamTitle?: string | null;
22
+ taskId?: string | null;
23
+ taskTitle?: string | null;
24
+ message?: string | null;
25
+ }) => Promise<{
26
+ executionPolicy: {
27
+ domain: string;
28
+ requiredSkills: string[];
29
+ };
30
+ taskTitle: string | null;
31
+ workstreamTitle: string | null;
32
+ }>;
33
+ enforceSpawnGuardForDispatch: (input: {
34
+ sourceEventPrefix: string;
35
+ initiativeId: string | null;
36
+ correlationId: string;
37
+ runId?: string | null;
38
+ executionPolicy: {
39
+ domain: string;
40
+ requiredSkills: string[];
41
+ };
42
+ agentId?: string | null;
43
+ taskId?: string | null;
44
+ taskTitle?: string | null;
45
+ workstreamId?: string | null;
46
+ workstreamTitle?: string | null;
47
+ milestoneId?: string | null;
48
+ }) => Promise<{
49
+ allowed: boolean;
50
+ retryable: boolean;
51
+ blockedReason: string | null;
52
+ spawnGuardResult: unknown | null;
53
+ }>;
54
+ buildPolicyEnforcedMessage: (input: {
55
+ baseMessage: string;
56
+ executionPolicy: {
57
+ domain: string;
58
+ requiredSkills: string[];
59
+ };
60
+ spawnGuardResult?: unknown | null;
61
+ }) => string;
62
+ syncParentRollupsForTask: (input: {
63
+ initiativeId: string | null;
64
+ taskId: string | null;
65
+ workstreamId?: string | null;
66
+ milestoneId?: string | null;
67
+ correlationId?: string | null;
68
+ }) => Promise<void>;
69
+ emitActivitySafe: (input: {
70
+ initiativeId: string | null;
71
+ runId?: string | null;
72
+ correlationId?: string | null;
73
+ phase: "intent" | "execution" | "blocked" | "review" | "handoff" | "completed";
74
+ message: string;
75
+ level?: "info" | "warn" | "error";
76
+ progressPct?: number;
77
+ nextStep?: string;
78
+ metadata?: Record<string, unknown>;
79
+ }) => Promise<void>;
80
+ extractSpawnGuardModelTier: (result: unknown) => string | null;
81
+ upsertAgentContext: (input: {
82
+ agentId: string;
83
+ initiativeId: string | null;
84
+ initiativeTitle?: string | null;
85
+ workstreamId?: string | null;
86
+ taskId?: string | null;
87
+ }) => unknown;
88
+ upsertRunContext: (input: {
89
+ runId: string;
90
+ agentId: string;
91
+ initiativeId: string | null;
92
+ initiativeTitle?: string | null;
93
+ workstreamId?: string | null;
94
+ taskId?: string | null;
95
+ }) => unknown;
96
+ spawnAgentTurn: (input: {
97
+ agentId: string;
98
+ sessionId: string;
99
+ message: string;
100
+ }) => {
101
+ pid: number | null;
102
+ };
103
+ upsertAgentRun: typeof upsertAgentRunType;
104
+ };
105
+ export declare function createAutopilotOperations(deps: CreateAutopilotOperationsDeps): {
106
+ registerArtifactSafe: (input: {
107
+ initiativeId: string;
108
+ runId: string;
109
+ agentId: string;
110
+ agentName?: string | null;
111
+ workstreamId: string;
112
+ artifact: AutopilotSliceArtifact;
113
+ }) => Promise<{
114
+ ok: boolean;
115
+ id: string | null;
116
+ }>;
117
+ applyAgentStatusUpdatesSafe: (input: {
118
+ initiativeId: string;
119
+ runId: string;
120
+ correlationId: string;
121
+ taskUpdates: Array<{
122
+ task_id: string;
123
+ status: string;
124
+ reason?: string | null;
125
+ }>;
126
+ milestoneUpdates: Array<{
127
+ milestone_id: string;
128
+ status: string;
129
+ reason?: string | null;
130
+ }>;
131
+ }) => Promise<{
132
+ applied: number;
133
+ buffered: boolean;
134
+ }>;
135
+ resolveAgentDisplayName: (agentId: string, fallbackName?: string | null) => Promise<string | null>;
136
+ dispatchFallbackWorkstreamTurn: (input: {
137
+ initiativeId: string;
138
+ initiativeTitle: string;
139
+ workstreamId: string;
140
+ workstreamTitle: string;
141
+ agentId: string;
142
+ agentName?: string | null;
143
+ taskId?: string | null;
144
+ taskTitle?: string | null;
145
+ }) => Promise<{
146
+ sessionId: string | null;
147
+ pid: number | null;
148
+ blockedReason: string | null;
149
+ retryable: boolean;
150
+ executionPolicy: {
151
+ domain: string;
152
+ requiredSkills: string[];
153
+ };
154
+ spawnGuardResult: unknown | null;
155
+ }>;
156
+ };
157
+ export {};
@@ -0,0 +1,403 @@
1
+ import { appendToOutbox } from "../../outbox.js";
2
+ import { registerArtifact } from "../../artifacts/register-artifact.js";
3
+ export function createAutopilotOperations(deps) {
4
+ async function registerArtifactSafe(input) {
5
+ const now = new Date().toISOString();
6
+ const name = (input.artifact.name ?? "").trim();
7
+ if (!name)
8
+ return { ok: false, id: null };
9
+ const artifactType = (input.artifact.artifact_type ?? "other").trim() || "other";
10
+ const artifactId = deps.randomUUID();
11
+ const verificationSteps = Array.isArray(input.artifact.verification_steps)
12
+ ? input.artifact.verification_steps
13
+ .filter((step) => typeof step === "string")
14
+ .map((step) => step.trim())
15
+ .filter(Boolean)
16
+ : [];
17
+ const descriptionParts = [];
18
+ if (typeof input.artifact.description === "string" && input.artifact.description.trim()) {
19
+ descriptionParts.push(input.artifact.description.trim());
20
+ }
21
+ if (verificationSteps.length > 0) {
22
+ descriptionParts.push(`Verification:\n${verificationSteps.map((step) => `- ${step}`).join("\n")}`);
23
+ }
24
+ const description = descriptionParts.length > 0 ? descriptionParts.join("\n\n") : undefined;
25
+ const hasUuidAgent = typeof input.agentId === "string" &&
26
+ /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(input.agentId);
27
+ const createdByType = hasUuidAgent ? "agent" : "human";
28
+ const createdById = hasUuidAgent ? input.agentId : null;
29
+ try {
30
+ const entityType = input.artifact.milestone_id ? "milestone" : "initiative";
31
+ const entityId = input.artifact.milestone_id ? input.artifact.milestone_id : input.initiativeId;
32
+ const result = await registerArtifact(deps.client, deps.client.getBaseUrl(), {
33
+ artifact_id: artifactId,
34
+ entity_type: entityType,
35
+ entity_id: entityId,
36
+ name,
37
+ artifact_type: artifactType,
38
+ created_by_type: createdByType,
39
+ created_by_id: createdById,
40
+ description,
41
+ external_url: input.artifact.url ?? null,
42
+ preview_markdown: null,
43
+ status: "draft",
44
+ metadata: {
45
+ source: "autopilot_slice",
46
+ artifact_id: artifactId,
47
+ run_id: input.runId,
48
+ initiative_id: input.initiativeId,
49
+ workstream_id: input.workstreamId,
50
+ milestone_id: input.artifact.milestone_id ?? null,
51
+ task_ids: input.artifact.task_ids ?? null,
52
+ },
53
+ // Make persistence validation opt-in to avoid adding latency to every slice by default.
54
+ validate_persistence: process.env.ORGX_VALIDATE_ARTIFACT_PERSISTENCE === "1",
55
+ });
56
+ return { ok: result.ok, id: result.artifact_id };
57
+ }
58
+ catch (err) {
59
+ try {
60
+ await appendToOutbox(input.initiativeId, {
61
+ id: deps.randomUUID(),
62
+ type: "artifact",
63
+ timestamp: now,
64
+ payload: {
65
+ artifact_id: artifactId,
66
+ entity_type: input.artifact.milestone_id ? "milestone" : "initiative",
67
+ entity_id: input.artifact.milestone_id ?? input.initiativeId,
68
+ name,
69
+ artifact_type: artifactType,
70
+ created_by_type: createdByType,
71
+ created_by_id: createdById,
72
+ description,
73
+ url: input.artifact.url ?? undefined,
74
+ run_id: input.runId,
75
+ },
76
+ activityItem: {
77
+ id: deps.randomUUID(),
78
+ type: "artifact_created",
79
+ title: name,
80
+ description: description ?? null,
81
+ agentId: input.agentId,
82
+ agentName: input.agentName ?? null,
83
+ requesterAgentId: input.agentId,
84
+ requesterAgentName: input.agentName ?? null,
85
+ executorAgentId: input.agentId,
86
+ executorAgentName: input.agentName ?? null,
87
+ runId: input.runId,
88
+ initiativeId: input.initiativeId,
89
+ timestamp: now,
90
+ phase: "handoff",
91
+ summary: input.artifact.url ?? null,
92
+ metadata: {
93
+ source: "openclaw_local_fallback",
94
+ event: "autopilot_slice_artifact_buffered",
95
+ artifact_type: artifactType,
96
+ artifact_id: artifactId,
97
+ url: input.artifact.url ?? null,
98
+ error: deps.safeErrorMessage(err),
99
+ },
100
+ },
101
+ });
102
+ }
103
+ catch {
104
+ // best effort
105
+ }
106
+ return { ok: false, id: null };
107
+ }
108
+ }
109
+ async function applyAgentStatusUpdatesSafe(input) {
110
+ const normalizeTaskStatus = (raw) => {
111
+ const normalized = raw.trim().toLowerCase().replace(/\s+/g, "_");
112
+ if (!normalized)
113
+ return null;
114
+ if (normalized === "done")
115
+ return "done";
116
+ if (normalized === "todo")
117
+ return "todo";
118
+ if (normalized === "blocked")
119
+ return "blocked";
120
+ if (normalized === "in_progress")
121
+ return "in_progress";
122
+ // Common synonyms from LMs.
123
+ if (normalized === "completed" || normalized === "complete" || normalized === "finished") {
124
+ return "done";
125
+ }
126
+ if (normalized === "inprogress" || normalized === "running" || normalized === "working") {
127
+ return "in_progress";
128
+ }
129
+ if (normalized === "not_started" || normalized === "planned" || normalized === "pending") {
130
+ return "todo";
131
+ }
132
+ return null;
133
+ };
134
+ const normalizeMilestoneStatus = (raw) => {
135
+ const normalized = raw.trim().toLowerCase().replace(/\s+/g, "_");
136
+ if (!normalized)
137
+ return null;
138
+ if (normalized === "planned")
139
+ return "planned";
140
+ if (normalized === "in_progress")
141
+ return "in_progress";
142
+ if (normalized === "completed")
143
+ return "completed";
144
+ if (normalized === "at_risk")
145
+ return "at_risk";
146
+ if (normalized === "cancelled")
147
+ return "cancelled";
148
+ // Common synonyms from LMs.
149
+ if (normalized === "done" || normalized === "complete" || normalized === "finished") {
150
+ return "completed";
151
+ }
152
+ if (normalized === "inprogress" || normalized === "running" || normalized === "working") {
153
+ return "in_progress";
154
+ }
155
+ if (normalized === "todo" || normalized === "not_started" || normalized === "pending") {
156
+ return "planned";
157
+ }
158
+ if (normalized === "blocked" || normalized === "stuck") {
159
+ return "at_risk";
160
+ }
161
+ return null;
162
+ };
163
+ const operations = [];
164
+ for (const update of input.taskUpdates) {
165
+ const taskId = (update?.task_id ?? "").trim();
166
+ const status = normalizeTaskStatus(update?.status ?? "");
167
+ if (!taskId || !status)
168
+ continue;
169
+ operations.push({ op: "task.update", task_id: taskId, status });
170
+ }
171
+ for (const update of input.milestoneUpdates) {
172
+ const milestoneId = (update?.milestone_id ?? "").trim();
173
+ const status = normalizeMilestoneStatus(update?.status ?? "");
174
+ if (!milestoneId || !status)
175
+ continue;
176
+ operations.push({ op: "milestone.update", milestone_id: milestoneId, status });
177
+ }
178
+ if (operations.length === 0)
179
+ return { applied: 0, buffered: false };
180
+ try {
181
+ await deps.client.applyChangeset({
182
+ initiative_id: input.initiativeId,
183
+ run_id: input.runId,
184
+ correlation_id: input.correlationId,
185
+ source_client: "openclaw",
186
+ idempotency_key: deps.idempotencyKey([
187
+ "openclaw",
188
+ "autopilot",
189
+ "slice_status",
190
+ input.initiativeId,
191
+ input.correlationId,
192
+ ]),
193
+ operations: operations,
194
+ });
195
+ return { applied: operations.length, buffered: false };
196
+ }
197
+ catch (err) {
198
+ const timestamp = new Date().toISOString();
199
+ try {
200
+ await appendToOutbox(input.initiativeId, {
201
+ id: deps.randomUUID(),
202
+ type: "changeset",
203
+ timestamp,
204
+ payload: {
205
+ initiative_id: input.initiativeId,
206
+ correlation_id: input.correlationId,
207
+ source_client: "openclaw",
208
+ idempotency_key: deps.idempotencyKey([
209
+ "openclaw",
210
+ "autopilot",
211
+ "slice_status",
212
+ input.initiativeId,
213
+ input.correlationId,
214
+ "outbox",
215
+ ]),
216
+ operations,
217
+ },
218
+ activityItem: {
219
+ id: deps.randomUUID(),
220
+ type: "run_started",
221
+ title: `Buffered status updates for slice ${input.runId}`,
222
+ description: null,
223
+ agentId: null,
224
+ agentName: null,
225
+ requesterAgentId: null,
226
+ requesterAgentName: null,
227
+ executorAgentId: null,
228
+ executorAgentName: null,
229
+ runId: input.runId,
230
+ initiativeId: input.initiativeId,
231
+ timestamp,
232
+ phase: "review",
233
+ summary: `Will apply ${operations.length} status update(s) when connected.`,
234
+ metadata: {
235
+ source: "openclaw_local_fallback",
236
+ event: "autopilot_slice_status_updates_buffered",
237
+ error: deps.safeErrorMessage(err),
238
+ },
239
+ },
240
+ });
241
+ }
242
+ catch {
243
+ // best effort
244
+ }
245
+ return { applied: operations.length, buffered: true };
246
+ }
247
+ }
248
+ async function resolveAgentDisplayName(agentId, fallbackName) {
249
+ const normalizedAgentId = agentId.trim();
250
+ if (!normalizedAgentId)
251
+ return null;
252
+ const normalizedFallback = typeof fallbackName === "string" && fallbackName.trim().length > 0
253
+ ? fallbackName.trim()
254
+ : null;
255
+ return normalizedFallback ?? normalizedAgentId;
256
+ }
257
+ async function dispatchFallbackWorkstreamTurn(input) {
258
+ const now = new Date().toISOString();
259
+ const sessionId = deps.randomUUID();
260
+ const taskId = input.taskId?.trim() || null;
261
+ const taskTitle = input.taskTitle?.trim() || null;
262
+ const policyResolution = await deps.resolveDispatchExecutionPolicy({
263
+ initiativeId: input.initiativeId,
264
+ initiativeTitle: input.initiativeTitle,
265
+ workstreamId: input.workstreamId,
266
+ workstreamTitle: input.workstreamTitle,
267
+ taskId,
268
+ taskTitle,
269
+ message: "Continue this workstream from the latest context. Identify and execute the next concrete task.",
270
+ });
271
+ const executionPolicy = policyResolution.executionPolicy;
272
+ const resolvedWorkstreamTitle = policyResolution.workstreamTitle ?? input.workstreamTitle;
273
+ const resolvedTaskTitle = policyResolution.taskTitle ?? taskTitle;
274
+ const guard = await deps.enforceSpawnGuardForDispatch({
275
+ sourceEventPrefix: "next_up_fallback",
276
+ initiativeId: input.initiativeId,
277
+ correlationId: sessionId,
278
+ runId: sessionId,
279
+ executionPolicy,
280
+ agentId: input.agentId,
281
+ taskId,
282
+ taskTitle: resolvedTaskTitle,
283
+ workstreamId: input.workstreamId,
284
+ workstreamTitle: resolvedWorkstreamTitle,
285
+ });
286
+ if (!guard.allowed) {
287
+ return {
288
+ sessionId: null,
289
+ pid: null,
290
+ blockedReason: guard.blockedReason,
291
+ retryable: guard.retryable,
292
+ executionPolicy,
293
+ spawnGuardResult: guard.spawnGuardResult,
294
+ };
295
+ }
296
+ const baseMessage = [
297
+ `Initiative: ${input.initiativeTitle}`,
298
+ `Workstream: ${resolvedWorkstreamTitle}`,
299
+ taskId ? `Task: ${resolvedTaskTitle ?? taskId}` : null,
300
+ "",
301
+ "Continue this workstream from the latest context.",
302
+ "Identify and execute the next concrete task, then provide a concise progress summary.",
303
+ ]
304
+ .filter((line) => Boolean(line))
305
+ .join("\n");
306
+ const message = deps.buildPolicyEnforcedMessage({
307
+ baseMessage,
308
+ executionPolicy,
309
+ spawnGuardResult: guard.spawnGuardResult,
310
+ });
311
+ if (taskId) {
312
+ try {
313
+ await deps.client.updateEntity("task", taskId, { status: "in_progress" });
314
+ }
315
+ catch {
316
+ // best effort
317
+ }
318
+ try {
319
+ await deps.syncParentRollupsForTask({
320
+ initiativeId: input.initiativeId,
321
+ taskId,
322
+ workstreamId: input.workstreamId,
323
+ correlationId: sessionId,
324
+ });
325
+ }
326
+ catch {
327
+ // best effort
328
+ }
329
+ }
330
+ await deps.emitActivitySafe({
331
+ initiativeId: input.initiativeId,
332
+ runId: sessionId,
333
+ correlationId: sessionId,
334
+ phase: "execution",
335
+ level: "info",
336
+ message: `Next Up dispatched ${resolvedWorkstreamTitle}.`,
337
+ metadata: {
338
+ event: "next_up_manual_dispatch_started",
339
+ agent_id: input.agentId,
340
+ agent_name: input.agentName ?? input.agentId,
341
+ requested_by_agent_id: input.agentId,
342
+ requested_by_agent_name: input.agentName ?? input.agentId,
343
+ session_id: sessionId,
344
+ workstream_id: input.workstreamId,
345
+ workstream_title: resolvedWorkstreamTitle,
346
+ task_id: taskId,
347
+ task_title: resolvedTaskTitle,
348
+ domain: executionPolicy.domain,
349
+ required_skills: executionPolicy.requiredSkills,
350
+ spawn_guard_model_tier: deps.extractSpawnGuardModelTier(guard.spawnGuardResult),
351
+ fallback: true,
352
+ },
353
+ });
354
+ deps.upsertAgentContext({
355
+ agentId: input.agentId,
356
+ initiativeId: input.initiativeId,
357
+ initiativeTitle: input.initiativeTitle,
358
+ workstreamId: input.workstreamId,
359
+ taskId,
360
+ });
361
+ deps.upsertRunContext({
362
+ runId: sessionId,
363
+ agentId: input.agentId,
364
+ initiativeId: input.initiativeId,
365
+ initiativeTitle: input.initiativeTitle,
366
+ workstreamId: input.workstreamId,
367
+ taskId,
368
+ });
369
+ const spawned = deps.spawnAgentTurn({
370
+ agentId: input.agentId,
371
+ sessionId,
372
+ message,
373
+ });
374
+ deps.upsertAgentRun({
375
+ runId: sessionId,
376
+ agentId: input.agentId,
377
+ pid: spawned.pid,
378
+ message,
379
+ provider: null,
380
+ model: null,
381
+ initiativeId: input.initiativeId,
382
+ initiativeTitle: input.initiativeTitle,
383
+ workstreamId: input.workstreamId,
384
+ taskId,
385
+ startedAt: now,
386
+ status: "running",
387
+ });
388
+ return {
389
+ sessionId,
390
+ pid: spawned.pid,
391
+ blockedReason: null,
392
+ retryable: false,
393
+ executionPolicy,
394
+ spawnGuardResult: guard.spawnGuardResult,
395
+ };
396
+ }
397
+ return {
398
+ registerArtifactSafe,
399
+ applyAgentStatusUpdatesSafe,
400
+ resolveAgentDisplayName,
401
+ dispatchFallbackWorkstreamTurn,
402
+ };
403
+ }
@@ -0,0 +1,42 @@
1
+ import { type ChildProcess } from "node:child_process";
2
+ import type { RuntimeHookPayload, RuntimeInstanceRecord } from "../../runtime-instance-store.js";
3
+ import type { RuntimeSourceClient } from "../../runtime-instance-store.js";
4
+ import type { CodexBinInfo } from "./autopilot-slice-utils.js";
5
+ type CreateAutopilotRuntimeDeps = {
6
+ filename: string;
7
+ autoContinueSliceChildren: Map<string, ChildProcess>;
8
+ resolveByokEnvOverrides: () => Record<string, string | undefined>;
9
+ safeErrorMessage: (err: unknown) => string;
10
+ resolveCodexBinInfo: () => CodexBinInfo;
11
+ upsertRuntimeInstanceFromHook: (payload: RuntimeHookPayload) => RuntimeInstanceRecord;
12
+ broadcastRuntimeSse: (event: string, payload: RuntimeInstanceRecord) => void;
13
+ clearSnapshotResponseCache: () => void;
14
+ };
15
+ export declare function createAutopilotRuntime(deps: CreateAutopilotRuntimeDeps): {
16
+ spawnCodexSliceWorker: (input: {
17
+ runId: string;
18
+ prompt: string;
19
+ cwd: string;
20
+ logPath: string;
21
+ outputPath: string;
22
+ env: Record<string, string | undefined>;
23
+ }) => {
24
+ pid: number | null;
25
+ };
26
+ writeRuntimeEvent: (input: {
27
+ sourceClient: RuntimeSourceClient;
28
+ event: RuntimeHookPayload["event"];
29
+ runId: string;
30
+ initiativeId: string;
31
+ workstreamId: string | null;
32
+ taskId: string | null;
33
+ agentId: string | null;
34
+ agentName: string | null;
35
+ phase: string | null;
36
+ message?: string | null;
37
+ progressPct?: number | null;
38
+ metadata?: Record<string, unknown> | null;
39
+ timestamp?: string | null;
40
+ }) => RuntimeInstanceRecord;
41
+ };
42
+ export {};