@capybara-hq/kernel 0.1.0-rc.11 → 0.1.0-rc.13

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 (220) hide show
  1. package/dist/admin/admin.schemas.d.ts +13 -0
  2. package/dist/agents/agent-lookup.d.ts +5 -0
  3. package/dist/agents/agent-lookup.js +15 -0
  4. package/dist/agents/agents.schemas.d.ts +3 -0
  5. package/dist/agents/agents.service.js +11 -1
  6. package/dist/agents/definition.d.ts +1 -0
  7. package/dist/agents/definition.js +7 -3
  8. package/dist/agents/org-templates.js +4 -0
  9. package/dist/agents/pending-connectors.service.js +1 -1
  10. package/dist/background/background.module.js +2 -2
  11. package/dist/background/launch-lock.d.ts +1 -1
  12. package/dist/background/launch-lock.js +1 -1
  13. package/dist/background/poll.job.d.ts +2 -2
  14. package/dist/background/poll.job.js +10 -10
  15. package/dist/background/stop.d.ts +1 -1
  16. package/dist/background/stop.js +3 -3
  17. package/dist/background/store.d.ts +5 -5
  18. package/dist/background/store.js +5 -5
  19. package/dist/background/tasks.service.d.ts +6 -6
  20. package/dist/background/tasks.service.js +13 -13
  21. package/dist/catalog/component-scope.controller.d.ts +18 -6
  22. package/dist/catalog/component-scope.controller.js +36 -13
  23. package/dist/catalog/component-scope.service.d.ts +11 -0
  24. package/dist/catalog/component-scope.service.js +4 -0
  25. package/dist/catalog/component-state.d.ts +8 -0
  26. package/dist/catalog/component-state.js +19 -11
  27. package/dist/catalog/marketplaces.service.d.ts +1 -1
  28. package/dist/catalog/plugin-import.js +4 -1
  29. package/dist/channels/channels.module.js +2 -2
  30. package/dist/channels/inbound.d.ts +8 -8
  31. package/dist/channels/inbound.js +31 -31
  32. package/dist/channels/phrases.d.ts +27 -27
  33. package/dist/channels/phrases.js +27 -27
  34. package/dist/config/docs.js +1 -1
  35. package/dist/config/schema.d.ts +2 -2
  36. package/dist/config/schema.js +21 -21
  37. package/dist/conversations/conversations.controller.d.ts +11 -11
  38. package/dist/conversations/conversations.controller.js +15 -15
  39. package/dist/conversations/conversations.module.d.ts +1 -1
  40. package/dist/conversations/conversations.module.js +7 -7
  41. package/dist/conversations/conversations.schemas.js +1 -1
  42. package/dist/conversations/conversations.service.d.ts +23 -14
  43. package/dist/conversations/conversations.service.js +28 -21
  44. package/dist/conversations/{environment-status.d.ts → device-status.d.ts} +9 -9
  45. package/dist/conversations/{environment-status.js → device-status.js} +18 -18
  46. package/dist/conversations/event-log.d.ts +1 -1
  47. package/dist/conversations/event-log.js +1 -1
  48. package/dist/conversations/events.d.ts +2 -1
  49. package/dist/conversations/events.js +2 -2
  50. package/dist/ctx/create-ctx.d.ts +10 -1
  51. package/dist/ctx/create-ctx.js +86 -25
  52. package/dist/db/kernel-schema.d.ts +39 -23
  53. package/dist/{environments → devices}/access.d.ts +19 -19
  54. package/dist/{environments → devices}/access.js +28 -28
  55. package/dist/devices/conversation-devices.d.ts +75 -0
  56. package/dist/{environments/conversation-environments.js → devices/conversation-devices.js} +71 -72
  57. package/dist/devices/devices.controller.d.ts +36 -0
  58. package/dist/{environments/environments.controller.js → devices/devices.controller.js} +37 -37
  59. package/dist/devices/devices.module.d.ts +5 -13
  60. package/dist/devices/devices.module.js +16 -29
  61. package/dist/devices/devices.schemas.d.ts +3 -0
  62. package/dist/devices/devices.schemas.js +14 -0
  63. package/dist/{environments/environments.service.d.ts → devices/devices.service.d.ts} +70 -70
  64. package/dist/{environments/environments.service.js → devices/devices.service.js} +122 -122
  65. package/dist/devices/dto.d.ts +13 -54
  66. package/dist/devices/dto.js +7 -39
  67. package/dist/devices/label.d.ts +11 -0
  68. package/dist/{environments → devices}/label.js +7 -7
  69. package/dist/{environments → devices}/legacy-cleanup.job.d.ts +3 -3
  70. package/dist/{environments → devices}/legacy-cleanup.job.js +3 -3
  71. package/dist/errors.d.ts +27 -25
  72. package/dist/errors.js +27 -25
  73. package/dist/evals/recorded-tools.d.ts +2 -2
  74. package/dist/evals/recorded-tools.js +6 -6
  75. package/dist/extensions/admin-ops.js +1 -0
  76. package/dist/extensions/admin-view.js +2 -0
  77. package/dist/extensions/effective-config.d.ts +6 -0
  78. package/dist/extensions/effective-config.js +18 -7
  79. package/dist/extensions/host.d.ts +13 -2
  80. package/dist/extensions/host.js +24 -3
  81. package/dist/extensions/instance.d.ts +12 -1
  82. package/dist/extensions/instance.js +13 -0
  83. package/dist/extensions/permission-view.d.ts +10 -1
  84. package/dist/files/previewers.d.ts +1 -1
  85. package/dist/files/previewers.js +1 -1
  86. package/dist/http/api.module.js +10 -6
  87. package/dist/http/gateway-routes.d.ts +1 -1
  88. package/dist/http/gateway-routes.js +1 -1
  89. package/dist/identity/settings.d.ts +32 -0
  90. package/dist/identity/settings.js +26 -2
  91. package/dist/infra/config/kernel-config.service.js +4 -4
  92. package/dist/kernel.module.js +3 -3
  93. package/dist/{devices → local-devices}/device-auth.controller.d.ts +6 -6
  94. package/dist/{devices → local-devices}/device-auth.controller.js +5 -5
  95. package/dist/{devices → local-devices}/device-auth.d.ts +20 -20
  96. package/dist/{devices → local-devices}/device-auth.js +51 -53
  97. package/dist/local-devices/device-auth.module.d.ts +7 -0
  98. package/dist/{devices → local-devices}/device-auth.module.js +5 -5
  99. package/dist/{devices → local-devices}/device-routes.d.ts +3 -3
  100. package/dist/{devices → local-devices}/device-routes.js +2 -2
  101. package/dist/local-devices/dto.d.ts +66 -0
  102. package/dist/local-devices/dto.js +44 -0
  103. package/dist/{devices → local-devices}/keys.d.ts +11 -11
  104. package/dist/{devices → local-devices}/keys.js +11 -11
  105. package/dist/{devices/device-gateway.d.ts → local-devices/local-device-gateway.d.ts} +14 -14
  106. package/dist/{devices/device-gateway.js → local-devices/local-device-gateway.js} +44 -44
  107. package/dist/{devices/device-provider.d.ts → local-devices/local-device-provider.d.ts} +15 -15
  108. package/dist/{devices/device-provider.js → local-devices/local-device-provider.js} +23 -23
  109. package/dist/local-devices/local-devices.module.d.ts +16 -0
  110. package/dist/local-devices/local-devices.module.js +44 -0
  111. package/dist/{devices → local-devices}/machines.d.ts +26 -26
  112. package/dist/{devices → local-devices}/machines.js +71 -71
  113. package/dist/{devices → local-devices}/relay.d.ts +15 -15
  114. package/dist/{devices → local-devices}/relay.js +55 -55
  115. package/dist/{devices → local-devices}/targets.d.ts +8 -8
  116. package/dist/{devices → local-devices}/targets.js +14 -14
  117. package/dist/orgs/offboarding.d.ts +6 -6
  118. package/dist/orgs/offboarding.js +12 -12
  119. package/dist/orgs/settings.service.d.ts +28 -0
  120. package/dist/orgs/settings.service.js +20 -1
  121. package/dist/platform/exclusions.js +48 -3
  122. package/dist/platform/operation.js +6 -2
  123. package/dist/platform/ops/admin.ops.js +8 -2
  124. package/dist/platform/ops/agents.ops.js +19 -6
  125. package/dist/platform/ops/conversations.ops.d.ts +3 -3
  126. package/dist/platform/ops/conversations.ops.js +9 -9
  127. package/dist/platform/ops/devices.ops.d.ts +26 -0
  128. package/dist/platform/ops/devices.ops.js +311 -0
  129. package/dist/platform/ops/org-settings.ops.js +2 -2
  130. package/dist/platform/ops/orgs.ops.js +1 -0
  131. package/dist/platform/ops/ui.ops.d.ts +8 -0
  132. package/dist/platform/ops/ui.ops.js +41 -0
  133. package/dist/platform/platform-ops.module.d.ts +3 -2
  134. package/dist/platform/platform-ops.module.js +8 -5
  135. package/dist/platform/route-schemas.js +6 -3
  136. package/dist/roles/gateway-role.d.ts +3 -3
  137. package/dist/roles/gateway-role.js +4 -4
  138. package/dist/roles/gateway.module.d.ts +1 -1
  139. package/dist/roles/gateway.module.js +5 -5
  140. package/dist/roles/worker.module.js +1 -1
  141. package/dist/runtime/context/build.d.ts +1 -1
  142. package/dist/runtime/context/build.js +6 -6
  143. package/dist/runtime/context/compaction.js +1 -1
  144. package/dist/runtime/context/{environment-paths.d.ts → device-paths.d.ts} +11 -11
  145. package/dist/runtime/context/{environment-paths.js → device-paths.js} +13 -13
  146. package/dist/runtime/maintenance.d.ts +1 -1
  147. package/dist/runtime/subagents/definition.d.ts +3 -2
  148. package/dist/runtime/subagents/definition.js +2 -1
  149. package/dist/sandbox/jobs.d.ts +13 -13
  150. package/dist/sandbox/jobs.js +20 -20
  151. package/dist/sandbox/leases.d.ts +9 -9
  152. package/dist/sandbox/leases.js +14 -14
  153. package/dist/sandbox/providers.d.ts +8 -8
  154. package/dist/sandbox/providers.js +8 -8
  155. package/dist/sandbox/sandbox.module.d.ts +1 -1
  156. package/dist/sandbox/sandbox.module.js +1 -1
  157. package/dist/sandbox/sandbox.service.d.ts +76 -76
  158. package/dist/sandbox/sandbox.service.js +230 -230
  159. package/dist/tools/builtins/builtin-tools.d.ts +2 -2
  160. package/dist/tools/builtins/builtin-tools.js +5 -5
  161. package/dist/tools/builtins/platform.js +1 -1
  162. package/dist/tools/builtins/sandbox/bash.js +6 -6
  163. package/dist/tools/builtins/sandbox/common.d.ts +25 -25
  164. package/dist/tools/builtins/sandbox/common.js +51 -51
  165. package/dist/tools/builtins/sandbox/edit.js +2 -2
  166. package/dist/tools/builtins/sandbox/index.d.ts +1 -1
  167. package/dist/tools/builtins/sandbox/index.js +1 -1
  168. package/dist/tools/builtins/sandbox/task-output.d.ts +6 -6
  169. package/dist/tools/builtins/sandbox/task-output.js +10 -10
  170. package/dist/tools/builtins/sandbox/task-stop.js +2 -2
  171. package/dist/tools/builtins/sandbox/write.js +2 -2
  172. package/dist/tools/builtins/skill-load.d.ts +1 -1
  173. package/dist/tools/builtins/skill-load.js +2 -2
  174. package/dist/tools/connector-account-policies.d.ts +51 -0
  175. package/dist/tools/connector-account-policies.js +165 -0
  176. package/dist/tools/connectors.controller.d.ts +35 -4
  177. package/dist/tools/connectors.controller.js +66 -7
  178. package/dist/tools/connectors.schemas.d.ts +11 -0
  179. package/dist/tools/connectors.schemas.js +11 -0
  180. package/dist/tools/connectors.service.d.ts +2 -0
  181. package/dist/tools/connectors.service.js +1 -0
  182. package/dist/tools/pipeline.d.ts +1 -1
  183. package/dist/tools/pipeline.js +4 -3
  184. package/dist/tools/policy.d.ts +23 -1
  185. package/dist/tools/policy.js +99 -24
  186. package/dist/tools/registry.d.ts +2 -2
  187. package/dist/tools/tools.module.js +6 -3
  188. package/dist/ui/admin-ui.controller.d.ts +56 -0
  189. package/dist/ui/admin-ui.controller.js +192 -0
  190. package/dist/ui/arrangement.d.ts +74 -0
  191. package/dist/ui/arrangement.js +98 -0
  192. package/dist/ui/embed-token.d.ts +2 -2
  193. package/dist/ui/embed-token.js +30 -5
  194. package/dist/ui/registry.d.ts +29 -14
  195. package/dist/ui/registry.js +31 -10
  196. package/dist/ui/slots.controller.d.ts +11 -0
  197. package/dist/ui/slots.controller.js +25 -0
  198. package/dist/ui/ui-stream.d.ts +20 -3
  199. package/dist/ui/ui-stream.js +25 -7
  200. package/dist/ui/ui.schemas.d.ts +66 -0
  201. package/dist/ui/ui.schemas.js +65 -0
  202. package/dist/ui/views.controller.d.ts +35 -49
  203. package/dist/ui/views.controller.js +48 -70
  204. package/dist/ui/views.d.ts +84 -18
  205. package/dist/ui/views.js +201 -38
  206. package/package.json +3 -3
  207. package/src/migrations/0104_connector_tool_account_policies.sql +16 -0
  208. package/src/migrations/0105_devices_rename.sql +136 -0
  209. package/dist/devices/device-auth.module.d.ts +0 -7
  210. package/dist/environments/conversation-environments.d.ts +0 -75
  211. package/dist/environments/dto.d.ts +0 -25
  212. package/dist/environments/dto.js +0 -12
  213. package/dist/environments/environments.controller.d.ts +0 -36
  214. package/dist/environments/environments.module.d.ts +0 -8
  215. package/dist/environments/environments.module.js +0 -31
  216. package/dist/environments/environments.schemas.d.ts +0 -3
  217. package/dist/environments/environments.schemas.js +0 -14
  218. package/dist/environments/label.d.ts +0 -11
  219. package/dist/platform/ops/environments.ops.d.ts +0 -26
  220. package/dist/platform/ops/environments.ops.js +0 -311
