@runuai/host 0.9.116 → 0.9.117

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.
@@ -135,6 +135,7 @@ import type {
135
135
  HostEvent,
136
136
  } from "../src/protocol";
137
137
  import {
138
+ type TaskStartStage,
138
139
  HOST_ACCOUNT_SCOPE,
139
140
  MAX_AGENT_ID_CHARS,
140
141
  MAX_SECRETARY_DISPATCH_ID_CHARS,
@@ -455,6 +456,11 @@ export class Orchestrator {
455
456
  this.emitHost({ kind: "system.note", taskId, text });
456
457
  }
457
458
 
459
+ /** A task-start stage boundary (the launch screen on the task page). */
460
+ emitTaskStage(taskId: string, stage: TaskStartStage): void {
461
+ this.emitHost({ kind: "task.stage", taskId, stage, at: Date.now() });
462
+ }
463
+
458
464
  private emitHost(event: HostEvent): void {
459
465
  for (const fn of this.hostSubscribers) {
460
466
  try {
@@ -1889,6 +1895,7 @@ export class Orchestrator {
1889
1895
  // which the client caps at 10s (Codex) / 30s (Claude Code). Idempotent
1890
1896
  // and ~0.5s once the build is present; a failure arms its own 60s retry
1891
1897
  // rather than depending on another delivery/ensure to arrive.
1898
+ this.emitTaskStage(channel.taskId, "tools");
1892
1899
  await this.ensureBrowserSetup(
1893
1900
  channel,
1894
1901
  initialRoster.some((a) => a.kind === "codex"),
@@ -1923,6 +1930,7 @@ export class Orchestrator {
1923
1930
  return false;
1924
1931
  }
1925
1932
 
1933
+ this.emitTaskStage(channel.taskId, "agents");
1926
1934
  for (const agent of initialRoster) {
1927
1935
  if (!this.isActiveChannel(channel)) return false;
1928
1936
  // A prior partial start or an independently guarded recovery may already
@@ -1972,6 +1980,7 @@ export class Orchestrator {
1972
1980
  // so it both duplicated the opening turn AND re-injected it on a host
1973
1981
  // restart, making agents redo the first turn mid-task. The persona/mission
1974
1982
  // an agent needs live in the always-on system preamble, so nothing is lost.
1983
+ this.emitTaskStage(channel.taskId, "ready");
1975
1984
  return true;
1976
1985
  }
1977
1986
 
@@ -128,7 +128,7 @@ registry.register(appleProvider);
128
128
  // host) until machine-backing becomes a per-task property.
129
129
  // ---------------------------------------------------------------------------
130
130
 
131
- function machineTasksEnabled(): boolean {
131
+ export function machineTasksEnabled(): boolean {
132
132
  return process.env.UAI_MACHINE_TASKS === "1";
133
133
  }
134
134
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@runuai/host",
3
- "version": "0.9.116",
3
+ "version": "0.9.117",
4
4
  "description": "Uai host — runs ephemeral AI tasks in containers on a machine you control.",
5
5
  "license": "MIT",
6
6
  "author": "Uai Tech <team@runuai.com>",
package/src/index.ts CHANGED
@@ -77,6 +77,7 @@ import {
77
77
  } from "../lib/container-runtime";
78
78
  import { vnodeAdmissionProblem } from "../lib/vnode-pressure";
79
79
  import {
80
+ machineTasksEnabled,
80
81
  provisionTaskEnvironment,
81
82
  reconstructPersistedTaskEnvironment,
82
83
  } from "../lib/task-environment";
@@ -818,6 +819,13 @@ export const hostCommands: HostCommands = {
818
819
  "GitHub is connected on this host, but Uai could not prepare its credential for Git. Retry the task; if it persists, reconnect GitHub on this host.",
819
820
  );
820
821
  }
822
+ // Launch screen: the first stage boundary. A machine-backed task
823
+ // spends the next minute launching an EC2 instance; a container
824
+ // task goes straight to preparing its workspace.
825
+ orchestrator.emitTaskStage(
826
+ input.task.id,
827
+ machineTasksEnabled() ? "machine" : "workspace",
828
+ );
821
829
  try {
822
830
  const provisioned = gitCredential
823
831
  ? await gitCredential.run(() =>
package/src/protocol.ts CHANGED
@@ -1831,6 +1831,15 @@ export type HostToCloud =
1831
1831
  | EngineConnectEventFrame
1832
1832
  | HostConfigAckFrame;
1833
1833
 
1834
+ /** Task start stages, in order (docs/agent-notes.md "task start screen"). The
1835
+ * host emits them as `task.stage` events while a task comes up; the page
1836
+ * shows a launch screen instead of the chat until `ready`. */
1837
+ export const TASK_START_STAGES = ["machine", "workspace", "tools", "agents", "ready"] as const;
1838
+ export type TaskStartStage = (typeof TASK_START_STAGES)[number];
1839
+ export function isTaskStartStage(value: unknown): value is TaskStartStage {
1840
+ return (TASK_START_STAGES as readonly unknown[]).includes(value);
1841
+ }
1842
+
1834
1843
  export type HostEvent =
1835
1844
  | {
1836
1845
  kind: "task.status_changed";
@@ -1838,6 +1847,7 @@ export type HostEvent =
1838
1847
  from: string;
1839
1848
  to: string;
1840
1849
  }
1850
+ | { kind: "task.stage"; taskId: string; stage: TaskStartStage; at: number }
1841
1851
  | {
1842
1852
  kind: "task.log";
1843
1853
  taskId: string;