@indigoai-us/hq-cli 5.126.0 → 5.128.0

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 (78) hide show
  1. package/CHANGELOG.md +218 -0
  2. package/assets/lanes-hooks/hq-lanes-drain.json +15 -0
  3. package/assets/lanes-hooks/hq-lanes-drain.mjs +254 -0
  4. package/assets/lanes-hooks/hq-lanes-drain.sh +21 -0
  5. package/assets/lanes-reconcile/hq-lanes-reconcile.service +11 -0
  6. package/assets/lanes-reconcile/hq-lanes-reconcile.timer +12 -0
  7. package/dist/command-catalog.generated.d.ts +245 -11
  8. package/dist/command-catalog.generated.js +323 -11
  9. package/dist/command-registration-plan.d.ts +1 -0
  10. package/dist/command-registration-plan.js +11 -2
  11. package/dist/commands/agents.d.ts +12 -0
  12. package/dist/commands/agents.js +46 -2
  13. package/dist/commands/lanes.d.ts +55 -16
  14. package/dist/commands/lanes.js +1187 -250
  15. package/dist/commands/mesh.js +254 -19
  16. package/dist/lib/core-utils/sentry-report.d.ts +2 -0
  17. package/dist/lib/core-utils/sentry-report.js +47 -7
  18. package/dist/lib/lanes/accounts.d.ts +67 -7
  19. package/dist/lib/lanes/accounts.js +233 -43
  20. package/dist/lib/lanes/compaction.d.ts +96 -0
  21. package/dist/lib/lanes/compaction.js +197 -0
  22. package/dist/lib/lanes/config.d.ts +15 -0
  23. package/dist/lib/lanes/config.js +65 -8
  24. package/dist/lib/lanes/delivery.d.ts +151 -0
  25. package/dist/lib/lanes/delivery.js +354 -0
  26. package/dist/lib/lanes/dropbox.d.ts +96 -0
  27. package/dist/lib/lanes/dropbox.js +408 -0
  28. package/dist/lib/lanes/effort.d.ts +50 -0
  29. package/dist/lib/lanes/effort.js +109 -0
  30. package/dist/lib/lanes/errors.d.ts +2 -2
  31. package/dist/lib/lanes/hooks-install.d.ts +81 -0
  32. package/dist/lib/lanes/hooks-install.js +326 -0
  33. package/dist/lib/lanes/hq-root.d.ts +19 -0
  34. package/dist/lib/lanes/hq-root.js +28 -0
  35. package/dist/lib/lanes/index.d.ts +35 -5
  36. package/dist/lib/lanes/index.js +19 -4
  37. package/dist/lib/lanes/liveness.d.ts +7 -1
  38. package/dist/lib/lanes/liveness.js +64 -5
  39. package/dist/lib/lanes/machine-identity.d.ts +34 -0
  40. package/dist/lib/lanes/machine-identity.js +92 -0
  41. package/dist/lib/lanes/mesh-events.d.ts +109 -0
  42. package/dist/lib/lanes/mesh-events.js +275 -0
  43. package/dist/lib/lanes/outpost-dispatch.d.ts +65 -0
  44. package/dist/lib/lanes/outpost-dispatch.js +90 -0
  45. package/dist/lib/lanes/questions.d.ts +75 -0
  46. package/dist/lib/lanes/questions.js +243 -0
  47. package/dist/lib/lanes/quota.d.ts +95 -0
  48. package/dist/lib/lanes/quota.js +320 -0
  49. package/dist/lib/lanes/reconcile-install.d.ts +69 -0
  50. package/dist/lib/lanes/reconcile-install.js +221 -0
  51. package/dist/lib/lanes/reconcile.d.ts +102 -0
  52. package/dist/lib/lanes/reconcile.js +985 -0
  53. package/dist/lib/lanes/registry.d.ts +18 -5
  54. package/dist/lib/lanes/registry.js +293 -19
  55. package/dist/lib/lanes/spawn.d.ts +274 -0
  56. package/dist/lib/lanes/spawn.js +1363 -0
  57. package/dist/lib/lanes/store.d.ts +7 -3
  58. package/dist/lib/lanes/store.js +150 -32
  59. package/dist/lib/lanes/types.d.ts +346 -4
  60. package/dist/lib/lanes/types.js +138 -5
  61. package/dist/lib/lanes/watcher-main.d.ts +9 -0
  62. package/dist/lib/lanes/watcher-main.js +22 -0
  63. package/dist/lib/lanes/watcher.d.ts +216 -0
  64. package/dist/lib/lanes/watcher.js +859 -0
  65. package/dist/lib/mesh/api.d.ts +71 -7
  66. package/dist/lib/mesh/api.js +167 -28
  67. package/dist/lib/mesh/live/backfill-held.d.ts +18 -7
  68. package/dist/lib/mesh/live/backfill-held.js +66 -21
  69. package/dist/lib/mesh/live/daemon/run.d.ts +2 -0
  70. package/dist/lib/mesh/live/daemon/run.js +111 -54
  71. package/dist/lib/mesh/live/daemon/state.d.ts +2 -0
  72. package/dist/lib/mesh/live/daemon/transcript-watch.d.ts +3 -0
  73. package/dist/lib/mesh/live/daemon/transcript-watch.js +31 -8
  74. package/dist/lib/scan-packages/index.d.ts +2 -0
  75. package/dist/lib/scan-packages/index.js +1 -1
  76. package/dist/lib/work-context/state.d.ts +12 -0
  77. package/dist/lib/work-context/state.js +131 -3
  78. package/package.json +3 -1