@@ -10,8 +10,6 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
10
10
  import { randomUUID } from "node:crypto";
11
11
  import { Inject, Injectable } from "@nestjs/common";
12
12
  import { sql } from "kysely";
13
- import { deviceLeaseKey } from "../devices/keys.js";
14
- import { MachinesService } from "../devices/machines.js";
15
13
  import { ApiError } from "../errors.js";
16
14
  import { ExtensionDisplayNames } from "../extensions/display-name.js";
17
15
  import { audit } from "../identity/audit.js";
@@ -22,23 +20,25 @@ import { TransactionHost } from "../infra/database/transaction-host.js";
22
20
  import { Transactional } from "../infra/database/transactional.decorator.js";
23
21
  import { LockService } from "../infra/lock/lock.service.js";
24
22
  import { KERNEL_LOGGER } from "../infra/tokens.js";
23
+ import { deviceLeaseKey } from "../local-devices/keys.js";
24
+ import { MachinesService } from "../local-devices/machines.js";
25
25
  import { SandboxJobs } from "../sandbox/jobs.js";
26
- import { DEVICE_PROVIDER, isInternalProvider, SandboxProviders } from "../sandbox/providers.js";
27
- import { environmentNotFound, SandboxService } from "../sandbox/sandbox.service.js";
28
- import { demotedProvider, EnvironmentAccess, environmentProvider, environmentUnavailable, inUseForDefault, } from "./access.js";
26
+ import { isInternalProvider, LOCAL_PROVIDER, SandboxProviders } from "../sandbox/providers.js";
27
+ import { deviceNotFound, SandboxService } from "../sandbox/sandbox.service.js";
28
+ import { DeviceAccess, demotedProvider, deviceProvider, deviceUnavailable, inUseForDefault, } from "./access.js";
29
29
  const isUniqueViolation = (e, constraint) => typeof e === "object" &&
