@mindfoldhq/runtime-manager 0.1.5 → 0.1.7-hotfix.1

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.
package/README.md CHANGED
@@ -16,7 +16,7 @@ VINE_REMOTE_SANDBOX_PROVIDER='e2b' \
16
16
  VINE_RUNNER_LINK_HOST='0.0.0.0' \
17
17
  VINE_RUNNER_LINK_PORT='8788' \
18
18
  VINE_RUNNER_LINK_PUBLIC_URL='<public-runner-link-wss-url>' \
19
- npx @mindfoldhq/runtime-manager serve
19
+ npx -y @mindfoldhq/runtime-manager serve
20
20
  ```
21
21
 
22
22
  `VINE_MANAGER_TOKEN` is created in Vine Web Settings -> Runtime managers. The
@@ -1739,7 +1739,11 @@ var WRITABLE_TASK_DOCS = [
1739
1739
  "implement_md"
1740
1740
  ];
1741
1741
  var WritableTaskDoc = z8.enum(WRITABLE_TASK_DOCS);
1742
- var TASK_MUTATIONS = ["create", "update_status"];
1742
+ var TASK_MUTATIONS = [
1743
+ "create",
1744
+ "update_status",
1745
+ "review_request"
1746
+ ];
1743
1747
  var TaskMutationCapability = z8.enum(TASK_MUTATIONS);
1744
1748
  var contextPolicyFields = {
1745
1749
  channelHistory: ChannelHistoryMode,
@@ -3026,6 +3030,16 @@ var AgentSessionStatePayload = z20.object({
3026
3030
  last_error: z20.string().nullable(),
3027
3031
  metadata: z20.record(z20.string(), z20.unknown()).optional()
3028
3032
  });
3033
+ var ManagerTurnStartedPayload = z20.object({
3034
+ agent_turn_id: z20.string().min(1),
3035
+ organization_id: z20.string().min(1),
3036
+ session_id: z20.string().min(1),
3037
+ runner_id: z20.string().min(1),
3038
+ agent_session_id: z20.string().min(1),
3039
+ agent_profile_id: z20.string().min(1),
3040
+ project_agent_profile_id: z20.string().nullable(),
3041
+ backend_kind: ManagerBackendKind
3042
+ });
3029
3043
  var ManagerTurnEventPayload = z20.object({
3030
3044
  agent_turn_id: z20.string().min(1),
3031
3045
  kind: ManagerTurnEventKind,
@@ -3077,6 +3091,15 @@ var TaskCliStatusUpdatePayload = z20.object({
3077
3091
  status: TaskStatus,
3078
3092
  expected_version: z20.number().int().optional()
3079
3093
  }).strict();
3094
+ var TaskCliReviewRequestCreatePayload = z20.object({
3095
+ request_id: z20.string().min(1),
3096
+ session_id: z20.string().min(1),
3097
+ agent_turn_id: z20.string().min(1),
3098
+ project_repository_id: z20.string().min(1).optional(),
3099
+ repo_slug: z20.string().min(1).optional(),
3100
+ title: z20.string().min(1).max(256).optional(),
3101
+ body: z20.string().max(65000).optional()
3102
+ }).strict();
3080
3103
  var ManagerTaskRefsSnapshotPayload = TaskRefsSnapshotPayload;
3081
3104
  var AgentQuestionCreatePayload = z20.object({
3082
3105
  request_id: z20.string().min(1),
@@ -3237,6 +3260,15 @@ var TaskCliStatusUpdateResultPayload = z20.object({
3237
3260
  message: z20.string().min(1)
3238
3261
  }).optional()
3239
3262
  });
3263
+ var TaskCliReviewRequestCreateResultPayload = z20.object({
3264
+ request_id: z20.string().min(1),
3265
+ status: z20.enum(["ok", "error"]),
3266
+ review_request: TaskReviewRequestDto.optional(),
3267
+ error: z20.object({
3268
+ code: z20.string().min(1),
3269
+ message: z20.string().min(1)
3270
+ }).optional()
3271
+ });
3240
3272
  var AgentQuestionCreateResultPayload = z20.object({
3241
3273
  request_id: z20.string().min(1),
3242
3274
  status: z20.enum(["ok", "error"]),
@@ -3395,6 +3427,10 @@ var ManagerToServerMessage = z20.discriminatedUnion("type", [
3395
3427
  type: z20.literal("agent_session.state"),
3396
3428
  payload: AgentSessionStatePayload
3397
3429
  }),
3430
+ z20.object({
3431
+ type: z20.literal("turn.started"),
3432
+ payload: ManagerTurnStartedPayload
3433
+ }),
3398
3434
  z20.object({ type: z20.literal("turn.event"), payload: ManagerTurnEventPayload }),
3399
3435
  z20.object({
3400
3436
  type: z20.literal("turn.finished"),
@@ -3420,6 +3456,10 @@ var ManagerToServerMessage = z20.discriminatedUnion("type", [
3420
3456
  type: z20.literal("task.cli_status_update"),
3421
3457
  payload: TaskCliStatusUpdatePayload
3422
3458
  }),
3459
+ z20.object({
3460
+ type: z20.literal("task.cli_review_request_create"),
3461
+ payload: TaskCliReviewRequestCreatePayload
3462
+ }),
3423
3463
  z20.object({
3424
3464
  type: z20.literal("task.refs_snapshot"),
3425
3465
  payload: ManagerTaskRefsSnapshotPayload
@@ -3511,6 +3551,10 @@ var ServerToManagerMessage = z20.discriminatedUnion("type", [
3511
3551
  type: z20.literal("task.cli_status_update.result"),
3512
3552
  payload: TaskCliStatusUpdateResultPayload
3513
3553
  }),
3554
+ z20.object({
3555
+ type: z20.literal("task.cli_review_request_create.result"),
3556
+ payload: TaskCliReviewRequestCreateResultPayload
3557
+ }),
3514
3558
  z20.object({
3515
3559
  type: z20.literal("agent.question.create.result"),
3516
3560
  payload: AgentQuestionCreateResultPayload
@@ -6679,6 +6723,7 @@ var VineCliCommandName = z44.enum([
6679
6723
  "task.update_implement",
6680
6724
  "task.create",
6681
6725
  "task.update_status",
6726
+ "task.create_review_request",
6682
6727
  "task.ask"
6683
6728
  ]);
6684
6729
  var VineCliTaskUpdateArgs = z44.object({
@@ -6719,6 +6764,19 @@ var VineCliTaskStatusUpdateCommand = z44.object({
6719
6764
  command: z44.literal("task.update_status"),
6720
6765
  args: VineCliTaskStatusUpdateArgs
6721
6766
  });
6767
+ var VineCliTaskReviewRequestCreateArgs = z44.object({
6768
+ project_repository_id: z44.string().min(1).optional(),
6769
+ repo_slug: z44.string().min(1).optional(),
6770
+ title: z44.string().min(1).max(256).optional(),
6771
+ body: z44.string().max(65000).optional()
6772
+ }).strict().refine((args) => !(args.project_repository_id && args.repo_slug), {
6773
+ message: "pass either project_repository_id or repo_slug, not both",
6774
+ path: ["repo_slug"]
6775
+ });
6776
+ var VineCliTaskReviewRequestCreateCommand = z44.object({
6777
+ command: z44.literal("task.create_review_request"),
6778
+ args: VineCliTaskReviewRequestCreateArgs
6779
+ });
6722
6780
  var VineCliAskArgs = z44.object({
6723
6781
  questions: z44.array(AgentQuestionSpec).min(1)
6724
6782
  });
@@ -6735,6 +6793,7 @@ var VineCliCommand = z44.discriminatedUnion("command", [
6735
6793
  VineCliTaskUpdateImplementCommand,
6736
6794
  VineCliTaskCreateCommand,
6737
6795
  VineCliTaskStatusUpdateCommand,
6796
+ VineCliTaskReviewRequestCreateCommand,
6738
6797
  VineCliAskCommand
6739
6798
  ]);
6740
6799
  var TASK_DOC_WRITEBACK = {
@@ -8355,6 +8414,50 @@ async function handleTaskStatusUpdateCommand(input, command, deps) {
8355
8414
  }
8356
8415
  };
8357
8416
  }
8417
+ async function handleTaskReviewRequestCreateCommand(input, command, deps) {
8418
+ const args = VineCliTaskReviewRequestCreateArgs.safeParse(command.args);
8419
+ if (!args.success) {
8420
+ return errorResponse2(input.request.request_id, "VALIDATION_MALFORMED_PAYLOAD", "task review request command args are malformed");
8421
+ }
8422
+ const binding = deps.sessionBinding(input.sessionId);
8423
+ if (!binding) {
8424
+ return errorResponse2(input.request.request_id, "RUNTIME_SESSION_NOT_FOUND", "runtime session is not active");
8425
+ }
8426
+ if (binding.taskId === null) {
8427
+ return errorResponse2(input.request.request_id, "AUTH_FORBIDDEN", "runtime session is not linked to a task");
8428
+ }
8429
+ const activeTurn = deps.resolveActiveTurn(input.sessionId);
8430
+ if (!activeTurn.ok) {
8431
+ return activeTurnError2(input.request.request_id, activeTurn.code);
8432
+ }
8433
+ const result = await deps.taskClient.createTaskReviewRequestFromCli({
8434
+ request_id: input.request.request_id,
8435
+ session_id: input.sessionId,
8436
+ agent_turn_id: activeTurn.turnId,
8437
+ ...args.data.project_repository_id === undefined ? {} : { project_repository_id: args.data.project_repository_id },
8438
+ ...args.data.repo_slug === undefined ? {} : { repo_slug: args.data.repo_slug },
8439
+ ...args.data.title === undefined ? {} : { title: args.data.title },
8440
+ ...args.data.body === undefined ? {} : { body: args.data.body }
8441
+ });
8442
+ if (result.status === "ok") {
8443
+ if (result.review_request === undefined) {
8444
+ return errorResponse2(input.request.request_id, "INTERNAL_BUG", "task review request succeeded without review request details");
8445
+ }
8446
+ return {
8447
+ request_id: input.request.request_id,
8448
+ status: "ok",
8449
+ body: result.review_request
8450
+ };
8451
+ }
8452
+ return {
8453
+ request_id: input.request.request_id,
8454
+ status: "error",
8455
+ error: result.error ?? {
8456
+ code: "INTERNAL_BUG",
8457
+ message: "task review request failed"
8458
+ }
8459
+ };
8460
+ }
8358
8461
  function activeTurnError2(requestId, code) {
8359
8462
  return errorResponse2(requestId, code, code === "ASK_AMBIGUOUS_ACTIVE_TURN" ? "runtime session has multiple active turns" : "runtime session has no active turn");
8360
8463
  }
@@ -8450,6 +8553,8 @@ async function routeCliRequest(input, deps) {
8450
8553
  return handleTaskCreateCommand(input, parsed.data, deps);
8451
8554
  case "task.update_status":
8452
8555
  return handleTaskStatusUpdateCommand(input, parsed.data, deps);
8556
+ case "task.create_review_request":
8557
+ return handleTaskReviewRequestCreateCommand(input, parsed.data, deps);
8453
8558
  case "task.update_prd":
8454
8559
  case "task.update_design":
8455
8560
  case "task.update_implement":
@@ -8929,6 +9034,7 @@ class E2BProvider {
8929
9034
  await this.killTrackedRunnerCommand(tracked, "respawn");
8930
9035
  let command;
8931
9036
  try {
9037
+ await this.cleanupPersistedRunnerState(tracked.sandbox, workspaceRoot, tracked, "respawn");
8932
9038
  tracked.reposFilePath = reposFilePath;
8933
9039
  if (reposFilePath) {
8934
9040
  await tracked.sandbox.files.write(reposFilePath, serializeRuntimeReposManifest(remoteRepos));
@@ -9043,7 +9149,10 @@ class E2BProvider {
9043
9149
  return result;
9044
9150
  }
9045
9151
  async prepareRestoredSandbox(sandbox, workspaceRoot, tracked) {
9046
- const result = await sandbox.commands.run(this.restoredSandboxCleanupCommand(workspaceRoot), {
9152
+ await this.cleanupPersistedRunnerState(sandbox, workspaceRoot, tracked, "restore");
9153
+ }
9154
+ async cleanupPersistedRunnerState(sandbox, workspaceRoot, tracked, reason) {
9155
+ const result = await sandbox.commands.run(this.persistedRunnerCleanupCommand(workspaceRoot), {
9047
9156
  cwd: "/",
9048
9157
  timeoutMs: DEFAULT_CLEANUP_TIMEOUT_MS,
9049
9158
  onStdout: (data) => {
@@ -9054,13 +9163,14 @@ class E2BProvider {
9054
9163
  }
9055
9164
  });
9056
9165
  if (isCommandHandle(result)) {
9057
- throw new Error("E2B restore cleanup unexpectedly ran in background");
9166
+ throw new Error(`E2B ${reason} cleanup unexpectedly ran in background`);
9058
9167
  }
9059
9168
  if (result.exitCode !== 0) {
9060
- throw new Error(`E2B restore cleanup exited ${result.exitCode}: ${redactDiagnosticString(result.stderr)}`);
9169
+ throw new Error(`E2B ${reason} cleanup exited ${result.exitCode}: ${redactDiagnosticString(result.stderr)}`);
9061
9170
  }
9171
+ log8.info({ sandbox_id: sandbox.sandboxId, reason }, "E2B persisted runner cleanup completed");
9062
9172
  }
9063
- restoredSandboxCleanupCommand(workspaceRoot) {
9173
+ persistedRunnerCleanupCommand(workspaceRoot) {
9064
9174
  const socketPath = shellQuote2(`${workspaceRoot}/.vine/vine.sock`);
9065
9175
  return [
9066
9176
  "set -eu;",
@@ -10868,6 +10978,15 @@ class SessionLifecycle {
10868
10978
  dirty_files: 0
10869
10979
  };
10870
10980
  if (!this.m.runnerLink.hasRunner(session.sessionId)) {
10981
+ if (session.providerKind === "remote_sandbox" && session.repos.length > 0) {
10982
+ log11.warn({
10983
+ session_id: session.sessionId,
10984
+ provider_key: session.providerKey,
10985
+ repo_count: session.repos.length
10986
+ }, "no runner connected for remote repo workspace — treating dirty state as unknown/dirty");
10987
+ resolve3(conservativeDirty);
10988
+ return;
10989
+ }
10871
10990
  log11.info({ session_id: session.sessionId }, "no runner connected — skipping dirty probe, treating workspace as clean");
10872
10991
  resolve3({
10873
10992
  session_id: session.sessionId,
@@ -11573,10 +11692,23 @@ class TaskProjectionBridge {
11573
11692
  const agentKey = session.turnToAgentKey.get(turnStart.turn_id);
11574
11693
  const agentSession = agentKey ? session.agentSessions.get(agentKey) : undefined;
11575
11694
  if (agentSession) {
11695
+ this.emitTurnStarted(session, turnStart, agentSession);
11576
11696
  this.m.emitAgentSessionState(session, agentSession, "active");
11577
11697
  }
11578
11698
  }
11579
11699
  }
11700
+ emitTurnStarted(session, turnStart, agentSession) {
11701
+ this.m.serverClient.emitTurnStarted({
11702
+ agent_turn_id: turnStart.turn_id,
11703
+ organization_id: session.organizationId,
11704
+ session_id: session.sessionId,
11705
+ runner_id: session.runnerId,
11706
+ agent_session_id: agentSession.agentSessionId,
11707
+ agent_profile_id: agentSession.agentProfileId,
11708
+ project_agent_profile_id: agentSession.projectAgentProfileId,
11709
+ backend_kind: agentSession.backendKind
11710
+ });
11711
+ }
11580
11712
  }
11581
11713
 
11582
11714
  // src/runtime-manager-terminal-relay.ts
@@ -12256,6 +12388,16 @@ class TurnRouter {
12256
12388
  this.m.maybeRespawnDisconnectedSession(session, "turn_dispatch");
12257
12389
  return;
12258
12390
  }
12391
+ this.m.serverClient.emitTurnStarted({
12392
+ agent_turn_id: dispatch.agent_turn_id,
12393
+ organization_id: session.organizationId,
12394
+ session_id: session.sessionId,
12395
+ runner_id: session.runnerId,
12396
+ agent_session_id: agentSession.agentSessionId,
12397
+ agent_profile_id: agentSession.agentProfileId,
12398
+ project_agent_profile_id: agentSession.projectAgentProfileId,
12399
+ backend_kind: agentSession.backendKind
12400
+ });
12259
12401
  this.m.emitAgentSessionState(session, agentSession, "active");
12260
12402
  log15.info({
12261
12403
  agent_turn_id: dispatch.agent_turn_id,
@@ -12559,6 +12701,7 @@ class ServerClient {
12559
12701
  pendingTaskCliUpdates = new Map;
12560
12702
  pendingTaskCliCreates = new Map;
12561
12703
  pendingTaskCliStatusUpdates = new Map;
12704
+ pendingTaskCliReviewRequestCreates = new Map;
12562
12705
  pendingQuestionCreates = new Map;
12563
12706
  pendingTerminalFrames = [];
12564
12707
  constructor(opts) {
@@ -12809,6 +12952,10 @@ class ServerClient {
12809
12952
  this.settleTaskCliStatusUpdate(parsed.payload);
12810
12953
  return;
12811
12954
  }
12955
+ case "task.cli_review_request_create.result": {
12956
+ this.settleTaskCliReviewRequestCreate(parsed.payload);
12957
+ return;
12958
+ }
12812
12959
  case "agent.question.create.result": {
12813
12960
  this.settleQuestionCreate(parsed.payload);
12814
12961
  return;
@@ -12950,6 +13097,13 @@ class ServerClient {
12950
13097
  payload: { ...payload, request_id: requestId }
12951
13098
  }));
12952
13099
  }
13100
+ requestTaskCliReviewRequestCreate(payload) {
13101
+ const requestId = payload.request_id ?? randomUUID6();
13102
+ return this.trackTaskRequest(this.pendingTaskCliReviewRequestCreates, requestId, () => this.send({
13103
+ type: "task.cli_review_request_create",
13104
+ payload: { ...payload, request_id: requestId }
13105
+ }));
13106
+ }
12953
13107
  requestQuestionCreate(payload) {
12954
13108
  const requestId = payload.request_id ?? randomUUID6();
12955
13109
  return this.trackTaskRequest(this.pendingQuestionCreates, requestId, () => this.send({
@@ -12988,6 +13142,9 @@ class ServerClient {
12988
13142
  settleTaskCliStatusUpdate(payload) {
12989
13143
  this.settleTaskRequest(this.pendingTaskCliStatusUpdates, payload.request_id, payload);
12990
13144
  }
13145
+ settleTaskCliReviewRequestCreate(payload) {
13146
+ this.settleTaskRequest(this.pendingTaskCliReviewRequestCreates, payload.request_id, payload);
13147
+ }
12991
13148
  settleQuestionCreate(payload) {
12992
13149
  this.settleTaskRequest(this.pendingQuestionCreates, payload.request_id, payload);
12993
13150
  }
@@ -13007,6 +13164,7 @@ class ServerClient {
13007
13164
  this.pendingTaskCliUpdates,
13008
13165
  this.pendingTaskCliCreates,
13009
13166
  this.pendingTaskCliStatusUpdates,
13167
+ this.pendingTaskCliReviewRequestCreates,
13010
13168
  this.pendingQuestionCreates
13011
13169
  ]) {
13012
13170
  for (const request of pending.values()) {
@@ -13025,6 +13183,9 @@ class ServerClient {
13025
13183
  emitAgentSessionState(payload) {
13026
13184
  return this.send({ type: "agent_session.state", payload });
13027
13185
  }
13186
+ emitTurnStarted(payload) {
13187
+ return this.send({ type: "turn.started", payload });
13188
+ }
13028
13189
  }
13029
13190
  function unrefTimer(timer) {
13030
13191
  const maybeTimer = timer;
@@ -13479,6 +13640,7 @@ class RuntimeManager {
13479
13640
  taskClient: {
13480
13641
  createTaskFromCli: (payload) => this.serverClient.requestTaskCliCreate(payload),
13481
13642
  updateTaskStatusFromCli: (payload) => this.serverClient.requestTaskCliStatusUpdate(payload),
13643
+ createTaskReviewRequestFromCli: (payload) => this.serverClient.requestTaskCliReviewRequestCreate(payload),
13482
13644
  updateTaskFromCli: (payload) => this.serverClient.requestTaskCliUpdate(payload)
13483
13645
  },
13484
13646
  questionClient: {
@@ -13546,15 +13708,22 @@ class RuntimeManager {
13546
13708
  }
13547
13709
  this.clearRunnerBootTimer(session);
13548
13710
  }
13549
- this.runnerLink.stop();
13550
13711
  const releases = sessions.map(async (session) => {
13551
13712
  if (!session.provisioned) {
13552
13713
  this.emitReleasedState(session);
13553
- return;
13714
+ return "released";
13715
+ }
13716
+ if (session.lastStatus !== "idle_checkpointed" && await this.sessionLifecycle.dirtyProbeHoldsRelease(session)) {
13717
+ log17.info({
13718
+ session_id: session.sessionId,
13719
+ provider_key: session.providerKey
13720
+ }, "shutdown release blocked by dirty workspace — preserving provider runtime");
13721
+ return "preserved";
13554
13722
  }
13555
13723
  try {
13556
13724
  await providerForSession(this, session).releaseSession(session.provisioned);
13557
13725
  this.emitReleasedState(session);
13726
+ return "released";
13558
13727
  } catch (err) {
13559
13728
  log17.warn({ err, session_id: session.sessionId }, "session release failed during shutdown — marking failed");
13560
13729
  const detail = err instanceof Error ? err.message : String(err);
@@ -13563,12 +13732,17 @@ class RuntimeManager {
13563
13732
  }
13564
13733
  this.emitRunnerStateFailed(session, detail);
13565
13734
  this.emitSessionStateFailed(session, detail);
13735
+ return "failed";
13566
13736
  }
13567
13737
  });
13738
+ const results = await Promise.allSettled(releases);
13739
+ this.runnerLink.stop();
13568
13740
  this.sessions.clear();
13569
13741
  this.sessionsById.clear();
13570
- await Promise.allSettled(releases);
13571
- log17.info({ released: releases.length }, "all sessions released");
13742
+ const released = results.filter((result) => result.status === "fulfilled" && result.value === "released").length;
13743
+ const preserved = results.filter((result) => result.status === "fulfilled" && result.value === "preserved").length;
13744
+ const failed = results.length - released - preserved;
13745
+ log17.info({ released, preserved, failed }, "shutdown session release drain finished");
13572
13746
  this.serverClient.stop();
13573
13747
  }
13574
13748
  emitReleasedState(session) {
@@ -14356,6 +14530,7 @@ class RuntimeManager2 {
14356
14530
  taskClient: {
14357
14531
  createTaskFromCli: (payload) => this.serverClient.requestTaskCliCreate(payload),
14358
14532
  updateTaskStatusFromCli: (payload) => this.serverClient.requestTaskCliStatusUpdate(payload),
14533
+ createTaskReviewRequestFromCli: (payload) => this.serverClient.requestTaskCliReviewRequestCreate(payload),
14359
14534
  updateTaskFromCli: (payload) => this.serverClient.requestTaskCliUpdate(payload)
14360
14535
  },
14361
14536
  questionClient: {
@@ -14423,15 +14598,22 @@ class RuntimeManager2 {
14423
14598
  }
14424
14599
  this.clearRunnerBootTimer(session);
14425
14600
  }
14426
- this.runnerLink.stop();
14427
14601
  const releases = sessions.map(async (session) => {
14428
14602
  if (!session.provisioned) {
14429
14603
  this.emitReleasedState(session);
14430
- return;
14604
+ return "released";
14605
+ }
14606
+ if (session.lastStatus !== "idle_checkpointed" && await this.sessionLifecycle.dirtyProbeHoldsRelease(session)) {
14607
+ log19.info({
14608
+ session_id: session.sessionId,
14609
+ provider_key: session.providerKey
14610
+ }, "shutdown release blocked by dirty workspace — preserving provider runtime");
14611
+ return "preserved";
14431
14612
  }
14432
14613
  try {
14433
14614
  await providerForSession(this, session).releaseSession(session.provisioned);
14434
14615
  this.emitReleasedState(session);
14616
+ return "released";
14435
14617
  } catch (err) {
14436
14618
  log19.warn({ err, session_id: session.sessionId }, "session release failed during shutdown — marking failed");
14437
14619
  const detail = err instanceof Error ? err.message : String(err);
@@ -14440,12 +14622,17 @@ class RuntimeManager2 {
14440
14622
  }
14441
14623
  this.emitRunnerStateFailed(session, detail);
14442
14624
  this.emitSessionStateFailed(session, detail);
14625
+ return "failed";
14443
14626
  }
14444
14627
  });
14628
+ const results = await Promise.allSettled(releases);
14629
+ this.runnerLink.stop();
14445
14630
  this.sessions.clear();
14446
14631
  this.sessionsById.clear();
14447
- await Promise.allSettled(releases);
14448
- log19.info({ released: releases.length }, "all sessions released");
14632
+ const released = results.filter((result) => result.status === "fulfilled" && result.value === "released").length;
14633
+ const preserved = results.filter((result) => result.status === "fulfilled" && result.value === "preserved").length;
14634
+ const failed = results.length - released - preserved;
14635
+ log19.info({ released, preserved, failed }, "shutdown session release drain finished");
14449
14636
  this.serverClient.stop();
14450
14637
  }
14451
14638
  emitReleasedState(session) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mindfoldhq/runtime-manager",
3
- "version": "0.1.5",
3
+ "version": "0.1.7-hotfix.1",
4
4
  "description": "Vine runtime manager CLI",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",