@@ -5,9 +5,22 @@
5
5
  * optional `company:` field. A company path with a missing or contradictory
6
6
  * `company:` is `worker_tenancy_unresolved`, never a global worker.
7
7
  *
8
- * The registry does not index personal/workers/ for this command. Naming a
9
- * personal worker fails with a clear error and does not fall through to a
10
- * same-named entry in another tree.
8
+ * Personal workers are indexed by the registry generator when they have a
9
+ * worker.yaml. A personal directory that exists without one fails by name
10
+ * and does not fall through to a same-named entry in another tree.
11
+ *
12
+ * Package workers are not a fourth generator scan root. `hq core
13
+ * scan-packages` mounts a declared `contributes.workers` entry into
14
+ * `core/workers/public/<item>` (a symlink; origin/main writes that link
15
+ * relative to the host directory, this branch still writes it absolute).
16
+ * The generator then indexes the mount, and `packAttribution` keeps
17
+ * recognising it by realpath. Scanning `core/packages` as well would
18
+ * double-register that mount. A pack that declares a worker whose symlink
19
+ * is missing fails with `package_workers_unmounted` instead of resolving
20
+ * some other tree's copy. Tenancy for a mount follows the package: global
21
+ * when package.yaml has no company and access is public (or omitted),
22
+ * company-owned when package.yaml names `company`, and
23
+ * `worker_tenancy_unresolved` when that cannot be determined.
11
24
  */
12
25
  import * as fs from "node:fs";
13
26
  export declare const WORKER_REGISTRY_REL: string;
@@ -72,6 +85,8 @@ export interface ResolvedLaneWorker {
72
85
  defaultTimeout: unknown;
73
86
  approvalRequired: boolean;
74
87
  humanCheckpoints: string[];
88
+ /** Set when the worker's realpath lives in a package. */
89
+ pack?: string;
75
90
  }
76
91
  export interface RegistryDeps {
77
92
  existsSync: (p: string) => boolean;
@@ -90,8 +105,6 @@ export declare function tenancyFromRegistryPath(entry: RegistryWorkerEntry): Wor
90
105
  kind: "unresolved";
91
106
  pathSlug: string;
92
107
  field?: string;
93
- } | {
94
- kind: "personal";
95
108
  };