30
30
  e !== null &&
31
31
  e.code === "23505" &&
32
32
  e.constraint === constraint;
33
- const nameTaken = () => new ApiError("environment.name_taken", "You already have an environment with this name");
33
+ const nameTaken = () => new ApiError("device.name_taken", "You already have a device with this name");
34
34
  /**
35
- * Personal environments (spec 2026-11-07-environments-design §4.2 items 7, 12, 13; §6; §9):
35
+ * Personal devices (spec 2026-11-07-environments-design §4.2 items 7, 12, 13; §6; §9):
36
36
  * cloud ones on the deployment's sandbox provider and `device` ones on a connected machine; a
37
- * person's environments in an org, visible and usable only by their owner (anyone else gets
38
- * `environment.not_found`). Deleting one soft-deletes it and destroys its instance and files in a
37
+ * person's devices in an org, visible and usable only by their owner (anyone else gets
38
+ * `device.not_found`). Deleting one soft-deletes it and destroys its instance and files in a
39
39
  * `sandbox-destroy-for` job after the commit.
40
40
  */
41
- let EnvironmentsService = class EnvironmentsService {
41
+ let DevicesService = class DevicesService {
42
42
  db;
43
43
  txHost;
44
44
  config;
@@ -66,8 +66,8 @@ let EnvironmentsService = class EnvironmentsService {
66
66
  this.machines = machines;
67
67
  }
68
68
  /**
69
- * The person's live environments in the org, the default first, then by creation. With a
70
- * current sandbox provider the default environment is created first if missing (its first need,
69
+ * The person's live devices in the org, the default first, then by creation. With a
70
+ * current sandbox provider the default device is created first if missing (its first need,
71
71
  * spec §4.2 item 7; an existing one is only read).
72
72
  */
73
73
  async list(orgId, accountId) {
@@ -76,8 +76,8 @@ let EnvironmentsService = class EnvironmentsService {
76
76
  const items = await this.views(orgId, accountId);
77
77
  const last = await this.db
78
78
  .selectFrom("conversations as c")
79
- .innerJoin("environments as e", "e.id", "c.environment_id")
80
- .select("c.environment_id")
79
+ .innerJoin("devices as e", "e.id", "c.device_id")
80
+ .select("c.device_id")
81
81
  .where("c.org_id", "=", orgId)
82
82
  .where("c.account_id", "=", accountId)
83
83
  .where("e.org_id", "=", orgId)
@@ -90,22 +90,22 @@ let EnvironmentsService = class EnvironmentsService {
90
90
  return {
91
91
  items,
92
92
  defaultId: defaultId ?? items.find((v) => v.isDefault)?.id ?? null,
93
- lastUsedId: last?.environment_id ?? null,
93
+ lastUsedId: last?.device_id ?? null,
94
94
  cloudAvailable,
95
95
  };
96
96
  }
97
- /** One of the person's live environments; anyone else's (or a missing one) → `not_found`. */
97
+ /** One of the person's live devices; anyone else's (or a missing one) → `not_found`. */
98
98
  async get(orgId, accountId, id) {
99
99
  const [view] = await this.views(orgId, accountId, id);
100
100
  if (!view)
101
- throw environmentNotFound();
101
+ throw deviceNotFound();
102
102
  return view;
103
103
  }
104
104
  /**
105
- * A new personal cloud environment, ready at once (its instance and files are made on first
106
- * use). Needs a current sandbox provider (`environment.unavailable`); a live name of the person's
107
- * (case-insensitive) → `environment.name_taken`; `environments.maxPersonal` live ones (the
108
- * default counts) → `environment.limit_reached`. Serialized per person by their membership row.
105
+ * A new personal cloud device, ready at once (its instance and files are made on first
106
+ * use). Needs a current sandbox provider (`device.unavailable`); a live name of the person's
107
+ * (case-insensitive) → `device.name_taken`; `devices.maxPersonal` live ones (the
108
+ * default counts) → `device.limit_reached`. Serialized per person by their membership row.
109
109
  */
110
110
  async create(orgId, accountId, input, actorTokenId, auditDetail) {
111
111
  const id = await this.insert(orgId, accountId, input.name, actorTokenId, auditDetail);
@@ -114,44 +114,44 @@ let EnvironmentsService = class EnvironmentsService {
114
114
  async insert(orgId, accountId, name, actorTokenId, auditDetail) {
115
115
  const current = this.providers.cloud();
116
116
  if (!current)
117
- throw environmentUnavailable(null);
117
+ throw deviceUnavailable(null);
118
118
  return this.insertNamed(orgId, accountId, name, "cloud", current.plugin, actorTokenId, auditDetail ?? {});
119
119
  }
120
120
  /**
121
- * A new personal `device` environment for a machine being connected (provider `@device`; the
121
+ * A new personal local device for a machine being connected (provider `@local`; the
122
122
  * machine row is the caller's). Joins the caller's transaction (the device authorization's).
123
- * Counted against `environments.maxPersonal` (`environment.limit_reached`); a live name of the
124
- * person's → `environment.name_taken`. Needs no cloud provider.
123
+ * Counted against `devices.maxPersonal` (`device.limit_reached`); a live name of the
124
+ * person's → `device.name_taken`. Needs no cloud provider.
125
125
  */
126
- async createDevice(orgId, accountId, name) {
127
- const id = await this.insertNamed(orgId, accountId, name, "device", DEVICE_PROVIDER, undefined, {
128
- source: "device",
126
+ async createLocal(orgId, accountId, name) {
127
+ const id = await this.insertNamed(orgId, accountId, name, "local", LOCAL_PROVIDER, undefined, {
128
+ source: "local",
129
129
  });
130
130
  return { id };
131
131
  }
132
132
  /**
133
- * Inserts a named personal environment under the person's membership lock, after the limit
134
- * and name checks, and audits `environment.created`. Runs in the caller's transaction.
133
+ * Inserts a named personal device under the person's membership lock, after the limit
134
+ * and name checks, and audits `device.created`. Runs in the caller's transaction.
135
135
  */
136
136
  async insertNamed(orgId, accountId, name, source, provider, actorTokenId, auditDetail) {
137
137
  await this.lockMember(orgId, accountId);
138
138
  const { n } = await this.db
139
- .selectFrom("environments")
139
+ .selectFrom("devices")
140
140
  .select((eb) => eb.fn.countAll().as("n"))
141
141
  .where("org_id", "=", orgId)
142
142
  .where("owner_kind", "=", "personal")
143
143
  .where("owner_account_id", "=", accountId)
144
144
  .where("deleted_at", "is", null)
145
145
  .executeTakeFirstOrThrow();
146
- const max = this.config.get().environments.maxPersonal;
146
+ const max = this.config.get().devices.maxPersonal;
147
147
  if (Number(n) >= max) {
148
- throw new ApiError("environment.limit_reached", `You already have ${max} environments in this organization; delete one to create another`);
148
+ throw new ApiError("device.limit_reached", `You already have ${max} devices in this organization; delete one to create another`);
149
149
  }
150
150
  await this.assertNameFree(orgId, accountId, name);
151
151
  const id = randomUUID();
152
152
  try {
153
153
  await this.db
154
- .insertInto("environments")
154
+ .insertInto("devices")
155
155
  .values({
156
156
  id,
157
157
  org_id: orgId,
@@ -164,7 +164,7 @@ let EnvironmentsService = class EnvironmentsService {
164
164
  .execute();
165
165
  }
166
166
  catch (e) {
167
- if (isUniqueViolation(e, "environments_name_uq"))
167
+ if (isUniqueViolation(e, "devices_name_uq"))
168
168
  throw nameTaken();
169
169
  throw e;
170
170
  }
@@ -172,7 +172,7 @@ let EnvironmentsService = class EnvironmentsService {
172
172
  actorAccountId: accountId,
173
173
  ...(actorTokenId !== undefined && { actorTokenId }),
174
174
  orgId,
175
- action: "environment.created",
175
+ action: "device.created",
176
176
  target: id,
177
177
  detail: { name, ...auditDetail },
178
178
  });
@@ -185,35 +185,35 @@ let EnvironmentsService = class EnvironmentsService {
185
185
  */
186
186
  async checkCreate(orgId, accountId, name) {
187
187
  if (!this.providers.cloud())
188
- throw environmentUnavailable(null);
188
+ throw deviceUnavailable(null);
189
189
  const { n } = await this.db
190
- .selectFrom("environments")
190
+ .selectFrom("devices")
191
191
  .select((eb) => eb.fn.countAll().as("n"))
192
192
  .where("org_id", "=", orgId)
193
193
  .where("owner_kind", "=", "personal")
194
194
  .where("owner_account_id", "=", accountId)
195
195
  .where("deleted_at", "is", null)
196
196
  .executeTakeFirstOrThrow();
197
- const max = this.config.get().environments.maxPersonal;
197
+ const max = this.config.get().devices.maxPersonal;
198
198
  if (Number(n) >= max) {
199
- throw new ApiError("environment.limit_reached", `You already have ${max} environments in this organization; delete one to create another`);
199
+ throw new ApiError("device.limit_reached", `You already have ${max} devices in this organization; delete one to create another`);
200
200
  }
201
201
  await this.assertNameFree(orgId, accountId, name);
202
202
  }
203
- /** How many of the person's conversations work in the environment (read only). */
203
+ /** How many of the person's conversations work in the device (read only). */
204
204
  async boundConversations(orgId, accountId, id) {
205
205
  const { n } = await this.db
206
206
  .selectFrom("conversations")
207
207
  .select((eb) => eb.fn.countAll().as("n"))
208
208
  .where("org_id", "=", orgId)
209
209
  .where("account_id", "=", accountId)
210
- .where("environment_id", "=", id)
210
+ .where("device_id", "=", id)
211
211
  .executeTakeFirstOrThrow();
212
212
  return Number(n);
213
213
  }
214
214
  /**
215
215
  * The refusals {@link resetFiles} would raise (not found, its provider not current, a connected
216
- * environment), read only.
216
+ * device), read only.
217
217
  */
218
218
  async checkReset(orgId, accountId, id) {
219
219
  refuseDeviceReset(await this.access.usable(orgId, accountId, id));
@@ -226,7 +226,7 @@ let EnvironmentsService = class EnvironmentsService {
226
226
  }
227
227
  }
228
228
  /**
229
- * Renames one of the person's live environments (the default too); see {@link create}. A
229
+ * Renames one of the person's live devices (the default too); see {@link create}. A
230
230
  * renamed former default is the person's own from then on: it loses its demotion mark, so a
231
231
  * switch back to its provider no longer restores it.
232
232
  */
@@ -238,19 +238,19 @@ let EnvironmentsService = class EnvironmentsService {
238
238
  const before = await this.lockOwn(orgId, accountId, id);
239
239
  if (before.name === name)
240
240
  return;
241
- // the same name in another case is this environment's own: the index allows it
241
+ // the same name in another case is this device's own: the index allows it
242
242
  if (before.name?.toLowerCase() !== name.toLowerCase()) {
243
243
  await this.assertNameFree(orgId, accountId, name);
244
244
  }
245
245
  try {
246
246
  await this.db
247
- .updateTable("environments")
247
+ .updateTable("devices")
248
248
  .set({ name, demoted_from_provider: null, updated_at: sql `now()` })
249
249
  .where("id", "=", id)
250
250
  .execute();
251
251
  }
252
252
  catch (e) {
253
- if (isUniqueViolation(e, "environments_name_uq"))
253
+ if (isUniqueViolation(e, "devices_name_uq"))
254
254
  throw nameTaken();
255
255
  throw e;
256
256
  }
@@ -258,38 +258,38 @@ let EnvironmentsService = class EnvironmentsService {
258
258
  actorAccountId: accountId,
259
259
  ...(actorTokenId !== undefined && { actorTokenId }),
260
260
  orgId,
261
- action: "environment.renamed",
261
+ action: "device.renamed",
262
262
  target: id,
263
263
  detail: { from: before.name, to: name, ...auditDetail },
264
264
  });
265
265
  }
266
266
  /**
267
- * Deletes one of the person's live environments: soft delete, its IM default row cleared, and
267
+ * Deletes one of the person's live devices: soft delete, its IM default row cleared, and
268
268
  * after the commit a `sandbox-destroy-for` job (the worker waits for running commands, then
269
269
  * destroys the instance and the files). Conversations bound to it keep pointing at it; their
270
- * sandbox tools then fail with `environment.not_found`. A device environment's machine is
270
+ * sandbox tools then fail with `device.not_found`. A local device's machine is
271
271
  * revoked in the same transaction; after the commit it is told `stop { reason: "deleted" }`
272
272
  * (while connected) and its connection is closed.
273
273
  */
274
274
  async remove(orgId, accountId, id, actorTokenId, auditDetail) {
275
275
  const before = await this.lockOwn(orgId, accountId, id);
276
276
  await this.db
277
- .updateTable("environments")
277
+ .updateTable("devices")
278
278
  .set({ deleted_at: sql `now()`, updated_at: sql `now()` })
279
279
  .where("id", "=", id)
280
280
  .execute();
281
281
  await this.db
282
- .deleteFrom("environment_defaults")
282
+ .deleteFrom("device_defaults")
283
283
  .where("org_id", "=", orgId)
284
284
  .where("account_id", "=", accountId)
285
- .where("environment_id", "=", id)
285
+ .where("device_id", "=", id)
286
286
  .execute();
287
287
  await this.machines.revokeActive(id, "deleted");
288
288
  await audit(this.db.db, {
289
289
  actorAccountId: accountId,
290
290
  ...(actorTokenId !== undefined && { actorTokenId }),
291
291
  orgId,
292
- action: "environment.deleted",
292
+ action: "device.deleted",
293
293
  target: id,
294
294
  detail: { name: before.name, isDefault: before.is_default, ...auditDetail },
295
295
  });
@@ -298,25 +298,25 @@ let EnvironmentsService = class EnvironmentsService {
298
298
  await this.sandboxJobs.destroy([id]);
299
299
  }
300
300
  catch (err) {
301
- // the hourly destruction sweep destroys deleted environments too
302
- this.log.warn("cannot schedule environment destruction", { environmentId: id, err });
301
+ // the hourly destruction sweep destroys deleted devices too
302
+ this.log.warn("cannot schedule device destruction", { deviceId: id, err });
303
303
  }
304
304
  });
305
305
  }
306
306
  /**
307
- * Disconnects the machine of one of the person's own device environments (it must sign in
307
+ * Disconnects the machine of one of the person's own local devices (it must sign in
308
308
  * again); see {@link MachinesService.revoke}.
309
309
  */
310
310
  async revokeMachine(orgId, accountId, id, actorTokenId) {
311
311
  await this.machines.revoke(orgId, accountId, id, actorTokenId);
312
312
  }
313
313
  /**
314
- * Starts one of the person's environments over with empty files (after
315
- * `environment.files_lost`): records the request (audit), then, after the commit, enqueues the
316
- * `sandbox-reset-files` job (deterministic id per environment), whose worker waits for running
314
+ * Starts one of the person's devices over with empty files (after
315
+ * `device.files_lost`): records the request (audit), then, after the commit, enqueues the
316
+ * `sandbox-reset-files` job (deterministic id per device), whose worker waits for running
317
317
  * commands and destroys any instance and the file system; the next use creates new ones. Its
318
- * provider must be the current one (`environment.unavailable`); a connected environment's files
319
- * are its machine owner's (`environment.files_on_device`). An enqueue failure is thrown
318
+ * provider must be the current one (`device.unavailable`); a local device's files
319
+ * are its machine owner's (`device.files_on_device`). An enqueue failure is thrown
320
320
  * (the request can be repeated: the reset is idempotent).
321
321
  */
322
322
  async resetFiles(orgId, accountId, id, actorTokenId, auditDetail) {
@@ -330,17 +330,17 @@ let EnvironmentsService = class EnvironmentsService {
330
330
  actorAccountId: accountId,
331
331
  ...(actorTokenId !== undefined && { actorTokenId }),
332
332
  orgId,
333
- action: "environment.files_reset",
333
+ action: "device.files_reset",
334
334
  target: id,
335
335
  ...(auditDetail !== undefined && { detail: auditDetail }),
336
336
  });
337
337
  }
338
338
  /**
339
- * The person's default environment in the org, created when missing (named by the UI, `name`
339
+ * The person's default device in the org, created when missing (named by the UI, `name`
340
340
  * NULL). An existing usable one is read without locking. A live default whose files or
341
341
  * instance are kept by a provider that is not the current one (a provider switch, spec §4.2
342
342
  * item 13) is stranded: it is demoted (marked with the provider it was demoted from; the UI
343
- * names it 「个人环境(<provider display name>)」) and stays listed as unavailable and deletable.
343
+ * names it 「个人设备(<provider display name>)」) and stays listed as unavailable and deletable.
344
344
  * Its replacement is the person's former default demoted from the current provider when there
345
345
  * is one (switching back restores it, with its files), else a fresh default. A live default
346
346
  * not in use yet (no healthy files, no instance, none being created: {@link inUseForDefault})
@@ -349,7 +349,7 @@ let EnvironmentsService = class EnvironmentsService {
349
349
  * belongs to the provider holding its resources once it holds any, else to the one it was
350
350
  * demoted from ({@link demotedProvider}), so one swapped out empty and used afterwards is
351
351
  * labelled and restored by where its files are.
352
- * All of it in one transaction: switching back and forth never adds environments.
352
+ * All of it in one transaction: switching back and forth never adds devices.
353
353
  *
354
354
  * Replacing one first takes the person's membership row (`FOR SHARE`, after the org row), so an
355
355
  * offboarding that removes them cannot leave a live default behind; not a member (any more) →
@@ -357,8 +357,8 @@ let EnvironmentsService = class EnvironmentsService {
357
357
  * defaults of the current provider are locked (`FOR NO KEY UPDATE`) and the live default re-read
358
358
  * after them, the partial unique index on the live default makes a racing insert do nothing, and
359
359
  * the select that follows reads the winner. Needs a current sandbox provider
360
- * (`environment.unavailable`). It is the person's baseline, so it is created even at
361
- * `environments.maxPersonal`.
360
+ * (`device.unavailable`). It is the person's baseline, so it is created even at
361
+ * `devices.maxPersonal`.
362
362
  */
363
363
  async ensureDefault(orgId, accountId) {
364
364
  const live = await this.defaultOf(orgId, accountId);
@@ -375,7 +375,7 @@ let EnvironmentsService = class EnvironmentsService {
375
375
  async insertDefault(orgId, accountId) {
376
376
  const current = this.providers.cloud();
377
377
  if (!current)
378
- throw environmentUnavailable(null);
378
+ throw deviceUnavailable(null);
379
379
  await this.lockMember(orgId, accountId, "share");
380
380
  const locked = await this.defaultOf(orgId, accountId, true);
381
381
  const former = await this.formerDefaults(orgId, accountId, current.plugin, true);
@@ -391,20 +391,20 @@ let EnvironmentsService = class EnvironmentsService {
391
391
  const restore = withFiles ?? (live === undefined || stranded ? former[0] : undefined);
392
392
  if (live) {
393
393
  const from = stranded
394
- ? (environmentProvider(live, current.plugin) ?? "unknown")
394
+ ? (deviceProvider(live, current.plugin) ?? "unknown")
395
395
  : (live.provider ?? current.plugin);
396
396
  await this.demote(live.id, from);
397
397
  }
398
398
  if (restore) {
399
399
  await this.db
400
- .updateTable("environments")
400
+ .updateTable("devices")
401
401
  .set({ is_default: true, demoted_from_provider: null, updated_at: sql `now()` })
402
402
  .where("id", "=", restore.id)
403
403
  .execute();
404
404
  return restore.id;
405
405
  }
406
406
  await this.db
407
- .insertInto("environments")
407
+ .insertInto("devices")
408
408
  .values({
409
409
  id: randomUUID(),
410
410
  org_id: orgId,
@@ -422,17 +422,17 @@ let EnvironmentsService = class EnvironmentsService {
422
422
  .execute();
423
423
  const row = await this.defaultOf(orgId, accountId);
424
424
  if (row === undefined)
425
- throw new Error("the default environment was not created");
425
+ throw new Error("the default device was not created");
426
426
  return row.id;
427
427
  }
428
428
  /**
429
- * Turns the live default into an ordinary environment marked as demoted from `provider`; a name
429
+ * Turns the live default into an ordinary device marked as demoted from `provider`; a name
430
430
  * the person gave it stays. Runs under the person's membership lock and the default row's lock,
431
431
  * before any other row becomes the default (the partial unique index).
432
432
  */
433
433
  async demote(id, provider) {
434
434
  await this.db
435
- .updateTable("environments")
435
+ .updateTable("devices")
436
436
  .set({ is_default: false, demoted_from_provider: provider, updated_at: sql `now()` })
437
437
  .where("id", "=", id)
438
438
  .execute();
@@ -446,8 +446,8 @@ let EnvironmentsService = class EnvironmentsService {
446
446
  */
447
447
  async formerDefaults(orgId, accountId, provider, lock = false) {
448
448
  const rows = await this.db
449
- .selectFrom("environments as e")
450
- .leftJoin("environment_instances as i", "i.environment_id", "e.id")
449
+ .selectFrom("devices as e")
450
+ .leftJoin("device_instances as i", "i.device_id", "e.id")
451
451
  .select([
452
452
  "e.id",
453
453
  "e.provider",
@@ -491,13 +491,13 @@ let EnvironmentsService = class EnvironmentsService {
491
491
  .map(({ r, holdsFiles }) => ({ id: r.id, holdsFiles }));
492
492
  }
493
493
  /**
494
- * The person's IM default (what `/env` set): the environment their next new IM conversation
494
+ * The person's IM default (what `/device` set): the device their next new IM conversation
495
495
  * uses. Null when none was set, or the chosen one is deleted (the row is cleared with it).
496
496
  */
497
497
  async imDefault(orgId, accountId) {
498
498
  const row = await this.db
499
- .selectFrom("environment_defaults as d")
500
- .innerJoin("environments as e", "e.id", "d.environment_id")
499
+ .selectFrom("device_defaults as d")
500
+ .innerJoin("devices as e", "e.id", "d.device_id")
501
501
  .select("e.id")
502
502
  .where("d.org_id", "=", orgId)
503
503
  .where("d.account_id", "=", accountId)
@@ -509,44 +509,44 @@ let EnvironmentsService = class EnvironmentsService {
509
509
  return row?.id ?? null;
510
510
  }
511
511
  /**
512
- * Sets the person's IM default. Only one of their own live environments in the org, usable now
513
- * (`environment.not_found` / `environment.unavailable` otherwise); the row is written by one
514
- * statement that re-checks the environment is live. There is no row lock, so a delete racing
512
+ * Sets the person's IM default. Only one of their own live devices in the org, usable now
513
+ * (`device.not_found` / `device.unavailable` otherwise); the row is written by one
514
+ * statement that re-checks the device is live. There is no row lock, so a delete racing
515
515
  * past that check can leave a stale row; reads ignore it ({@link imDefault} joins on
516
516
  * `deleted_at IS NULL`).
517
517
  */
518
- async setImDefault(orgId, accountId, environmentId) {
519
- await this.access.usable(orgId, accountId, environmentId);
518
+ async setImDefault(orgId, accountId, deviceId) {
519
+ await this.access.usable(orgId, accountId, deviceId);
520
520
  const written = await this.db
521
- .insertInto("environment_defaults")
522
- .columns(["org_id", "account_id", "environment_id"])
521
+ .insertInto("device_defaults")
522
+ .columns(["org_id", "account_id", "device_id"])
523
523
  .expression(this.db
524
- .selectFrom("environments")
524
+ .selectFrom("devices")
525
525
  .select([
526
526
  sql `${orgId}::text`.as("org_id"),
527
527
  sql `${accountId}::text`.as("account_id"),
528
528
  "id",
529
529
  ])
530
- .where("id", "=", environmentId)
530
+ .where("id", "=", deviceId)
531
531
  .where("org_id", "=", orgId)
532
532
  .where("owner_kind", "=", "personal")
533
533
  .where("owner_account_id", "=", accountId)
534
534
  .where("deleted_at", "is", null))
535
535
  .onConflict((oc) => oc
536
536
  .columns(["org_id", "account_id"])
537
- .doUpdateSet({ environment_id: environmentId, updated_at: new Date() }))
537
+ .doUpdateSet({ device_id: deviceId, updated_at: new Date() }))
538
538
  .executeTakeFirst();
539
539
  if (Number(written.numInsertedOrUpdatedRows ?? 0) === 0)
540
- throw environmentNotFound();
540
+ throw deviceNotFound();
541
541
  }
542
542
  /**
543
- * The person's live default environment in the org, if any, with what decides its provider;
543
+ * The person's live default device in the org, if any, with what decides its provider;
544
544
  * `lock` takes its row (`FOR NO KEY UPDATE`; a racing demotion makes it read none).
545
545
  */
546
546
  async defaultOf(orgId, accountId, lock = false) {
547
547
  const row = await this.db
548
- .selectFrom("environments as e")
549
- .leftJoin("environment_instances as i", "i.environment_id", "e.id")
548
+ .selectFrom("devices as e")
549
+ .leftJoin("device_instances as i", "i.device_id", "e.id")
550
550
  .select([
551
551
  "e.id",
552
552
  "e.provider",
@@ -574,15 +574,15 @@ let EnvironmentsService = class EnvironmentsService {
574
574
  /** Its files or instance are kept by a provider that is not the current one. */
575
575
  stranded(f) {
576
576
  const current = this.providers.cloud()?.plugin;
577
- return current !== undefined && environmentProvider(f, current) !== current;
577
+ return current !== undefined && deviceProvider(f, current) !== current;
578
578
  }
579
- /** The person's live environments (or the one `id`) as views. */
579
+ /** The person's live devices (or the one `id`) as views. */
580
580
  async views(orgId, accountId, id) {
581
581
  // all of them even for one `id`: a former default's ordinal counts its siblings
582
582
  const all = await this.db
583
- .selectFrom("environments as e")
584
- .leftJoin("environment_instances as i", "i.environment_id", "e.id")
585
- .leftJoin("environment_machines as m", (j) => j.onRef("m.environment_id", "=", "e.id").on("m.revoked_at", "is", null))
583
+ .selectFrom("devices as e")
584
+ .leftJoin("device_instances as i", "i.device_id", "e.id")
585
+ .leftJoin("device_machines as m", (j) => j.onRef("m.device_id", "=", "e.id").on("m.revoked_at", "is", null))
586
586
  .select([
587
587
  "e.id",
588
588
  "e.name",
@@ -641,12 +641,12 @@ let EnvironmentsService = class EnvironmentsService {
641
641
  this.displayNames.many(demotedProviders),
642
642
  ]);
643
643
  const current = this.providers.cloud()?.plugin;
644
- // a device environment is online while a replica holds its machine's connection lease
644
+ // a local device is online while a replica holds its machine's connection lease
645
645
  const online = new Map(await Promise.all(rows
646
- .filter((r) => r.source === "device")
646
+ .filter((r) => r.source === "local")
647
647
  .map(async (r) => [r.id, (await this.locks.holderOf(deviceLeaseKey(r.id))) !== null])));
648
648
  return rows.map((r) => {
649
- const provider = environmentProvider(factsOf(r), current);
649
+ const provider = deviceProvider(factsOf(r), current);
650
650
  const live = (r.status === "running" || r.status === "suspended") && r.last_used_at;
651
651
  const from = demoted.get(r.id) ?? null;
652
652
  return {
@@ -666,7 +666,7 @@ let EnvironmentsService = class EnvironmentsService {
666
666
  available: provider !== null && isInternalProvider(provider)
667
667
  ? this.providers.forName(provider) !== undefined
668
668
  : current !== undefined && provider === current,
669
- online: r.source === "device" ? (online.get(r.id) ?? false) : null,
669
+ online: r.source === "local" ? (online.get(r.id) ?? false) : null,
670
670
  machine: r.machine_id !== null && r.machine_name !== null && r.machine_os !== null
671
671
  ? {
672
672
  id: r.machine_id,
@@ -677,7 +677,7 @@ let EnvironmentsService = class EnvironmentsService {
677
677
  lastSeenAt: r.machine_last_seen_at?.toISOString() ?? null,
678
678
  }
679
679
  : null,
680
- // a device environment's machine decides it; cloud environments have none in phase 2
680
+ // a local device's machine decides it; cloud devices have none in phase 2
681
681
  sessionIsolation: r.machine_session_isolation ?? false,
682
682
  filesLost: r.fs_status === "lost",
683
683
  instance: live
@@ -692,7 +692,7 @@ let EnvironmentsService = class EnvironmentsService {
692
692
  });
693
693
  }
694
694
  /**
695
- * Serializes the person's environment writes in the org: the org row (`FOR SHARE`), then their
695
+ * Serializes the person's device writes in the org: the org row (`FOR SHARE`), then their
696
696
  * membership row (`FOR NO KEY UPDATE`, or `FOR SHARE` with `mode` share: enough to keep the
697
697
  * membership from being removed meanwhile), the order member removal locks them in. Not a
698
698
  * member (any more) → `org.not_found`, as the org guard answers.
@@ -717,11 +717,11 @@ let EnvironmentsService = class EnvironmentsService {
717
717
  if (!m)
718
718
  throw new ApiError("org.not_found", "Organization not found");
719
719
  }
720
- /** Locks one of the person's live environments (after their membership); else `not_found`. */
720
+ /** Locks one of the person's live devices (after their membership); else `not_found`. */
721
721
  async lockOwn(orgId, accountId, id) {
722
722
  await this.lockMember(orgId, accountId);
723
723
  const row = await this.db
724
- .selectFrom("environments")
724
+ .selectFrom("devices")
725
725
  .select(["name", "is_default"])
726
726
  .where("id", "=", id)
727
727
  .where("org_id", "=", orgId)
@@ -731,12 +731,12 @@ let EnvironmentsService = class EnvironmentsService {
731
731
  .forNoKeyUpdate()
732
732
  .executeTakeFirst();
733
733
  if (!row)
734
- throw environmentNotFound();
734
+ throw deviceNotFound();
735
735
  return row;
736
736
  }
737
737
  async assertNameFree(orgId, accountId, name) {
738
738
  const clash = await this.db
739
- .selectFrom("environments")
739
+ .selectFrom("devices")
740
740
  .select("id")
741
741
  .where("org_id", "=", orgId)
742
742
  .where("owner_account_id", "=", accountId)
@@ -749,23 +749,23 @@ let EnvironmentsService = class EnvironmentsService {
749
749
  };
750
750
  __decorate([
751
751
  Transactional()
752
- ], EnvironmentsService.prototype, "insert", null);
752
+ ], DevicesService.prototype, "insert", null);
753
753
  __decorate([
754
754
  Transactional()
755
- ], EnvironmentsService.prototype, "createDevice", null);
755
+ ], DevicesService.prototype, "createLocal", null);
756
756
  __decorate([
757
757
  Transactional()
758
- ], EnvironmentsService.prototype, "renameIn", null);
758
+ ], DevicesService.prototype, "renameIn", null);
759
759
  __decorate([
760
760
  Transactional()
761
- ], EnvironmentsService.prototype, "remove", null);
761
+ ], DevicesService.prototype, "remove", null);
762
762
  __decorate([
763
763
  Transactional()
764
- ], EnvironmentsService.prototype, "recordReset", null);
764
+ ], DevicesService.prototype, "recordReset", null);
765
765
  __decorate([
766
766
  Transactional()
767
- ], EnvironmentsService.prototype, "insertDefault", null);
768
- EnvironmentsService = __decorate([
767
+ ], DevicesService.prototype, "insertDefault", null);
768
+ DevicesService = __decorate([
769
769
  Injectable(),
770
770
  __param(0, Inject(KernelDb)),
771
771
  __param(1, Inject(TransactionHost)),
@@ -773,19 +773,19 @@ EnvironmentsService = __decorate([
773
773
  __param(3, Inject(SandboxProviders)),
774
774
  __param(4, Inject(SandboxService)),
775
775
  __param(5, Inject(SandboxJobs)),
776
- __param(6, Inject(EnvironmentAccess)),
776
+ __param(6, Inject(DeviceAccess)),
777
777
  __param(7, Inject(ExtensionDisplayNames)),
778
778
  __param(8, Inject(KERNEL_LOGGER)),
779
779
  __param(9, Inject(LockService)),
780
780
  __param(10, Inject(MachinesService))
781
- ], EnvironmentsService);
782
- export { EnvironmentsService };
781
+ ], DevicesService);
782
+ export { DevicesService };
783
783
  /**
784
- * Ruling R24: a connected environment's files are in a directory on its machine, which the
784
+ * Ruling R24: a local device's files are in a directory on its machine, which the
785
785
  * platform never wipes; a lost directory comes back with `capybara-device logout` and a new `login` on the machine.
786
786
  */
787
787
  function refuseDeviceReset(env) {
788
- if (env.provider === DEVICE_PROVIDER) {
789
- throw new ApiError("environment.files_on_device", "This environment's files are in a directory on its connected machine and cannot be reset from here. To start over, run capybara-device logout, then capybara-device login into this environment, on that machine.");
788
+ if (env.provider === LOCAL_PROVIDER) {
789
+ throw new ApiError("device.files_on_device", "This device's files are in a directory on its connected machine and cannot be reset from here. To start over, run capybara-device logout, then capybara-device login into this device, on that machine.");
790
790
  }
791
791
  }