96
109
  /**
97
110
  * Resolve context.base against HQ root, then core/, then the worker directory.
@@ -5,13 +5,28 @@
5
5
  * optional `company:` field. A company path with a missing or contradictory
6
6
  * `company:` is `worker_tenancy_unresolved`, never a global worker.
7
7
  *
8
- * The registry does not index personal/workers/ for this command. Naming a
9
- * personal worker fails with a clear error and does not fall through to a
10
- * same-named entry in another tree.
8
+ * Personal workers are indexed by the registry generator when they have a
9
+ * worker.yaml. A personal directory that exists without one fails by name
10
+ * and does not fall through to a same-named entry in another tree.
11
+ *
12
+ * Package workers are not a fourth generator scan root. `hq core
13
+ * scan-packages` mounts a declared `contributes.workers` entry into
14
+ * `core/workers/public/<item>` (a symlink; origin/main writes that link
15
+ * relative to the host directory, this branch still writes it absolute).
16
+ * The generator then indexes the mount, and `packAttribution` keeps
17
+ * recognising it by realpath. Scanning `core/packages` as well would
18
+ * double-register that mount. A pack that declares a worker whose symlink
19
+ * is missing fails with `package_workers_unmounted` instead of resolving
20
+ * some other tree's copy. Tenancy for a mount follows the package: global
21
+ * when package.yaml has no company and access is public (or omitted),
22
+ * company-owned when package.yaml names `company`, and
23
+ * `worker_tenancy_unresolved` when that cannot be determined.
11
24
  */
12
25
  import * as fs from "node:fs";
13
26
  import * as path from "node:path";
14
27
  import { parseUserYaml } from "../../utils/user-yaml-error.js";
28
+ import { readContributes } from "../scan-packages/index.js";
29
+ import { contributionLinks, linkStatus, } from "../../utils/pack-contributions.js";
15
30
  import { WorkerResolutionError } from "./errors.js";
16
31
  export const WORKER_REGISTRY_REL = path.join("core", "workers", "registry.yaml");
17
32
  function defaultRegistryDeps() {
@@ -107,8 +122,10 @@ const CORE_PATH = /^(?:core\/workers\/)/;
107
122
  */
108
123
  export function tenancyFromRegistryPath(entry) {
109
124
  const normalized = entry.path.replaceAll("\\", "/");
125
+ // personal/workers is the operator's tree, not a tenant. Path still wins
126
+ // over a company: field, which is ignored here.
110
127
  if (PERSONAL_PATH.test(normalized)) {
111
- return { kind: "personal" };
128
+ return { kind: "global" };
112
129
  }
113
130
  const companyMatch = COMPANY_PATH.exec(normalized);
114
131
  if (companyMatch) {
@@ -146,7 +163,7 @@ function loadWorkerYaml(hqRoot, relativeDir, deps) {
146
163
  * Entries that resolve nowhere are dropped, not passed on.
147
164
  */
148
165
  export function resolveContextBasePaths(hqRoot, workerDir, bases, deps = defaultRegistryDeps()) {
149
- if (!bases || bases.length === 0)
166
+ if (!Array.isArray(bases) || bases.length === 0)
150
167
  return [];
151
168
  const resolved = [];
152
169
  for (const entry of bases) {
@@ -164,7 +181,7 @@ export function resolveContextBasePaths(hqRoot, workerDir, bases, deps = default
164
181
  return resolved;
165
182
  }
166
183
  export function resolveSkillFiles(workerDir, skills, deps = defaultRegistryDeps()) {
167
- if (!skills)
184
+ if (!Array.isArray(skills) || skills.length === 0)
168
185
  return [];
169
186
  const files = [];
170
187
  for (const skill of skills) {
@@ -185,28 +202,287 @@ function humanCheckpointsOf(yaml) {
185
202
  return [];
186
203
  return raw.filter((item) => typeof item === "string");
187
204
  }
205
+ function normalizeRel(value) {
206
+ const norm = value.replaceAll("\\", "/").replace(/\/+$/, "");
207
+ return norm.length > 0 ? `${norm}/` : norm;
208
+ }
209
+ function realpathOf(hqRoot, relativeDir) {
210
+ const abs = path.join(hqRoot, relativeDir.replace(/\/+$/, ""));
211
+ try {
212
+ return fs.realpathSync(abs);
213
+ }
214
+ catch {
215
+ return abs;
216
+ }
217
+ }
218
+ function workerIdInYaml(filePath, deps) {
219
+ if (!deps.existsSync(filePath))
220
+ return null;
221
+ let doc;
222
+ try {
223
+ doc = parseUserYaml(deps.readFileSync(filePath, "utf8"), filePath);
224
+ }
225
+ catch {
226
+ return null;
227
+ }
228
+ if (!isPlainObject(doc) || !isPlainObject(doc.worker))
229
+ return null;
230
+ const worker = doc.worker;
231
+ const id = typeof worker.id === "string" ? worker.id.trim() : "";
232
+ if (!id)
233
+ return null;
234
+ return {
235
+ id,
236
+ company: typeof worker.company === "string" ? worker.company : undefined,
237
+ status: typeof worker.status === "string" ? worker.status : undefined,
238
+ type: typeof worker.type === "string" ? worker.type : undefined,
239
+ description: typeof worker.description === "string" ? worker.description : undefined,
240
+ };
241
+ }
242
+ /**
243
+ * A personal directory with files but no worker.yaml claims the id. An
244
+ * empty directory is a leftover and does not.
245
+ */
246
+ function personalDirClaim(hqRoot, workerId, deps) {
247
+ const dir = personalWorkerDir(hqRoot, workerId);
248
+ let st;
249
+ try {
250
+ st = deps.statSync(dir);
251
+ }
252
+ catch (err) {
253
+ const code = err.code;
254
+ if (code === "ENOENT")
255
+ return "none";
256
+ throw err;
257
+ }
258
+ if (!st.isDirectory())
259
+ return "none";
260
+ const yamlPath = path.join(dir, "worker.yaml");
261
+ try {
262
+ if (deps.statSync(yamlPath).isFile())
263
+ return "yaml";
264
+ }
265
+ catch (err) {
266
+ const code = err.code;
267
+ if (code !== "ENOENT")
268
+ throw err;
269
+ }
270
+ let names;
271
+ try {
272
+ names = fs.readdirSync(dir);
273
+ }
274
+ catch {
275
+ return "none";
276
+ }
277
+ const rest = names.filter((name) => name !== "worker.yaml");
278
+ return rest.length > 0 ? "missing_yaml" : "none";
279
+ }
280
+ function packNameFromRealpath(hqRoot, real) {
281
+ const rel = path.relative(hqRoot, real).replaceAll("\\", "/");
282
+ const match = /^core\/packages\/([^/]+)\//.exec(rel);
283
+ return match?.[1] ?? null;
284
+ }
285
+ function declaredPackWorkers(hqRoot, deps) {
286
+ const packagesDir = path.join(hqRoot, "core", "packages");
287
+ if (!deps.existsSync(packagesDir))
288
+ return [];
289
+ let names;
290
+ try {
291
+ names = fs.readdirSync(packagesDir);
292
+ }
293
+ catch {
294
+ return [];
295
+ }
296
+ const found = [];
297
+ for (const pack of names) {
298
+ if (pack.startsWith("."))
299
+ continue;
300
+ const packDir = path.join(packagesDir, pack);
301
+ const manifest = path.join(packDir, "package.yaml");
302
+ if (!deps.existsSync(manifest))
303
+ continue;
304
+ let contributes;
305
+ try {
306
+ contributes = readContributes(manifest);
307
+ }
308
+ catch {
309
+ continue;
310
+ }
311
+ for (const link of contributionLinks(hqRoot, packDir, contributes)) {
312
+ if (link.key !== "workers")
313
+ continue;
314
+ const fields = workerIdInYaml(path.join(link.src, "worker.yaml"), deps);
315
+ found.push({ pack, item: link.item, link, workerId: fields?.id ?? null });
316
+ }
317
+ }
318
+ return found;
319
+ }
320
+ function declarationMatches(row, workerId) {
321
+ return row.workerId === workerId || row.item === workerId;
322
+ }
323
+ /**
324
+ * A package is global unless it declares company ownership. `company: <slug>`
325
+ * in package.yaml is that declaration. No company and access public (or
326
+ * access omitted, which is how the shipped public packs read) is global.
327
+ * A missing manifest, a non-string company, a private access with no slug,
328
+ * or a worker.yaml company that disagrees with the package is unresolved.
329
+ */
330
+ function tenancyFromPackage(hqRoot, pack, workerCompany, deps) {
331
+ const manifest = path.join(hqRoot, "core", "packages", pack, "package.yaml");
332
+ if (!deps.existsSync(manifest)) {
333
+ return { kind: "unresolved", pathSlug: "", field: undefined };
334
+ }
335
+ let doc;
336
+ try {
337
+ doc = parseUserYaml(deps.readFileSync(manifest, "utf8"), manifest);
338
+ }
339
+ catch {
340
+ return { kind: "unresolved", pathSlug: "", field: undefined };
341
+ }
342
+ if (!isPlainObject(doc)) {
343
+ return { kind: "unresolved", pathSlug: "", field: undefined };
344
+ }
345
+ const access = typeof doc.access === "string" ? doc.access.trim() : "";
346
+ if (doc.company !== undefined) {
347
+ if (typeof doc.company !== "string" || doc.company.trim().length === 0) {
348
+ return {
349
+ kind: "unresolved",
350
+ pathSlug: "",
351
+ field: typeof doc.company === "string" ? doc.company : undefined,
352
+ };
353
+ }
354
+ const slug = doc.company.trim();
355
+ const field = workerCompany?.trim() ?? "";
356
+ if (field && field !== slug) {
357
+ return { kind: "unresolved", pathSlug: slug, field };
358
+ }
359
+ return { kind: "company", slug };
360
+ }
361
+ if (access === "" || access === "public")
362
+ return { kind: "global" };
363
+ return { kind: "unresolved", pathSlug: "", field: access };
364
+ }
365
+ function readRegistryOrEmpty(hqRoot, deps) {
366
+ if (!deps.existsSync(registryPath(hqRoot)))
367
+ return [];
368
+ return readWorkerRegistryFile(hqRoot, deps);
369
+ }
188
370
  export function resolveLaneWorker(hqRoot, workerId, laneCompany, deps = defaultRegistryDeps()) {
189
- if (personalWorkerExists(hqRoot, workerId, deps)) {
190
- throw new WorkerResolutionError("personal_worker_unindexed", `Worker ${JSON.stringify(workerId)} lives under personal/workers/ which the registry does not index; --worker cannot resolve personal workers`, {
371
+ const personalRel = path.posix.join("personal", "workers", workerId);
372
+ const personalClaim = personalDirClaim(hqRoot, workerId, deps);
373
+ if (personalClaim === "missing_yaml") {
374
+ throw new WorkerResolutionError("worker_not_found", `Worker ${JSON.stringify(workerId)} is at ${personalRel}/ but worker.yaml is missing`, { worker: workerId, path: `${personalRel}/`, missing: "worker.yaml" });
375
+ }
376
+ const entries = readRegistryOrEmpty(hqRoot, deps);
377
+ const candidates = [];
378
+ for (const entry of entries) {
379
+ if (entry.id !== workerId)
380
+ continue;
381
+ const rel = normalizeRel(entry.path);
382
+ candidates.push({
383
+ id: entry.id,
384
+ path: rel,
385
+ type: entry.type,
386
+ status: entry.status && entry.status.length > 0 ? entry.status : "active",
387
+ visibility: entry.visibility,
388
+ description: entry.description,
389
+ company: entry.company,
390
+ realpath: realpathOf(hqRoot, rel),
391
+ });
392
+ }
393
+ if (personalClaim === "yaml") {
394
+ const rel = normalizeRel(personalRel);
395
+ const real = realpathOf(hqRoot, rel);
396
+ if (!candidates.some((item) => item.realpath === real)) {
397
+ const fields = workerIdInYaml(path.join(hqRoot, rel, "worker.yaml"), deps);
398
+ candidates.push({
399
+ id: workerId,
400
+ path: rel,
401
+ type: fields?.type ?? "",
402
+ status: fields?.status && fields.status.length > 0 ? fields.status : "active",
403
+ description: fields?.description,
404
+ company: fields?.company,
405
+ realpath: real,
406
+ });
407
+ }
408
+ }
409
+ const declarations = declaredPackWorkers(hqRoot, deps).filter((row) => declarationMatches(row, workerId));
410
+ const unmounted = [];
411
+ for (const row of declarations) {
412
+ const status = linkStatus(row.link, path.join(hqRoot, "core", "packages", row.pack));
413
+ if (status !== "live") {
414
+ unmounted.push(row);
415
+ continue;
416
+ }
417
+ const yamlPath = path.join(row.link.src, "worker.yaml");
418
+ if (!deps.existsSync(yamlPath)) {
419
+ throw new WorkerResolutionError("worker_not_found", `Worker ${JSON.stringify(workerId)} is mounted from pack ${row.pack} but worker.yaml is missing`, {
420
+ worker: workerId,
421
+ path: path.relative(hqRoot, row.link.dst).replaceAll("\\", "/"),
422
+ pack: row.pack,
423
+ missing: "worker.yaml",
424
+ });
425
+ }
426
+ const rel = normalizeRel(path.relative(hqRoot, row.link.dst));
427
+ const real = realpathOf(hqRoot, rel);
428
+ if (candidates.some((item) => item.realpath === real))
429
+ continue;
430
+ const fields = workerIdInYaml(yamlPath, deps);
431
+ candidates.push({
432
+ id: workerId,
433
+ path: rel,
434
+ type: fields?.type ?? "",
435
+ status: fields?.status && fields.status.length > 0 ? fields.status : "active",
436
+ description: fields?.description,
437
+ company: fields?.company,
438
+ realpath: real,
439
+ });
440
+ }
441
+ if (unmounted.length > 0) {
442
+ const row = unmounted[0];
443
+ throw new WorkerResolutionError("package_workers_unmounted", `Worker ${JSON.stringify(workerId)} is declared by pack ${row.pack} but ${path.relative(hqRoot, row.link.dst)} is not a symlink to that pack. Run hq core scan-packages, then regenerate the worker registry.`, {
191
444
  worker: workerId,
192
- path: path.join("personal", "workers", workerId).replaceAll("\\", "/"),
445
+ pack: row.pack,
446
+ item: row.item,
447
+ expected: path.relative(hqRoot, row.link.dst).replaceAll("\\", "/"),
448
+ also_registered_at: candidates.map((item) => item.path),
193
449
  });
194
450
  }
195
- const entries = readWorkerRegistryFile(hqRoot, deps);
196
- const entry = entries.find((item) => item.id === workerId);
451
+ const distinct = [];
452
+ for (const candidate of candidates) {
453
+ if (distinct.some((item) => item.realpath === candidate.realpath))
454
+ continue;
455
+ distinct.push(candidate);
456
+ }
457
+ if (distinct.length > 1) {
458
+ throw new WorkerResolutionError("worker_id_conflict", `Worker ${JSON.stringify(workerId)} exists in more than one tree: ${distinct.map((item) => item.path).join(", ")}. Refusing to pick one.`, { worker: workerId, paths: distinct.map((item) => item.path) });
459
+ }
460
+ const entry = distinct[0];
197
461
  if (!entry) {
198
462
  throw new WorkerResolutionError("worker_not_found", `Worker ${JSON.stringify(workerId)} is not in core/workers/registry.yaml`, { worker: workerId });
199
463
  }
200
- const tenancy = tenancyFromRegistryPath(entry);
201
- if (tenancy.kind === "personal") {
202
- throw new WorkerResolutionError("personal_worker_unindexed", `Worker ${JSON.stringify(workerId)} is registered under personal/workers/ which lanes do not admit`, { worker: workerId, path: entry.path });
203
- }
464
+ const relativeDir = entry.path.replace(/\/+$/, "");
465
+ const workerDir = path.join(hqRoot, relativeDir);
466
+ const workerYaml = loadWorkerYaml(hqRoot, relativeDir, deps);
467
+ const pack = packNameFromRealpath(hqRoot, entry.realpath);
468
+ const workerCompany = typeof workerYaml.worker?.company === "string" ? workerYaml.worker.company : entry.company;
469
+ const tenancy = pack
470
+ ? tenancyFromPackage(hqRoot, pack, workerCompany, deps)
471
+ : tenancyFromRegistryPath({
472
+ id: entry.id,
473
+ path: entry.path,
474
+ type: entry.type,
475
+ company: workerCompany,
476
+ });
204
477
  if (tenancy.kind === "unresolved") {
205
- throw new WorkerResolutionError("worker_tenancy_unresolved", `Worker ${JSON.stringify(workerId)} has a company path whose company field is missing or contradicts the path`, {
478
+ throw new WorkerResolutionError("worker_tenancy_unresolved", pack
479
+ ? `Worker ${JSON.stringify(workerId)} is mounted from pack ${pack} whose company ownership cannot be determined`
480
+ : `Worker ${JSON.stringify(workerId)} has a company path whose company field is missing or contradicts the path`, {
206
481
  worker: workerId,
207
482
  path: entry.path,
208
483
  path_slug: tenancy.pathSlug,
209
484
  company_field: tenancy.field ?? null,
485
+ ...(pack ? { pack } : {}),
210
486
  });
211
487
  }
212
488
  if (tenancy.kind === "company") {
@@ -222,9 +498,6 @@ export function resolveLaneWorker(hqRoot, workerId, laneCompany, deps = defaultR
222
498
  if (status !== "active") {
223
499
  throw new WorkerResolutionError("worker_not_active", `Worker ${JSON.stringify(workerId)} has status ${JSON.stringify(status)} (need active)`, { worker: workerId, status });
224
500
  }
225
- const relativeDir = entry.path.replace(/\/+$/, "");
226
- const workerDir = path.join(hqRoot, relativeDir);
227
- const workerYaml = loadWorkerYaml(hqRoot, relativeDir, deps);
228
501
  const resolvedContextBase = resolveContextBasePaths(hqRoot, workerDir, workerYaml.context?.base, deps);
229
502
  const skillFiles = resolveSkillFiles(workerDir, workerYaml.skills, deps);
230
503
  return {
@@ -242,6 +515,7 @@ export function resolveLaneWorker(hqRoot, workerId, laneCompany, deps = defaultR
242
515
  defaultTimeout: workerYaml.execution?.max_runtime,
243
516
  approvalRequired: workerYaml.verification?.approval_required === true,
244
517
  humanCheckpoints: humanCheckpointsOf(workerYaml),
518
+ ...(pack ? { pack } : {}),
245
519
  };
246
520
  }
247
521
  //# sourceMappingURL=registry.js.map