opencode-hive 1.0.0 → 1.0.2

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/dist/index.js CHANGED
@@ -12,10 +12,10 @@ var __export = (target, all) => {
12
12
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
13
13
 
14
14
  // src/index.ts
15
- import * as path5 from "path";
16
- import * as fs6 from "fs";
15
+ import * as path7 from "path";
16
+ import * as fs9 from "fs";
17
17
 
18
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/classic/external.js
18
+ // ../../node_modules/zod/v4/classic/external.js
19
19
  var exports_external = {};
20
20
  __export(exports_external, {
21
21
  xid: () => xid2,
@@ -245,7 +245,7 @@ __export(exports_external, {
245
245
  $brand: () => $brand
246
246
  });
247
247
 
248
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/core/index.js
248
+ // ../../node_modules/zod/v4/core/index.js
249
249
  var exports_core2 = {};
250
250
  __export(exports_core2, {
251
251
  version: () => version,
@@ -509,7 +509,7 @@ __export(exports_core2, {
509
509
  $ZodAny: () => $ZodAny
510
510
  });
511
511
 
512
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/core/core.js
512
+ // ../../node_modules/zod/v4/core/core.js
513
513
  var NEVER = Object.freeze({
514
514
  status: "aborted"
515
515
  });
@@ -576,7 +576,7 @@ function config(newConfig) {
576
576
  Object.assign(globalConfig, newConfig);
577
577
  return globalConfig;
578
578
  }
579
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/core/util.js
579
+ // ../../node_modules/zod/v4/core/util.js
580
580
  var exports_util = {};
581
581
  __export(exports_util, {
582
582
  unwrapMessage: () => unwrapMessage,
@@ -1205,7 +1205,7 @@ class Class {
1205
1205
  constructor(..._args) {}
1206
1206
  }
1207
1207
 
1208
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/core/errors.js
1208
+ // ../../node_modules/zod/v4/core/errors.js
1209
1209
  var initializer = (inst, def) => {
1210
1210
  inst.name = "$ZodError";
1211
1211
  Object.defineProperty(inst, "_zod", {
@@ -1348,7 +1348,7 @@ function prettifyError(error) {
1348
1348
  `);
1349
1349
  }
1350
1350
 
1351
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/core/parse.js
1351
+ // ../../node_modules/zod/v4/core/parse.js
1352
1352
  var _parse = (_Err) => (schema, value, _ctx, _params) => {
1353
1353
  const ctx = _ctx ? Object.assign(_ctx, { async: false }) : { async: false };
1354
1354
  const result = schema._zod.run({ value, issues: [] }, ctx);
@@ -1435,7 +1435,7 @@ var _safeDecodeAsync = (_Err) => async (schema, value, _ctx) => {
1435
1435
  return _safeParseAsync(_Err)(schema, value, _ctx);
1436
1436
  };
1437
1437
  var safeDecodeAsync = /* @__PURE__ */ _safeDecodeAsync($ZodRealError);
1438
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/core/regexes.js
1438
+ // ../../node_modules/zod/v4/core/regexes.js
1439
1439
  var exports_regexes = {};
1440
1440
  __export(exports_regexes, {
1441
1441
  xid: () => xid,
@@ -1587,7 +1587,7 @@ var sha512_hex = /^[0-9a-fA-F]{128}$/;
1587
1587
  var sha512_base64 = /* @__PURE__ */ fixedBase64(86, "==");
1588
1588
  var sha512_base64url = /* @__PURE__ */ fixedBase64url(86);
1589
1589
 
1590
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/core/checks.js
1590
+ // ../../node_modules/zod/v4/core/checks.js
1591
1591
  var $ZodCheck = /* @__PURE__ */ $constructor("$ZodCheck", (inst, def) => {
1592
1592
  var _a;
1593
1593
  inst._zod ?? (inst._zod = {});
@@ -2128,7 +2128,7 @@ var $ZodCheckOverwrite = /* @__PURE__ */ $constructor("$ZodCheckOverwrite", (ins
2128
2128
  };
2129
2129
  });
2130
2130
 
2131
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/core/doc.js
2131
+ // ../../node_modules/zod/v4/core/doc.js
2132
2132
  class Doc {
2133
2133
  constructor(args = []) {
2134
2134
  this.content = [];
@@ -2166,14 +2166,14 @@ class Doc {
2166
2166
  }
2167
2167
  }
2168
2168
 
2169
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/core/versions.js
2169
+ // ../../node_modules/zod/v4/core/versions.js
2170
2170
  var version = {
2171
2171
  major: 4,
2172
2172
  minor: 1,
2173
2173
  patch: 8
2174
2174
  };
2175
2175
 
2176
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/core/schemas.js
2176
+ // ../../node_modules/zod/v4/core/schemas.js
2177
2177
  var $ZodType = /* @__PURE__ */ $constructor("$ZodType", (inst, def) => {
2178
2178
  var _a;
2179
2179
  inst ?? (inst = {});
@@ -3996,7 +3996,7 @@ function handleRefineResult(result, payload, input, inst) {
3996
3996
  payload.issues.push(issue(_iss));
3997
3997
  }
3998
3998
  }
3999
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/index.js
3999
+ // ../../node_modules/zod/v4/locales/index.js
4000
4000
  var exports_locales = {};
4001
4001
  __export(exports_locales, {
4002
4002
  zhTW: () => zh_TW_default,
@@ -4047,7 +4047,7 @@ __export(exports_locales, {
4047
4047
  ar: () => ar_default
4048
4048
  });
4049
4049
 
4050
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/ar.js
4050
+ // ../../node_modules/zod/v4/locales/ar.js
4051
4051
  var error = () => {
4052
4052
  const Sizable = {
4053
4053
  string: { unit: "حرف", verb: "أن يحوي" },
@@ -4163,7 +4163,7 @@ function ar_default() {
4163
4163
  localeError: error()
4164
4164
  };
4165
4165
  }
4166
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/az.js
4166
+ // ../../node_modules/zod/v4/locales/az.js
4167
4167
  var error2 = () => {
4168
4168
  const Sizable = {
4169
4169
  string: { unit: "simvol", verb: "olmalıdır" },
@@ -4278,7 +4278,7 @@ function az_default() {
4278
4278
  localeError: error2()
4279
4279
  };
4280
4280
  }
4281
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/be.js
4281
+ // ../../node_modules/zod/v4/locales/be.js
4282
4282
  function getBelarusianPlural(count, one, few, many) {
4283
4283
  const absCount = Math.abs(count);
4284
4284
  const lastDigit = absCount % 10;
@@ -4442,7 +4442,7 @@ function be_default() {
4442
4442
  localeError: error3()
4443
4443
  };
4444
4444
  }
4445
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/ca.js
4445
+ // ../../node_modules/zod/v4/locales/ca.js
4446
4446
  var error4 = () => {
4447
4447
  const Sizable = {
4448
4448
  string: { unit: "caràcters", verb: "contenir" },
@@ -4559,7 +4559,7 @@ function ca_default() {
4559
4559
  localeError: error4()
4560
4560
  };
4561
4561
  }
4562
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/cs.js
4562
+ // ../../node_modules/zod/v4/locales/cs.js
4563
4563
  var error5 = () => {
4564
4564
  const Sizable = {
4565
4565
  string: { unit: "znaků", verb: "mít" },
@@ -4694,7 +4694,7 @@ function cs_default() {
4694
4694
  localeError: error5()
4695
4695
  };
4696
4696
  }
4697
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/da.js
4697
+ // ../../node_modules/zod/v4/locales/da.js
4698
4698
  var error6 = () => {
4699
4699
  const Sizable = {
4700
4700
  string: { unit: "tegn", verb: "havde" },
@@ -4825,7 +4825,7 @@ function da_default() {
4825
4825
  localeError: error6()
4826
4826
  };
4827
4827
  }
4828
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/de.js
4828
+ // ../../node_modules/zod/v4/locales/de.js
4829
4829
  var error7 = () => {
4830
4830
  const Sizable = {
4831
4831
  string: { unit: "Zeichen", verb: "zu haben" },
@@ -4941,7 +4941,7 @@ function de_default() {
4941
4941
  localeError: error7()
4942
4942
  };
4943
4943
  }
4944
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/en.js
4944
+ // ../../node_modules/zod/v4/locales/en.js
4945
4945
  var parsedType = (data) => {
4946
4946
  const t = typeof data;
4947
4947
  switch (t) {
@@ -5058,7 +5058,7 @@ function en_default() {
5058
5058
  localeError: error8()
5059
5059
  };
5060
5060
  }
5061
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/eo.js
5061
+ // ../../node_modules/zod/v4/locales/eo.js
5062
5062
  var parsedType2 = (data) => {
5063
5063
  const t = typeof data;
5064
5064
  switch (t) {
@@ -5174,7 +5174,7 @@ function eo_default() {
5174
5174
  localeError: error9()
5175
5175
  };
5176
5176
  }
5177
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/es.js
5177
+ // ../../node_modules/zod/v4/locales/es.js
5178
5178
  var error10 = () => {
5179
5179
  const Sizable = {
5180
5180
  string: { unit: "caracteres", verb: "tener" },
@@ -5322,7 +5322,7 @@ function es_default() {
5322
5322
  localeError: error10()
5323
5323
  };
5324
5324
  }
5325
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/fa.js
5325
+ // ../../node_modules/zod/v4/locales/fa.js
5326
5326
  var error11 = () => {
5327
5327
  const Sizable = {
5328
5328
  string: { unit: "کاراکتر", verb: "داشته باشد" },
@@ -5444,7 +5444,7 @@ function fa_default() {
5444
5444
  localeError: error11()
5445
5445
  };
5446
5446
  }
5447
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/fi.js
5447
+ // ../../node_modules/zod/v4/locales/fi.js
5448
5448
  var error12 = () => {
5449
5449
  const Sizable = {
5450
5450
  string: { unit: "merkkiä", subject: "merkkijonon" },
@@ -5566,7 +5566,7 @@ function fi_default() {
5566
5566
  localeError: error12()
5567
5567
  };
5568
5568
  }
5569
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/fr.js
5569
+ // ../../node_modules/zod/v4/locales/fr.js
5570
5570
  var error13 = () => {
5571
5571
  const Sizable = {
5572
5572
  string: { unit: "caractères", verb: "avoir" },
@@ -5682,7 +5682,7 @@ function fr_default() {
5682
5682
  localeError: error13()
5683
5683
  };
5684
5684
  }
5685
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/fr-CA.js
5685
+ // ../../node_modules/zod/v4/locales/fr-CA.js
5686
5686
  var error14 = () => {
5687
5687
  const Sizable = {
5688
5688
  string: { unit: "caractères", verb: "avoir" },
@@ -5799,7 +5799,7 @@ function fr_CA_default() {
5799
5799
  localeError: error14()
5800
5800
  };
5801
5801
  }
5802
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/he.js
5802
+ // ../../node_modules/zod/v4/locales/he.js
5803
5803
  var error15 = () => {
5804
5804
  const Sizable = {
5805
5805
  string: { unit: "אותיות", verb: "לכלול" },
@@ -5915,7 +5915,7 @@ function he_default() {
5915
5915
  localeError: error15()
5916
5916
  };
5917
5917
  }
5918
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/hu.js
5918
+ // ../../node_modules/zod/v4/locales/hu.js
5919
5919
  var error16 = () => {
5920
5920
  const Sizable = {
5921
5921
  string: { unit: "karakter", verb: "legyen" },
@@ -6031,7 +6031,7 @@ function hu_default() {
6031
6031
  localeError: error16()
6032
6032
  };
6033
6033
  }
6034
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/id.js
6034
+ // ../../node_modules/zod/v4/locales/id.js
6035
6035
  var error17 = () => {
6036
6036
  const Sizable = {
6037
6037
  string: { unit: "karakter", verb: "memiliki" },
@@ -6147,7 +6147,7 @@ function id_default() {
6147
6147
  localeError: error17()
6148
6148
  };
6149
6149
  }
6150
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/is.js
6150
+ // ../../node_modules/zod/v4/locales/is.js
6151
6151
  var parsedType3 = (data) => {
6152
6152
  const t = typeof data;
6153
6153
  switch (t) {
@@ -6264,7 +6264,7 @@ function is_default() {
6264
6264
  localeError: error18()
6265
6265
  };
6266
6266
  }
6267
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/it.js
6267
+ // ../../node_modules/zod/v4/locales/it.js
6268
6268
  var error19 = () => {
6269
6269
  const Sizable = {
6270
6270
  string: { unit: "caratteri", verb: "avere" },
@@ -6380,7 +6380,7 @@ function it_default() {
6380
6380
  localeError: error19()
6381
6381
  };
6382
6382
  }
6383
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/ja.js
6383
+ // ../../node_modules/zod/v4/locales/ja.js
6384
6384
  var error20 = () => {
6385
6385
  const Sizable = {
6386
6386
  string: { unit: "文字", verb: "である" },
@@ -6495,7 +6495,7 @@ function ja_default() {
6495
6495
  localeError: error20()
6496
6496
  };
6497
6497
  }
6498
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/ka.js
6498
+ // ../../node_modules/zod/v4/locales/ka.js
6499
6499
  var parsedType4 = (data) => {
6500
6500
  const t = typeof data;
6501
6501
  switch (t) {
@@ -6620,7 +6620,7 @@ function ka_default() {
6620
6620
  localeError: error21()
6621
6621
  };
6622
6622
  }
6623
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/km.js
6623
+ // ../../node_modules/zod/v4/locales/km.js
6624
6624
  var error22 = () => {
6625
6625
  const Sizable = {
6626
6626
  string: { unit: "តួអក្សរ", verb: "គួរមាន" },
@@ -6738,11 +6738,11 @@ function km_default() {
6738
6738
  };
6739
6739
  }
6740
6740
 
6741
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/kh.js
6741
+ // ../../node_modules/zod/v4/locales/kh.js
6742
6742
  function kh_default() {
6743
6743
  return km_default();
6744
6744
  }
6745
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/ko.js
6745
+ // ../../node_modules/zod/v4/locales/ko.js
6746
6746
  var error23 = () => {
6747
6747
  const Sizable = {
6748
6748
  string: { unit: "문자", verb: "to have" },
@@ -6863,7 +6863,7 @@ function ko_default() {
6863
6863
  localeError: error23()
6864
6864
  };
6865
6865
  }
6866
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/lt.js
6866
+ // ../../node_modules/zod/v4/locales/lt.js
6867
6867
  var parsedType5 = (data) => {
6868
6868
  const t = typeof data;
6869
6869
  return parsedTypeFromType(t, data);
@@ -7092,7 +7092,7 @@ function lt_default() {
7092
7092
  localeError: error24()
7093
7093
  };
7094
7094
  }
7095
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/mk.js
7095
+ // ../../node_modules/zod/v4/locales/mk.js
7096
7096
  var error25 = () => {
7097
7097
  const Sizable = {
7098
7098
  string: { unit: "знаци", verb: "да имаат" },
@@ -7209,7 +7209,7 @@ function mk_default() {
7209
7209
  localeError: error25()
7210
7210
  };
7211
7211
  }
7212
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/ms.js
7212
+ // ../../node_modules/zod/v4/locales/ms.js
7213
7213
  var error26 = () => {
7214
7214
  const Sizable = {
7215
7215
  string: { unit: "aksara", verb: "mempunyai" },
@@ -7325,7 +7325,7 @@ function ms_default() {
7325
7325
  localeError: error26()
7326
7326
  };
7327
7327
  }
7328
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/nl.js
7328
+ // ../../node_modules/zod/v4/locales/nl.js
7329
7329
  var error27 = () => {
7330
7330
  const Sizable = {
7331
7331
  string: { unit: "tekens" },
@@ -7442,7 +7442,7 @@ function nl_default() {
7442
7442
  localeError: error27()
7443
7443
  };
7444
7444
  }
7445
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/no.js
7445
+ // ../../node_modules/zod/v4/locales/no.js
7446
7446
  var error28 = () => {
7447
7447
  const Sizable = {
7448
7448
  string: { unit: "tegn", verb: "å ha" },
@@ -7558,7 +7558,7 @@ function no_default() {
7558
7558
  localeError: error28()
7559
7559
  };
7560
7560
  }
7561
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/ota.js
7561
+ // ../../node_modules/zod/v4/locales/ota.js
7562
7562
  var error29 = () => {
7563
7563
  const Sizable = {
7564
7564
  string: { unit: "harf", verb: "olmalıdır" },
@@ -7674,7 +7674,7 @@ function ota_default() {
7674
7674
  localeError: error29()
7675
7675
  };
7676
7676
  }
7677
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/ps.js
7677
+ // ../../node_modules/zod/v4/locales/ps.js
7678
7678
  var error30 = () => {
7679
7679
  const Sizable = {
7680
7680
  string: { unit: "توکي", verb: "ولري" },
@@ -7796,7 +7796,7 @@ function ps_default() {
7796
7796
  localeError: error30()
7797
7797
  };
7798
7798
  }
7799
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/pl.js
7799
+ // ../../node_modules/zod/v4/locales/pl.js
7800
7800
  var error31 = () => {
7801
7801
  const Sizable = {
7802
7802
  string: { unit: "znaków", verb: "mieć" },
@@ -7913,7 +7913,7 @@ function pl_default() {
7913
7913
  localeError: error31()
7914
7914
  };
7915
7915
  }
7916
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/pt.js
7916
+ // ../../node_modules/zod/v4/locales/pt.js
7917
7917
  var error32 = () => {
7918
7918
  const Sizable = {
7919
7919
  string: { unit: "caracteres", verb: "ter" },
@@ -8029,7 +8029,7 @@ function pt_default() {
8029
8029
  localeError: error32()
8030
8030
  };
8031
8031
  }
8032
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/ru.js
8032
+ // ../../node_modules/zod/v4/locales/ru.js
8033
8033
  function getRussianPlural(count, one, few, many) {
8034
8034
  const absCount = Math.abs(count);
8035
8035
  const lastDigit = absCount % 10;
@@ -8193,7 +8193,7 @@ function ru_default() {
8193
8193
  localeError: error33()
8194
8194
  };
8195
8195
  }
8196
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/sl.js
8196
+ // ../../node_modules/zod/v4/locales/sl.js
8197
8197
  var error34 = () => {
8198
8198
  const Sizable = {
8199
8199
  string: { unit: "znakov", verb: "imeti" },
@@ -8310,7 +8310,7 @@ function sl_default() {
8310
8310
  localeError: error34()
8311
8311
  };
8312
8312
  }
8313
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/sv.js
8313
+ // ../../node_modules/zod/v4/locales/sv.js
8314
8314
  var error35 = () => {
8315
8315
  const Sizable = {
8316
8316
  string: { unit: "tecken", verb: "att ha" },
@@ -8428,7 +8428,7 @@ function sv_default() {
8428
8428
  localeError: error35()
8429
8429
  };
8430
8430
  }
8431
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/ta.js
8431
+ // ../../node_modules/zod/v4/locales/ta.js
8432
8432
  var error36 = () => {
8433
8433
  const Sizable = {
8434
8434
  string: { unit: "எழுத்துக்கள்", verb: "கொண்டிருக்க வேண்டும்" },
@@ -8545,7 +8545,7 @@ function ta_default() {
8545
8545
  localeError: error36()
8546
8546
  };
8547
8547
  }
8548
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/th.js
8548
+ // ../../node_modules/zod/v4/locales/th.js
8549
8549
  var error37 = () => {
8550
8550
  const Sizable = {
8551
8551
  string: { unit: "ตัวอักษร", verb: "ควรมี" },
@@ -8662,7 +8662,7 @@ function th_default() {
8662
8662
  localeError: error37()
8663
8663
  };
8664
8664
  }
8665
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/tr.js
8665
+ // ../../node_modules/zod/v4/locales/tr.js
8666
8666
  var parsedType6 = (data) => {
8667
8667
  const t = typeof data;
8668
8668
  switch (t) {
@@ -8777,7 +8777,7 @@ function tr_default() {
8777
8777
  localeError: error38()
8778
8778
  };
8779
8779
  }
8780
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/uk.js
8780
+ // ../../node_modules/zod/v4/locales/uk.js
8781
8781
  var error39 = () => {
8782
8782
  const Sizable = {
8783
8783
  string: { unit: "символів", verb: "матиме" },
@@ -8894,11 +8894,11 @@ function uk_default() {
8894
8894
  };
8895
8895
  }
8896
8896
 
8897
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/ua.js
8897
+ // ../../node_modules/zod/v4/locales/ua.js
8898
8898
  function ua_default() {
8899
8899
  return uk_default();
8900
8900
  }
8901
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/ur.js
8901
+ // ../../node_modules/zod/v4/locales/ur.js
8902
8902
  var error40 = () => {
8903
8903
  const Sizable = {
8904
8904
  string: { unit: "حروف", verb: "ہونا" },
@@ -9015,7 +9015,7 @@ function ur_default() {
9015
9015
  localeError: error40()
9016
9016
  };
9017
9017
  }
9018
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/vi.js
9018
+ // ../../node_modules/zod/v4/locales/vi.js
9019
9019
  var error41 = () => {
9020
9020
  const Sizable = {
9021
9021
  string: { unit: "ký tự", verb: "có" },
@@ -9131,7 +9131,7 @@ function vi_default() {
9131
9131
  localeError: error41()
9132
9132
  };
9133
9133
  }
9134
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/zh-CN.js
9134
+ // ../../node_modules/zod/v4/locales/zh-CN.js
9135
9135
  var error42 = () => {
9136
9136
  const Sizable = {
9137
9137
  string: { unit: "字符", verb: "包含" },
@@ -9247,7 +9247,7 @@ function zh_CN_default() {
9247
9247
  localeError: error42()
9248
9248
  };
9249
9249
  }
9250
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/zh-TW.js
9250
+ // ../../node_modules/zod/v4/locales/zh-TW.js
9251
9251
  var error43 = () => {
9252
9252
  const Sizable = {
9253
9253
  string: { unit: "字元", verb: "擁有" },
@@ -9364,7 +9364,7 @@ function zh_TW_default() {
9364
9364
  localeError: error43()
9365
9365
  };
9366
9366
  }
9367
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/locales/yo.js
9367
+ // ../../node_modules/zod/v4/locales/yo.js
9368
9368
  var error44 = () => {
9369
9369
  const Sizable = {
9370
9370
  string: { unit: "àmi", verb: "ní" },
@@ -9479,7 +9479,7 @@ function yo_default() {
9479
9479
  localeError: error44()
9480
9480
  };
9481
9481
  }
9482
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/core/registries.js
9482
+ // ../../node_modules/zod/v4/core/registries.js
9483
9483
  var $output = Symbol("ZodOutput");
9484
9484
  var $input = Symbol("ZodInput");
9485
9485
 
@@ -9530,7 +9530,7 @@ function registry() {
9530
9530
  return new $ZodRegistry;
9531
9531
  }
9532
9532
  var globalRegistry = /* @__PURE__ */ registry();
9533
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/core/api.js
9533
+ // ../../node_modules/zod/v4/core/api.js
9534
9534
  function _string(Class2, params) {
9535
9535
  return new Class2({
9536
9536
  type: "string",
@@ -10408,7 +10408,7 @@ function _stringFormat(Class2, format, fnOrRegex, _params = {}) {
10408
10408
  const inst = new Class2(def);
10409
10409
  return inst;
10410
10410
  }
10411
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/core/to-json-schema.js
10411
+ // ../../node_modules/zod/v4/core/to-json-schema.js
10412
10412
  class JSONSchemaGenerator {
10413
10413
  constructor(params) {
10414
10414
  this.counter = 0;
@@ -11212,9 +11212,9 @@ function isTransforming(_schema, _ctx) {
11212
11212
  }
11213
11213
  throw new Error(`Unknown schema type: ${def.type}`);
11214
11214
  }
11215
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/core/json-schema.js
11215
+ // ../../node_modules/zod/v4/core/json-schema.js
11216
11216
  var exports_json_schema = {};
11217
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/classic/iso.js
11217
+ // ../../node_modules/zod/v4/classic/iso.js
11218
11218
  var exports_iso = {};
11219
11219
  __export(exports_iso, {
11220
11220
  time: () => time2,
@@ -11255,7 +11255,7 @@ function duration2(params) {
11255
11255
  return _isoDuration(ZodISODuration, params);
11256
11256
  }
11257
11257
 
11258
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/classic/errors.js
11258
+ // ../../node_modules/zod/v4/classic/errors.js
11259
11259
  var initializer2 = (inst, issues) => {
11260
11260
  $ZodError.init(inst, issues);
11261
11261
  inst.name = "ZodError";
@@ -11290,7 +11290,7 @@ var ZodRealError = $constructor("ZodError", initializer2, {
11290
11290
  Parent: Error
11291
11291
  });
11292
11292
 
11293
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/classic/parse.js
11293
+ // ../../node_modules/zod/v4/classic/parse.js
11294
11294
  var parse3 = /* @__PURE__ */ _parse(ZodRealError);
11295
11295
  var parseAsync2 = /* @__PURE__ */ _parseAsync(ZodRealError);
11296
11296
  var safeParse2 = /* @__PURE__ */ _safeParse(ZodRealError);
@@ -11304,7 +11304,7 @@ var safeDecode2 = /* @__PURE__ */ _safeDecode(ZodRealError);
11304
11304
  var safeEncodeAsync2 = /* @__PURE__ */ _safeEncodeAsync(ZodRealError);
11305
11305
  var safeDecodeAsync2 = /* @__PURE__ */ _safeDecodeAsync(ZodRealError);
11306
11306
 
11307
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/classic/schemas.js
11307
+ // ../../node_modules/zod/v4/classic/schemas.js
11308
11308
  var ZodType = /* @__PURE__ */ $constructor("ZodType", (inst, def) => {
11309
11309
  $ZodType.init(inst, def);
11310
11310
  inst.def = def;
@@ -12279,7 +12279,7 @@ function json(params) {
12279
12279
  function preprocess(fn, schema) {
12280
12280
  return pipe(transform(fn), schema);
12281
12281
  }
12282
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/classic/compat.js
12282
+ // ../../node_modules/zod/v4/classic/compat.js
12283
12283
  var ZodIssueCode = {
12284
12284
  invalid_type: "invalid_type",
12285
12285
  too_big: "too_big",
@@ -12303,7 +12303,7 @@ function getErrorMap() {
12303
12303
  }
12304
12304
  var ZodFirstPartyTypeKind;
12305
12305
  (function(ZodFirstPartyTypeKind2) {})(ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {}));
12306
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/classic/coerce.js
12306
+ // ../../node_modules/zod/v4/classic/coerce.js
12307
12307
  var exports_coerce = {};
12308
12308
  __export(exports_coerce, {
12309
12309
  string: () => string3,
@@ -12328,19 +12328,19 @@ function date4(params) {
12328
12328
  return _coercedDate(ZodDate, params);
12329
12329
  }
12330
12330
 
12331
- // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/classic/external.js
12331
+ // ../../node_modules/zod/v4/classic/external.js
12332
12332
  config(en_default());
12333
- // ../../node_modules/.bun/@opencode-ai+plugin@1.1.12/node_modules/@opencode-ai/plugin/dist/tool.js
12333
+ // ../../node_modules/@opencode-ai/plugin/dist/tool.js
12334
12334
  function tool(input) {
12335
12335
  return input;
12336
12336
  }
12337
12337
  tool.schema = exports_external;
12338
12338
  // src/skills/registry.generated.ts
12339
- var BUILTIN_SKILL_NAMES = ["brainstorming", "dispatching-parallel-agents", "executing-plans", "systematic-debugging", "test-driven-development", "verification-before-completion", "writing-plans"];
12339
+ var BUILTIN_SKILL_NAMES = ["brainstorming", "dispatching-parallel-agents", "executing-plans", "onboarding", "parallel-exploration", "systematic-debugging", "test-driven-development", "verification-before-completion", "writing-plans"];
12340
12340
  var BUILTIN_SKILLS = [
12341
12341
  {
12342
12342
  name: "brainstorming",
12343
- description: '"Use before any creative work - creating features, building components, adding functionality, or modifying behavior. Explores user intent, requirements and design before implementation."',
12343
+ description: "Use before any creative work - creating features, building components, adding functionality, or modifying behavior. Explores user intent, requirements and design before implementation.",
12344
12344
  template: `# Brainstorming Ideas Into Designs
12345
12345
 
12346
12346
  ## Overview
@@ -12642,6 +12642,351 @@ After all tasks complete and verified:
12642
12642
  - Reference skills when plan says to
12643
12643
  - Between batches: just report and wait
12644
12644
  - Stop when blocked, don't guess`
12645
+ },
12646
+ {
12647
+ name: "onboarding",
12648
+ description: "Ask about workflow preferences and store them in .hive/contexts/preferences.md before proceeding.",
12649
+ template: `# Onboarding Preferences
12650
+
12651
+ ## Overview
12652
+
12653
+ Gather workflow preferences so the assistant can match the user's desired working style.
12654
+
12655
+ ## When to Ask
12656
+
12657
+ - **Immediately when the skill is loaded**, before any other work.
12658
+ - If \`.hive/contexts/preferences.md\` does not exist, start onboarding.
12659
+ - If later a decision is ambiguous and preferences are missing, ask again.
12660
+
12661
+ ## Preference Storage
12662
+
12663
+ Use \`hive_context_write\` to write \`.hive/contexts/preferences.md\` with this exact template:
12664
+
12665
+ \`\`\`
12666
+ # Preferences
12667
+
12668
+ ## Exploration Style
12669
+ sync
12670
+
12671
+ ## Research Depth
12672
+ medium
12673
+
12674
+ ## Confirmation Level
12675
+ standard
12676
+
12677
+ ## Commit Behavior
12678
+ ask-before-commit
12679
+ \`\`\`
12680
+
12681
+ ## If Preferences Already Exist
12682
+
12683
+ Follow the same pattern used in \`packages/vscode-hive/src/tools/plan.ts\`:
12684
+
12685
+ 1. Use \`contextService.list(feature)\` to detect existing contexts.
12686
+ 2. Ask **"Preferences already exist. Keep or overwrite?"** using the \`question()\` tool.
12687
+ 3. If keep → continue using existing preferences.
12688
+ 4. If overwrite → collect new answers and write them with \`hive_context_write\`.
12689
+
12690
+ ## Questions to Ask (Always use \`question()\`)
12691
+
12692
+ Ask one at a time, with the provided options. Store the answers in \`.hive/contexts/preferences.md\`.
12693
+
12694
+ 1. **Exploration Style:** sync | async
12695
+ 2. **Research Depth:** shallow | medium | deep
12696
+ 3. **Confirmation Level:** minimal | standard | high
12697
+ 4. **Commit Behavior:** ask-before-commit | auto-commit | never-commit
12698
+
12699
+ ## Requirements
12700
+
12701
+ - Use the \`question()\` tool (no plain text questions).
12702
+ - Ask immediately when the skill loads if preferences are missing.
12703
+ - If later a decision is ambiguous and preferences are missing, ask again.
12704
+ - Always store answers using \`hive_context_write\` with the template above.`
12705
+ },
12706
+ {
12707
+ name: "parallel-exploration",
12708
+ description: "Use when you need parallel, read-only exploration via hive_hive_background_task (Scout fan-out)",
12709
+ template: `# Parallel Exploration (Background Scout Fan-Out)
12710
+
12711
+ ## Overview
12712
+
12713
+ When you need to answer "where/how does X work?" across multiple domains (codebase, tests, docs, OSS), investigating sequentially wastes time. Each investigation is independent and can happen in parallel.
12714
+
12715
+ **Core principle:** Decompose into independent sub-questions, spawn one \`hive_hive_background_task\` per sub-question, collect results asynchronously.
12716
+
12717
+ **Safe in Planning mode:** This is read-only exploration. It is OK to use during exploratory research even when there is no feature, no plan, and no approved tasks.
12718
+
12719
+ **This skill is for read-only research.** For parallel implementation work, use \`hive_skill("dispatching-parallel-agents")\` with \`hive_exec_start\`.
12720
+
12721
+ ## When to Use
12722
+
12723
+ **Default to this skill when:**
12724
+ **Use when:**
12725
+ - Investigation spans multiple domains (code + tests + docs)
12726
+ - User asks **2+ questions across different domains** (e.g., code + tests, code + docs/OSS, code + config/runtime)
12727
+ - Questions are independent (answer to A doesn't affect B)
12728
+ - User asks **3+ independent questions** (often as a numbered list or separate bullets)
12729
+ - No edits needed (read-only exploration)
12730
+ - User asks for an explorationthat likely spans multiple files/packages
12731
+ - The work is read-only and the questions can be investigated independently
12732
+
12733
+ **Only skip this skill when:**
12734
+ - Investigation requires shared state or context between questions
12735
+ - It's a single focused question that is genuinely answerable with **one quick grep + one file read**
12736
+ - Questions are dependent (answer A materially changes what to ask for B)
12737
+ - Work involves file edits (use Hive tasks / Forager instead)
12738
+
12739
+ **Important:** Do not treat "this is exploratory" as a reason to avoid delegation. This skill is specifically for exploratory research when fan-out makes it faster and cleaner.
12740
+
12741
+ ## The Pattern
12742
+
12743
+ ### 1. Decompose Into Independent Questions
12744
+
12745
+ Split your investigation into 2-4 independent sub-questions. Good decomposition:
12746
+
12747
+ | Domain | Question Example |
12748
+ |--------|------------------|
12749
+ | Codebase | "Where is X implemented? What files define it?" |
12750
+ | Tests | "How is X tested? What test patterns exist?" |
12751
+ | Docs/OSS | "How do other projects implement X? What's the recommended pattern?" |
12752
+ | Config | "How is X configured? What environment variables affect it?" |
12753
+
12754
+ **Bad decomposition (dependent questions):**
12755
+ - "What is X?" then "How is X used?" (second depends on first)
12756
+ - "Find the bug" then "Fix the bug" (not read-only)
12757
+
12758
+ ### 2. Spawn Background Tasks (Fan-Out)
12759
+
12760
+ Launch all tasks before waiting for any results:
12761
+
12762
+ \`\`\`typescript
12763
+ // Fan-out: spawn all tasks first
12764
+ hive_background_task({
12765
+ agent: "scout-researcher",
12766
+ description: "Find hive_background_task implementation",
12767
+ prompt: \`Where is hive_background_task implemented and registered?
12768
+ - Find the tool definition
12769
+ - Find the plugin registration
12770
+ - Return file paths with line numbers\`,
12771
+ sync: false
12772
+ })
12773
+
12774
+ hive_background_task({
12775
+ agent: "scout-researcher",
12776
+ description: "Analyze background task concurrency",
12777
+ prompt: \`How does background task concurrency/queueing work?
12778
+ - Find the manager/scheduler code
12779
+ - Document the concurrency model
12780
+ - Return file paths with evidence\`,
12781
+ sync: false
12782
+ })
12783
+
12784
+ hive_background_task({
12785
+ agent: "scout-researcher",
12786
+ description: "Find parent notification mechanism",
12787
+ prompt: \`How does parent notification work for background tasks?
12788
+ - Where is the notification built?
12789
+ - How is it sent to the parent session?
12790
+ - Return file paths with evidence\`,
12791
+ sync: false
12792
+ })
12793
+ \`\`\`
12794
+
12795
+ **Key points:**
12796
+ - Use \`agent: "scout-researcher"\` for read-only exploration
12797
+ - Use \`sync: false\` to return immediately (non-blocking)
12798
+ - Give each task a clear, focused \`description\`
12799
+ - Make prompts specific about what evidence to return
12800
+
12801
+ ### 3. Continue Working (Optional)
12802
+
12803
+ While tasks run, you can:
12804
+ - Work on other aspects of the problem
12805
+ - Prepare synthesis structure
12806
+ - Start drafting based on what you already know
12807
+
12808
+ You'll receive a \`<system-reminder>\` notification when each task completes.
12809
+
12810
+ ### 4. Collect Results
12811
+
12812
+ When notified of completion, retrieve results:
12813
+
12814
+ \`\`\`typescript
12815
+ // Get output from completed task
12816
+ hive_background_output({
12817
+ task_id: "task-abc123",
12818
+ block: false // Don't wait, task already done
12819
+ })
12820
+ \`\`\`
12821
+
12822
+ **For incremental output (long-running tasks):**
12823
+
12824
+ \`\`\`typescript
12825
+ // First call - get initial output
12826
+ hive_background_output({
12827
+ task_id: "task-abc123",
12828
+ block: true, // Wait for output
12829
+ timeout: 30000 // 30 second timeout
12830
+ })
12831
+ // Returns: { output: "...", cursor: "5" }
12832
+
12833
+ // Later call - get new output since cursor
12834
+ hive_background_output({
12835
+ task_id: "task-abc123",
12836
+ cursor: "5", // Resume from message 5
12837
+ block: true
12838
+ })
12839
+ \`\`\`
12840
+
12841
+ ### 5. Synthesize Findings
12842
+
12843
+ Combine results from all tasks:
12844
+ - Cross-reference findings (file X mentioned by tasks A and B)
12845
+ - Identify gaps (task C found nothing, need different approach)
12846
+ - Build coherent answer from parallel evidence
12847
+
12848
+ ### 6. Cleanup (If Needed)
12849
+
12850
+ Cancel tasks that are no longer needed:
12851
+
12852
+ \`\`\`typescript
12853
+ // Cancel specific task
12854
+ hive_background_cancel({ task_id: "task-abc123" })
12855
+
12856
+ // Cancel all your background tasks
12857
+ hive_background_cancel({ all: true })
12858
+ \`\`\`
12859
+
12860
+ ## Prompt Templates
12861
+
12862
+ ### Codebase Slice
12863
+
12864
+ \`\`\`
12865
+ Investigate [TOPIC] in the codebase:
12866
+ - Where is [X] defined/implemented?
12867
+ - What files contain [X]?
12868
+ - How does [X] interact with [Y]?
12869
+
12870
+ Return:
12871
+ - File paths with line numbers
12872
+ - Brief code snippets as evidence
12873
+ - Key patterns observed
12874
+ \`\`\`
12875
+
12876
+ ### Tests Slice
12877
+
12878
+ \`\`\`
12879
+ Investigate how [TOPIC] is tested:
12880
+ - What test files cover [X]?
12881
+ - What testing patterns are used?
12882
+ - What edge cases are tested?
12883
+
12884
+ Return:
12885
+ - Test file paths
12886
+ - Example test patterns
12887
+ - Coverage gaps if obvious
12888
+ \`\`\`
12889
+
12890
+ ### Docs/OSS Slice
12891
+
12892
+ \`\`\`
12893
+ Research [TOPIC] in external sources:
12894
+ - How do other projects implement [X]?
12895
+ - What does the official documentation say?
12896
+ - What are common patterns/anti-patterns?
12897
+
12898
+ Return:
12899
+ - Links to relevant docs/repos
12900
+ - Key recommendations
12901
+ - Patterns that apply to our codebase
12902
+ \`\`\`
12903
+
12904
+ ## Real Example
12905
+
12906
+ **Investigation:** "How does the background task system work?"
12907
+
12908
+ **Decomposition:**
12909
+ 1. Implementation: Where is \`hive_background_task\` tool defined?
12910
+ 2. Concurrency: How does task scheduling/queueing work?
12911
+ 3. Notifications: How does parent session get notified?
12912
+
12913
+ **Fan-out:**
12914
+ \`\`\`typescript
12915
+ // Task 1: Implementation
12916
+ hive_background_task({
12917
+ agent: "scout-researcher",
12918
+ description: "Find hive_background_task implementation",
12919
+ prompt: "Where is hive_background_task implemented? Find tool definition and registration.",
12920
+ sync: false
12921
+ })
12922
+
12923
+ // Task 2: Concurrency
12924
+ hive_background_task({
12925
+ agent: "scout-researcher",
12926
+ description: "Analyze concurrency model",
12927
+ prompt: "How does background task concurrency work? Find the manager/scheduler.",
12928
+ sync: false
12929
+ })
12930
+
12931
+ // Task 3: Notifications
12932
+ hive_background_task({
12933
+ agent: "scout-researcher",
12934
+ description: "Find notification mechanism",
12935
+ prompt: "How are parent sessions notified of task completion?",
12936
+ sync: false
12937
+ })
12938
+ \`\`\`
12939
+
12940
+ **Results:**
12941
+ - Task 1: Found \`background-tools.ts\` (tool definition), \`index.ts\` (registration)
12942
+ - Task 2: Found \`manager.ts\` with concurrency=3 default, queue-based scheduling
12943
+ - Task 3: Found \`session.prompt()\` call in manager for parent notification
12944
+
12945
+ **Synthesis:** Complete picture of background task lifecycle in ~1/3 the time of sequential investigation.
12946
+
12947
+ ## Common Mistakes
12948
+
12949
+ **Spawning sequentially (defeats the purpose):**
12950
+ \`\`\`typescript
12951
+ // BAD: Wait for each before spawning next
12952
+ const result1 = await hive_background_task({ ..., sync: true })
12953
+ const result2 = await hive_background_task({ ..., sync: true })
12954
+ \`\`\`
12955
+
12956
+ \`\`\`typescript
12957
+ // GOOD: Spawn all, then collect
12958
+ hive_background_task({ ..., sync: false }) // Returns immediately
12959
+ hive_background_task({ ..., sync: false }) // Returns immediately
12960
+ hive_background_task({ ..., sync: false }) // Returns immediately
12961
+ // ... later, collect results with hive_background_output
12962
+ \`\`\`
12963
+
12964
+ **Too many tasks (diminishing returns):**
12965
+ - 2-4 tasks: Good parallelization
12966
+ - 5+ tasks: Overhead exceeds benefit, harder to synthesize
12967
+
12968
+ **Dependent questions:**
12969
+ - Don't spawn task B if it needs task A's answer
12970
+ - Either make them independent or run sequentially
12971
+
12972
+ **Using for edits:**
12973
+ - Scout is read-only; use Forager for implementation
12974
+ - This skill is for exploration, not execution
12975
+
12976
+ ## Key Benefits
12977
+
12978
+ 1. **Speed** - 3 investigations in time of 1
12979
+ 2. **Focus** - Each Scout has narrow scope
12980
+ 3. **Independence** - No interference between tasks
12981
+ 4. **Flexibility** - Cancel unneeded tasks, add new ones
12982
+
12983
+ ## Verification
12984
+
12985
+ After using this pattern, verify:
12986
+ - [ ] All tasks spawned before collecting any results (true fan-out)
12987
+ - [ ] Received notifications for completed tasks
12988
+ - [ ] Successfully retrieved output with \`hive_background_output\`
12989
+ - [ ] Synthesized findings into coherent answer`
12645
12990
  },
12646
12991
  {
12647
12992
  name: "systematic-debugging",
@@ -13578,8 +13923,14 @@ function loadBuiltinSkill(name) {
13578
13923
  source: "builtin"
13579
13924
  };
13580
13925
  }
13581
- function getBuiltinSkills() {
13582
- return BUILTIN_SKILLS;
13926
+ function getFilteredSkills(disabledSkills = [], agentSkills) {
13927
+ const disabled = new Set(disabledSkills);
13928
+ let filtered = BUILTIN_SKILLS.filter((s) => !disabled.has(s.name));
13929
+ if (agentSkills && agentSkills.length > 0) {
13930
+ const enabled = new Set(agentSkills);
13931
+ filtered = filtered.filter((s) => enabled.has(s.name));
13932
+ }
13933
+ return filtered;
13583
13934
  }
13584
13935
 
13585
13936
  // src/agents/hive.ts
@@ -13610,13 +13961,22 @@ Run \`hive_status()\` or \`hive_feature_list()\` to detect phase:
13610
13961
  | Trivial | Single file, <10 lines | Do directly |
13611
13962
  | Simple | 1-2 files, <30 min | Light discovery → act |
13612
13963
  | Complex | 3+ files, multi-step | Full discovery → plan/delegate |
13613
- | Research | External data needed | Delegate to Scout (Explorer/Researcher/Retrieval) |
13964
+ | Research | Internal codebase exploration OR external data | Delegate to Scout (Explorer/Researcher/Retrieval) |
13965
+
13966
+ ### Canonical Delegation Threshold
13967
+
13968
+ - Delegate to Scout when you cannot name the file path upfront, expect to inspect 2+ files, or the question is open-ended ("how/where does X work?").
13969
+ - Prefer \`hive_background_task(agent: "scout-researcher", sync: true, ...)\` for single investigations; use \`sync: false\` only for multi-scout fan-out.
13970
+ - Local \`read/grep/glob\` is acceptable only for a single known file and a bounded question.
13614
13971
 
13615
13972
  ### Delegation
13616
13973
 
13617
- - Research/external data → \`task({ subagent_type: "scout", prompt: "..." })\`
13974
+ - Single-scout research → \`hive_background_task(agent: "scout-researcher", sync: true, ...)\` (blocks until complete, simpler flow)
13975
+ - Parallel exploration → Load \`hive_skill("parallel-exploration")\` and use \`hive_background_task(agent: "scout-researcher", sync: false, ...)\`
13618
13976
  - Implementation → \`hive_exec_start(task)\` (spawns Forager)
13619
13977
 
13978
+ During Planning, default to synchronous exploration (\`sync: true\`). If async/parallel exploration would help, ask the user via \`question()\`.
13979
+
13620
13980
  ### Context Persistence
13621
13981
 
13622
13982
  Save discoveries with \`hive_context_write\`:
@@ -13637,6 +13997,7 @@ Load when detailed guidance needed:
13637
13997
  - \`hive_skill("brainstorming")\` - exploring ideas and requirements
13638
13998
  - \`hive_skill("writing-plans")\` - structuring implementation plans
13639
13999
  - \`hive_skill("dispatching-parallel-agents")\` - parallel task delegation
14000
+ - \`hive_skill("parallel-exploration")\` - parallel read-only research via hive_background_task (Scout fan-out)
13640
14001
  - \`hive_skill("executing-plans")\` - step-by-step plan execution
13641
14002
 
13642
14003
  Load ONE skill at a time. Only when you need guidance beyond this prompt.
@@ -13685,9 +14046,9 @@ If yes → \`task({ subagent_type: "hygienic", prompt: "Review plan..." })\`
13685
14046
 
13686
14047
  ### Planning Iron Laws
13687
14048
 
13688
- - Research BEFORE asking (delegate to Scout if needed)
14049
+ - Research BEFORE asking (use \`hive_skill("parallel-exploration")\` for multi-domain research)
13689
14050
  - Save draft as working memory
13690
- - Don't execute - plan only
14051
+ - Don't implement (no edits/worktrees). Read-only exploration is allowed (local tools + Scout via hive_background_task).
13691
14052
 
13692
14053
  ---
13693
14054
 
@@ -13714,9 +14075,19 @@ hive_exec_start({ task: "01-task-name" }) // Creates worktree + Forager
13714
14075
 
13715
14076
  ### After Delegation
13716
14077
 
13717
- 1. \`hive_worker_status()\` - check progress
13718
- 2. Read reports for blockers
13719
- 3. If blocked: \`question()\` user decision \`continueFrom: "blocked"\`
14078
+ 1. Wait for the completion notification (no polling required)
14079
+ 2. Use \`hive_worker_status()\` for spot checks or if you suspect notifications did not deliver
14080
+ 3. Use \`hive_background_output\` only if interim output is explicitly needed, or after completion
14081
+ 4. When calling \`hive_background_output\`, choose a timeout (30-120s) based on task size
14082
+ 5. If blocked: \`question()\` → user decision → \`continueFrom: "blocked"\`
14083
+
14084
+ ### Observation Polling (Recommended)
14085
+
14086
+ - Prefer completion notifications over polling
14087
+ - Use \`hive_worker_status()\` for observation-based spot checks
14088
+ - Avoid tight loops with \`hive_background_output\`; if needed, wait 30-60s between checks
14089
+ - If you suspect notifications did not deliver, do a single \`hive_worker_status()\` check first
14090
+ - If you need to fetch final results, call \`hive_background_output({ task_id, block: false })\` after the completion notice
13720
14091
 
13721
14092
  ### Failure Recovery
13722
14093
 
@@ -13747,6 +14118,8 @@ hive_exec_start({ task: "01-task-name" }) // Creates worktree + Forager
13747
14118
  - Skip phase detection
13748
14119
  - Mix planning and orchestration in same action
13749
14120
  - Auto-load all skills at start
14121
+
14122
+ **User Input:** ALWAYS use \`question()\` tool for any user input - NEVER ask questions via plain text. This ensures structured responses.
13750
14123
  `;
13751
14124
 
13752
14125
  // src/agents/architect.ts
@@ -13762,7 +14135,9 @@ PLANNER, NOT IMPLEMENTER. "Do X" means "create plan for X".
13762
14135
  | Simple | 1-2 files, <30 min | Light interview → quick plan |
13763
14136
  | Complex | 3+ files, review needed | Full discovery → detailed plan |
13764
14137
  | Refactor | Existing code changes | Safety: tests, rollback, blast radius |
13765
- | Greenfield | New feature | Research patterns BEFORE asking (delegate to Scout (Explorer/Researcher/Retrieval) for external data) |
14138
+ | Greenfield | New feature | Research patterns BEFORE asking. Delegate to Scout via \`hive_background_task(agent: "scout-researcher", sync: true, ...)\` for single investigations. |
14139
+
14140
+ During Planning, default to synchronous exploration (\`sync: true\`). If async/parallel exploration would help, ask the user via \`question()\`.
13766
14141
 
13767
14142
  ## Self-Clearance Check (After Every Exchange)
13768
14143
 
@@ -13815,7 +14190,7 @@ Plan MUST include:
13815
14190
 
13816
14191
  **Never:**
13817
14192
  - Execute code (you plan, not implement)
13818
- - Delegate work or spawn workers (Swarm (Orchestrator) does this)
14193
+ - Spawn implementation/coding workers (Swarm (Orchestrator) does this); read-only research delegation to Scout is allowed
13819
14194
  - Use the task tool
13820
14195
  - Skip discovery for complex tasks
13821
14196
  - Assume when uncertain - ASK
@@ -13824,8 +14199,15 @@ Plan MUST include:
13824
14199
  - Classify intent FIRST
13825
14200
  - Run Self-Clearance after every exchange
13826
14201
  - Flag AI-Slop patterns
13827
- - Research BEFORE asking (greenfield); delegate external system data collection to Scout (Explorer/Researcher/Retrieval)
14202
+ - Research BEFORE asking (greenfield); delegate internal codebase exploration or external data collection to Scout
13828
14203
  - Save draft as working memory
14204
+
14205
+ ### Canonical Delegation Threshold
14206
+
14207
+ - Delegate to Scout when you cannot name the file path upfront, expect to inspect 2+ files, or the question is open-ended ("how/where does X work?").
14208
+ - Prefer \`hive_background_task(agent: "scout-researcher", sync: true, ...)\` for single investigations; use \`sync: false\` only for multi-scout fan-out.
14209
+ - Local \`read/grep/glob\` is acceptable only for a single known file and a bounded question.
14210
+ - When calling \`hive_background_output\`, choose a timeout (30-120s) based on task size.
13829
14211
  `;
13830
14212
 
13831
14213
  // src/agents/swarm.ts
@@ -13839,7 +14221,7 @@ Delegate by default. Work yourself only when trivial.
13839
14221
  |------|--------|--------|
13840
14222
  | Trivial | Single file, known location | Direct tools only |
13841
14223
  | Explicit | Specific file/line, clear command | Execute directly |
13842
- | Exploratory | "How does X work?" | Delegate to Scout (Explorer/Researcher/Retrieval) |
14224
+ | Exploratory | "How does X work?" | Delegate to Scout via hive_background_task(agent: "scout-researcher", sync: false, …). |
13843
14225
  | Open-ended | "Improve", "Refactor" | Assess first, then delegate |
13844
14226
  | Ambiguous | Unclear scope | Ask ONE clarifying question |
13845
14227
 
@@ -13848,7 +14230,8 @@ Delegate by default. Work yourself only when trivial.
13848
14230
  1. Is there a specialized agent that matches?
13849
14231
  2. Can I do it myself FOR SURE? REALLY?
13850
14232
  3. Does this require external system data (DBs/APIs/3rd-party tools)?
13851
- → If external data needed: DELEGATE to Scout (Explorer/Researcher/Retrieval)
14233
+ → If external data needed: Load \`hive_skill("parallel-exploration")\` for parallel Scout fan-out
14234
+ During Planning, default to synchronous exploration. If async exploration would help, ask the user via \`question()\` and follow the onboarding preferences.
13852
14235
  → Default: DELEGATE
13853
14236
 
13854
14237
  ## Delegation Prompt Structure (All 6 Sections)
@@ -13867,11 +14250,16 @@ Delegate by default. Work yourself only when trivial.
13867
14250
  \`\`\`
13868
14251
  hive_exec_start({ task: "01-task-name" })
13869
14252
  // If delegationRequired returned:
13870
- task({ subagent_type: "forager", prompt: "..." })
13871
- // If external system data is needed:
13872
- task({ subagent_type: "scout", prompt: "Collect external data from DB/API and summarize" })
14253
+ hive_background_task({ agent: "forager-worker", prompt: "...", sync: false })
14254
+ // If external system data is needed (parallel exploration):
14255
+ // Load hive_skill("parallel-exploration") for the full playbook, then:
14256
+ hive_background_task({ agent: "scout-researcher", prompt: "...", sync: false })
13873
14257
  \`\`\`
13874
14258
 
14259
+ **Sync Mode Guidance:**
14260
+ - \`sync: true\` — Use for single-scout research when you need the result before continuing
14261
+ - \`sync: false\` — Use for parallel fan-out (multiple scouts) or when you can proceed without waiting
14262
+
13875
14263
  ## After Delegation - ALWAYS VERIFY
13876
14264
 
13877
14265
  - Does it work as expected?
@@ -13914,7 +14302,9 @@ Merge only after verification passes.
13914
14302
  - Delegate by default
13915
14303
  - Verify delegate work
13916
14304
  - Use question() for user input (NEVER plain text)
13917
- - Cancel background tasks before completion
14305
+ - Cancel background tasks only when stale or no longer needed
14306
+
14307
+ **User Input:** ALWAYS use \`question()\` tool for any user input - NEVER ask questions via plain text. This ensures structured responses.
13918
14308
  `;
13919
14309
 
13920
14310
  // src/agents/scout.ts
@@ -15113,70 +15503,6 @@ var require_dist2 = __commonJS((exports) => {
15113
15503
  exports.createDeferred = deferred;
15114
15504
  exports.default = deferred;
15115
15505
  });
15116
- var require_strip_json_comments = __commonJS((exports, module) => {
15117
- var singleComment = 1;
15118
- var multiComment = 2;
15119
- function stripWithoutWhitespace() {
15120
- return "";
15121
- }
15122
- function stripWithWhitespace(str, start, end) {
15123
- return str.slice(start, end).replace(/\S/g, " ");
15124
- }
15125
- module.exports = function(str, opts) {
15126
- opts = opts || {};
15127
- var currentChar;
15128
- var nextChar;
15129
- var insideString = false;
15130
- var insideComment = false;
15131
- var offset = 0;
15132
- var ret = "";
15133
- var strip = opts.whitespace === false ? stripWithoutWhitespace : stripWithWhitespace;
15134
- for (var i = 0;i < str.length; i++) {
15135
- currentChar = str[i];
15136
- nextChar = str[i + 1];
15137
- if (!insideComment && currentChar === '"') {
15138
- var escaped = str[i - 1] === "\\" && str[i - 2] !== "\\";
15139
- if (!escaped) {
15140
- insideString = !insideString;
15141
- }
15142
- }
15143
- if (insideString) {
15144
- continue;
15145
- }
15146
- if (!insideComment && currentChar + nextChar === "//") {
15147
- ret += str.slice(offset, i);
15148
- offset = i;
15149
- insideComment = singleComment;
15150
- i++;
15151
- } else if (insideComment === singleComment && currentChar + nextChar === `\r
15152
- `) {
15153
- i++;
15154
- insideComment = false;
15155
- ret += strip(str, offset, i);
15156
- offset = i;
15157
- continue;
15158
- } else if (insideComment === singleComment && currentChar === `
15159
- `) {
15160
- insideComment = false;
15161
- ret += strip(str, offset, i);
15162
- offset = i;
15163
- } else if (!insideComment && currentChar + nextChar === "/*") {
15164
- ret += str.slice(offset, i);
15165
- offset = i;
15166
- insideComment = multiComment;
15167
- i++;
15168
- continue;
15169
- } else if (insideComment === multiComment && currentChar + nextChar === "*/") {
15170
- i++;
15171
- insideComment = false;
15172
- ret += strip(str, offset, i + 1);
15173
- offset = i + 1;
15174
- continue;
15175
- }
15176
- }
15177
- return ret + (insideComment ? strip(str.substr(offset)) : str.substr(offset));
15178
- };
15179
- });
15180
15506
  var DEFAULT_AGENT_MODELS = {
15181
15507
  "hive-master": "github-copilot/claude-opus-4.5",
15182
15508
  "architect-planner": "github-copilot/gpt-5.2-codex",
@@ -15188,6 +15514,10 @@ var DEFAULT_AGENT_MODELS = {
15188
15514
  var DEFAULT_HIVE_CONFIG = {
15189
15515
  $schema: "https://raw.githubusercontent.com/tctinh/agent-hive/main/packages/opencode-hive/schema/agent_hive.schema.json",
15190
15516
  enableToolsFor: [],
15517
+ disableSkills: [],
15518
+ disableMcps: [],
15519
+ agentMode: "unified",
15520
+ delegateMode: "task",
15191
15521
  agents: {
15192
15522
  "hive-master": {
15193
15523
  model: DEFAULT_AGENT_MODELS["hive-master"],
@@ -15197,32 +15527,37 @@ var DEFAULT_HIVE_CONFIG = {
15197
15527
  "writing-plans",
15198
15528
  "dispatching-parallel-agents",
15199
15529
  "executing-plans"
15200
- ]
15530
+ ],
15531
+ autoLoadSkills: ["parallel-exploration"]
15201
15532
  },
15202
15533
  "architect-planner": {
15203
15534
  model: DEFAULT_AGENT_MODELS["architect-planner"],
15204
15535
  temperature: 0.7,
15205
- skills: ["brainstorming", "writing-plans"]
15536
+ skills: ["brainstorming", "writing-plans"],
15537
+ autoLoadSkills: ["parallel-exploration"]
15206
15538
  },
15207
15539
  "swarm-orchestrator": {
15208
15540
  model: DEFAULT_AGENT_MODELS["swarm-orchestrator"],
15209
15541
  temperature: 0.5,
15210
- skills: ["dispatching-parallel-agents", "executing-plans"]
15542
+ skills: ["dispatching-parallel-agents", "executing-plans"],
15543
+ autoLoadSkills: []
15211
15544
  },
15212
15545
  "scout-researcher": {
15213
15546
  model: DEFAULT_AGENT_MODELS["scout-researcher"],
15214
15547
  temperature: 0.5,
15215
- skills: []
15548
+ skills: [],
15549
+ autoLoadSkills: ["parallel-exploration"]
15216
15550
  },
15217
15551
  "forager-worker": {
15218
15552
  model: DEFAULT_AGENT_MODELS["forager-worker"],
15219
15553
  temperature: 0.3,
15220
- skills: ["test-driven-development", "verification-before-completion"]
15554
+ autoLoadSkills: ["test-driven-development", "verification-before-completion"]
15221
15555
  },
15222
15556
  "hygienic-reviewer": {
15223
15557
  model: DEFAULT_AGENT_MODELS["hygienic-reviewer"],
15224
15558
  temperature: 0.3,
15225
- skills: ["systematic-debugging"]
15559
+ skills: ["systematic-debugging"],
15560
+ autoLoadSkills: []
15226
15561
  }
15227
15562
  }
15228
15563
  };
@@ -16095,7 +16430,7 @@ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
16095
16430
  var __esm = (fn, res) => function __init() {
16096
16431
  return fn && (res = (0, fn[__getOwnPropNames2(fn)[0]])(fn = 0)), res;
16097
16432
  };
16098
- var __commonJS2 = (cb, mod) => function __require() {
16433
+ var __commonJS2 = (cb, mod) => function __require22() {
16099
16434
  return mod || (0, cb[__getOwnPropNames2(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
16100
16435
  };
16101
16436
  var __export2 = (target, all) => {
@@ -20586,8 +20921,6 @@ ${f.content}`);
20586
20921
  return `${normalized}.md`;
20587
20922
  }
20588
20923
  }
20589
- var import_strip_json_comments = __toESM(require_strip_json_comments(), 1);
20590
-
20591
20924
  class ConfigService {
20592
20925
  configPath;
20593
20926
  constructor() {
@@ -20667,42 +21000,42 @@ class ConfigService {
20667
21000
  }
20668
21001
  return this.get();
20669
21002
  }
20670
- registerAgentsInOpenCode(agents) {
20671
- const homeDir = process.env.HOME || process.env.USERPROFILE || "";
20672
- const opencodePath = path6.join(homeDir, ".config", "opencode", "opencode.json");
20673
- try {
20674
- if (!fs10.existsSync(opencodePath)) {
20675
- return;
20676
- }
20677
- const raw = fs10.readFileSync(opencodePath, "utf-8");
20678
- const config2 = JSON.parse(import_strip_json_comments.default(raw));
20679
- if (!config2.agent) {
20680
- config2.agent = {};
20681
- }
20682
- for (const [name, agentConfig] of Object.entries(agents)) {
20683
- if (!config2.agent[name]) {
20684
- config2.agent[name] = agentConfig;
20685
- } else {
20686
- config2.agent[name] = {
20687
- ...agentConfig,
20688
- model: config2.agent[name].model || agentConfig.model,
20689
- temperature: config2.agent[name].temperature ?? agentConfig.temperature
20690
- };
20691
- }
20692
- }
20693
- fs10.writeFileSync(opencodePath, JSON.stringify(config2, null, 2));
20694
- } catch (err) {
20695
- console.error("[Hive] Failed to register agents in opencode.json:", err);
20696
- }
20697
- }
20698
21003
  getAgentConfig(agent) {
20699
21004
  const config2 = this.get();
20700
- return config2.agents?.[agent] ?? {};
21005
+ const agentConfig = config2.agents?.[agent] ?? {};
21006
+ const defaultAutoLoadSkills = DEFAULT_HIVE_CONFIG.agents?.[agent]?.autoLoadSkills ?? [];
21007
+ const userAutoLoadSkills = agentConfig.autoLoadSkills ?? [];
21008
+ const isPlannerAgent = agent === "hive-master" || agent === "architect-planner";
21009
+ const effectiveUserAutoLoadSkills = isPlannerAgent ? userAutoLoadSkills : userAutoLoadSkills.filter((skill) => skill !== "onboarding");
21010
+ const effectiveDefaultAutoLoadSkills = isPlannerAgent ? defaultAutoLoadSkills : defaultAutoLoadSkills.filter((skill) => skill !== "onboarding");
21011
+ const combinedAutoLoadSkills = [...effectiveDefaultAutoLoadSkills, ...effectiveUserAutoLoadSkills];
21012
+ const uniqueAutoLoadSkills = Array.from(new Set(combinedAutoLoadSkills));
21013
+ const disabledSkills = config2.disableSkills ?? [];
21014
+ const effectiveAutoLoadSkills = uniqueAutoLoadSkills.filter((skill) => !disabledSkills.includes(skill));
21015
+ return {
21016
+ ...agentConfig,
21017
+ autoLoadSkills: effectiveAutoLoadSkills
21018
+ };
20701
21019
  }
20702
21020
  isOmoSlimEnabled() {
20703
21021
  const config2 = this.get();
20704
21022
  return config2.omoSlimEnabled === true;
20705
21023
  }
21024
+ getDisabledSkills() {
21025
+ const config2 = this.get();
21026
+ return config2.disableSkills ?? [];
21027
+ }
21028
+ getDisabledMcps() {
21029
+ const config2 = this.get();
21030
+ return config2.disableMcps ?? [];
21031
+ }
21032
+ getDelegateMode() {
21033
+ const config2 = this.get();
21034
+ return config2.delegateMode ?? "task";
21035
+ }
21036
+ isHiveBackgroundEnabled() {
21037
+ return this.getDelegateMode() === "hive";
21038
+ }
20706
21039
  }
20707
21040
 
20708
21041
  // src/utils/worker-prompt.ts
@@ -20713,18 +21046,9 @@ function buildWorkerPrompt(params) {
20713
21046
  taskOrder,
20714
21047
  worktreePath,
20715
21048
  branch,
20716
- plan,
20717
- contextFiles,
20718
21049
  spec,
20719
- previousTasks,
20720
21050
  continueFrom
20721
21051
  } = params;
20722
- const contextSection = contextFiles.length > 0 ? contextFiles.map((f) => `### ${f.name}
20723
- ${f.content}`).join(`
20724
-
20725
- `) : "_No context files available._";
20726
- const previousSection = previousTasks?.length ? previousTasks.map((t) => `- **${t.name}**: ${t.summary}`).join(`
20727
- `) : "_This is the first task._";
20728
21052
  const continuationSection = continueFrom ? `
20729
21053
  ## Continuation from Blocked State
20730
21054
 
@@ -20758,24 +21082,6 @@ Do NOT modify files outside this directory.
20758
21082
  ${continuationSection}
20759
21083
  ---
20760
21084
 
20761
- ## Plan Context
20762
-
20763
- ${plan}
20764
-
20765
- ---
20766
-
20767
- ## Context Files (Royal Jelly)
20768
-
20769
- ${contextSection}
20770
-
20771
- ---
20772
-
20773
- ## Previous Tasks Completed
20774
-
20775
- ${previousSection}
20776
-
20777
- ---
20778
-
20779
21085
  ## Your Mission
20780
21086
 
20781
21087
  ${spec}
@@ -20890,7 +21196,7 @@ After 3 failed attempts at same fix: STOP and report blocker.
20890
21196
  - \`question\` - Escalate via blocker protocol instead
20891
21197
  - \`hive_exec_start\` - No spawning sub-workers
20892
21198
  - \`hive_merge\` - Only Hive Master merges
20893
- - \`background_task\` / \`task\` - No recursive delegation
21199
+ - \`hive_background_task\` / \`task\` - No recursive delegation
20894
21200
 
20895
21201
  ---
20896
21202
 
@@ -20904,10 +21210,305 @@ After 3 failed attempts at same fix: STOP and report blocker.
20904
21210
 
20905
21211
  ---
20906
21212
 
21213
+ **User Input:** ALWAYS use \`question()\` tool for any user input - NEVER ask questions via plain text. This ensures structured responses.
21214
+
21215
+ ---
21216
+
20907
21217
  Begin your task now.
20908
21218
  `;
20909
21219
  }
20910
21220
 
21221
+ // src/utils/prompt-observability.ts
21222
+ var DEFAULT_THRESHOLDS = {
21223
+ workerPromptMaxChars: 1e5,
21224
+ jsonPayloadMaxChars: 150000,
21225
+ contextMaxChars: 50000,
21226
+ previousTasksMaxChars: 20000,
21227
+ planMaxChars: 30000
21228
+ };
21229
+ function calculatePromptMeta(inputs) {
21230
+ return {
21231
+ planChars: safeLength(inputs.plan),
21232
+ contextChars: safeLength(inputs.context),
21233
+ previousTasksChars: safeLength(inputs.previousTasks),
21234
+ specChars: safeLength(inputs.spec),
21235
+ workerPromptChars: safeLength(inputs.workerPrompt)
21236
+ };
21237
+ }
21238
+ function calculatePayloadMeta(inputs) {
21239
+ return {
21240
+ jsonPayloadChars: safeLength(inputs.jsonPayload),
21241
+ promptInlined: inputs.promptInlined,
21242
+ promptReferencedByFile: inputs.promptReferencedByFile ?? !inputs.promptInlined
21243
+ };
21244
+ }
21245
+ function checkWarnings(promptMeta, payloadMeta, thresholds = {}) {
21246
+ const t = { ...DEFAULT_THRESHOLDS, ...thresholds };
21247
+ const warnings = [];
21248
+ if (promptMeta.workerPromptChars > t.workerPromptMaxChars) {
21249
+ const severity = getSeverity(promptMeta.workerPromptChars, t.workerPromptMaxChars);
21250
+ warnings.push({
21251
+ type: "workerPromptSize",
21252
+ severity,
21253
+ message: `Worker prompt size (${formatBytes(promptMeta.workerPromptChars)}) exceeds threshold (${formatBytes(t.workerPromptMaxChars)})`,
21254
+ currentValue: promptMeta.workerPromptChars,
21255
+ threshold: t.workerPromptMaxChars
21256
+ });
21257
+ }
21258
+ if (payloadMeta.jsonPayloadChars > t.jsonPayloadMaxChars) {
21259
+ const severity = getSeverity(payloadMeta.jsonPayloadChars, t.jsonPayloadMaxChars);
21260
+ warnings.push({
21261
+ type: "jsonPayloadSize",
21262
+ severity,
21263
+ message: `JSON payload size (${formatBytes(payloadMeta.jsonPayloadChars)}) exceeds threshold (${formatBytes(t.jsonPayloadMaxChars)})`,
21264
+ currentValue: payloadMeta.jsonPayloadChars,
21265
+ threshold: t.jsonPayloadMaxChars
21266
+ });
21267
+ }
21268
+ if (promptMeta.contextChars > t.contextMaxChars) {
21269
+ const severity = getSeverity(promptMeta.contextChars, t.contextMaxChars);
21270
+ warnings.push({
21271
+ type: "contextSize",
21272
+ severity,
21273
+ message: `Context size (${formatBytes(promptMeta.contextChars)}) exceeds threshold (${formatBytes(t.contextMaxChars)})`,
21274
+ currentValue: promptMeta.contextChars,
21275
+ threshold: t.contextMaxChars
21276
+ });
21277
+ }
21278
+ if (promptMeta.previousTasksChars > t.previousTasksMaxChars) {
21279
+ const severity = getSeverity(promptMeta.previousTasksChars, t.previousTasksMaxChars);
21280
+ warnings.push({
21281
+ type: "previousTasksSize",
21282
+ severity,
21283
+ message: `Previous tasks size (${formatBytes(promptMeta.previousTasksChars)}) exceeds threshold (${formatBytes(t.previousTasksMaxChars)})`,
21284
+ currentValue: promptMeta.previousTasksChars,
21285
+ threshold: t.previousTasksMaxChars
21286
+ });
21287
+ }
21288
+ if (t.planMaxChars && promptMeta.planChars > t.planMaxChars) {
21289
+ const severity = getSeverity(promptMeta.planChars, t.planMaxChars);
21290
+ warnings.push({
21291
+ type: "planSize",
21292
+ severity,
21293
+ message: `Plan size (${formatBytes(promptMeta.planChars)}) exceeds threshold (${formatBytes(t.planMaxChars)})`,
21294
+ currentValue: promptMeta.planChars,
21295
+ threshold: t.planMaxChars
21296
+ });
21297
+ }
21298
+ return warnings;
21299
+ }
21300
+ function safeLength(str) {
21301
+ if (str == null)
21302
+ return 0;
21303
+ return str.length;
21304
+ }
21305
+ function getSeverity(value, threshold) {
21306
+ const ratio = value / threshold;
21307
+ if (ratio > 2)
21308
+ return "critical";
21309
+ if (ratio > 1.5)
21310
+ return "warning";
21311
+ return "info";
21312
+ }
21313
+ function formatBytes(chars) {
21314
+ if (chars < 1000)
21315
+ return `${chars} chars`;
21316
+ if (chars < 1e6)
21317
+ return `${(chars / 1000).toFixed(1)}K chars`;
21318
+ return `${(chars / 1e6).toFixed(2)}M chars`;
21319
+ }
21320
+
21321
+ // src/utils/prompt-budgeting.ts
21322
+ var DEFAULT_BUDGET = {
21323
+ maxTasks: 10,
21324
+ maxSummaryChars: 2000,
21325
+ maxContextChars: 20000,
21326
+ maxTotalContextChars: 60000
21327
+ };
21328
+ var TRUNCATION_MARKER = "...[truncated]";
21329
+ function truncateWithMarker(str, maxLength) {
21330
+ if (str.length <= maxLength) {
21331
+ return { result: str, truncated: false };
21332
+ }
21333
+ const cutoff = maxLength - TRUNCATION_MARKER.length;
21334
+ if (cutoff <= 0) {
21335
+ return { result: TRUNCATION_MARKER, truncated: true };
21336
+ }
21337
+ return {
21338
+ result: str.slice(0, cutoff) + TRUNCATION_MARKER,
21339
+ truncated: true
21340
+ };
21341
+ }
21342
+ function applyTaskBudget(tasks, config2 = {}) {
21343
+ const maxTasks = config2.maxTasks ?? DEFAULT_BUDGET.maxTasks;
21344
+ const maxSummaryChars = config2.maxSummaryChars ?? DEFAULT_BUDGET.maxSummaryChars;
21345
+ const feature = config2.feature;
21346
+ const truncationEvents = [];
21347
+ let droppedTasksHint;
21348
+ if (tasks.length === 0) {
21349
+ return { tasks: [], truncationEvents: [] };
21350
+ }
21351
+ let selectedTasks = tasks;
21352
+ const droppedTasks = [];
21353
+ if (tasks.length > maxTasks) {
21354
+ const dropCount = tasks.length - maxTasks;
21355
+ droppedTasks.push(...tasks.slice(0, dropCount).map((t) => t.name));
21356
+ selectedTasks = tasks.slice(dropCount);
21357
+ truncationEvents.push({
21358
+ type: "tasks_dropped",
21359
+ message: `Dropped ${dropCount} older task(s) to stay within budget of ${maxTasks}`,
21360
+ count: dropCount,
21361
+ affected: droppedTasks
21362
+ });
21363
+ if (feature) {
21364
+ droppedTasksHint = `Dropped tasks: ${droppedTasks.join(", ")}. Full reports available at .hive/features/${feature}/tasks/<task>/report.md`;
21365
+ } else {
21366
+ droppedTasksHint = `Dropped tasks: ${droppedTasks.join(", ")}. Full reports available in task directories.`;
21367
+ }
21368
+ }
21369
+ const budgetedTasks = selectedTasks.map((task) => {
21370
+ const { result, truncated } = truncateWithMarker(task.summary, maxSummaryChars);
21371
+ if (truncated) {
21372
+ truncationEvents.push({
21373
+ type: "summary_truncated",
21374
+ message: `Truncated summary for task "${task.name}" from ${task.summary.length} to ${result.length} chars`,
21375
+ affected: [task.name]
21376
+ });
21377
+ }
21378
+ return {
21379
+ name: task.name,
21380
+ summary: result,
21381
+ truncated,
21382
+ originalLength: truncated ? task.summary.length : undefined
21383
+ };
21384
+ });
21385
+ return {
21386
+ tasks: budgetedTasks,
21387
+ truncationEvents,
21388
+ droppedTasksHint
21389
+ };
21390
+ }
21391
+ function applyContextBudget(files, config2 = {}) {
21392
+ const maxContextChars = config2.maxContextChars ?? DEFAULT_BUDGET.maxContextChars;
21393
+ const maxTotalContextChars = config2.maxTotalContextChars ?? DEFAULT_BUDGET.maxTotalContextChars;
21394
+ const feature = config2.feature;
21395
+ const truncationEvents = [];
21396
+ const namesOnlyFiles = [];
21397
+ if (files.length === 0) {
21398
+ return { files: [], truncationEvents: [] };
21399
+ }
21400
+ const budgetedFiles = [];
21401
+ let totalChars = 0;
21402
+ let switchedToNamesOnly = false;
21403
+ for (const file2 of files) {
21404
+ const pathHint = feature ? `.hive/features/${feature}/context/${file2.name}.md` : `context/${file2.name}.md`;
21405
+ if (totalChars >= maxTotalContextChars && !switchedToNamesOnly) {
21406
+ switchedToNamesOnly = true;
21407
+ truncationEvents.push({
21408
+ type: "context_names_only",
21409
+ message: `Switched to name-only listing after ${totalChars} chars (budget: ${maxTotalContextChars})`,
21410
+ affected: files.slice(files.indexOf(file2)).map((f) => f.name)
21411
+ });
21412
+ }
21413
+ if (switchedToNamesOnly) {
21414
+ namesOnlyFiles.push(file2.name);
21415
+ budgetedFiles.push({
21416
+ name: file2.name,
21417
+ content: `[Content available at: ${pathHint}]`,
21418
+ truncated: true,
21419
+ originalLength: file2.content.length,
21420
+ pathHint
21421
+ });
21422
+ continue;
21423
+ }
21424
+ const { result, truncated } = truncateWithMarker(file2.content, maxContextChars);
21425
+ if (truncated) {
21426
+ truncationEvents.push({
21427
+ type: "context_truncated",
21428
+ message: `Truncated context file "${file2.name}" from ${file2.content.length} to ${result.length} chars. Full content at: ${pathHint}`,
21429
+ affected: [file2.name]
21430
+ });
21431
+ }
21432
+ budgetedFiles.push({
21433
+ name: file2.name,
21434
+ content: result,
21435
+ truncated,
21436
+ originalLength: truncated ? file2.content.length : undefined,
21437
+ pathHint: truncated ? pathHint : undefined
21438
+ });
21439
+ totalChars += result.length;
21440
+ }
21441
+ return {
21442
+ files: budgetedFiles,
21443
+ truncationEvents,
21444
+ namesOnlyFiles: namesOnlyFiles.length > 0 ? namesOnlyFiles : undefined
21445
+ };
21446
+ }
21447
+
21448
+ // src/utils/prompt-file.ts
21449
+ import * as fs6 from "fs";
21450
+ import * as path5 from "path";
21451
+ function findWorkspaceRoot(startDir) {
21452
+ try {
21453
+ let current = path5.resolve(startDir);
21454
+ while (true) {
21455
+ const hivePath = path5.join(current, ".hive");
21456
+ if (fs6.existsSync(hivePath) && fs6.statSync(hivePath).isDirectory()) {
21457
+ return current;
21458
+ }
21459
+ const parent = path5.dirname(current);
21460
+ if (parent === current) {
21461
+ return null;
21462
+ }
21463
+ current = parent;
21464
+ }
21465
+ } catch {
21466
+ return null;
21467
+ }
21468
+ }
21469
+ function isValidPromptFilePath(filePath, workspaceRoot) {
21470
+ try {
21471
+ const normalizedFilePath = path5.resolve(filePath);
21472
+ const normalizedWorkspace = path5.resolve(workspaceRoot);
21473
+ if (!normalizedFilePath.startsWith(normalizedWorkspace + path5.sep) && normalizedFilePath !== normalizedWorkspace) {
21474
+ return false;
21475
+ }
21476
+ return true;
21477
+ } catch {
21478
+ return false;
21479
+ }
21480
+ }
21481
+ async function resolvePromptFromFile(promptFilePath, workspaceRoot) {
21482
+ if (!isValidPromptFilePath(promptFilePath, workspaceRoot)) {
21483
+ return {
21484
+ error: `Prompt file path "${promptFilePath}" is outside the workspace. ` + `Only files within "${workspaceRoot}" are allowed.`
21485
+ };
21486
+ }
21487
+ const resolvedPath = path5.resolve(promptFilePath);
21488
+ if (!fs6.existsSync(resolvedPath)) {
21489
+ return {
21490
+ error: `Prompt file not found: "${resolvedPath}"`
21491
+ };
21492
+ }
21493
+ try {
21494
+ const content = fs6.readFileSync(resolvedPath, "utf-8");
21495
+ return { content };
21496
+ } catch (err) {
21497
+ return {
21498
+ error: `Failed to read prompt file: ${err instanceof Error ? err.message : "Unknown error"}`
21499
+ };
21500
+ }
21501
+ }
21502
+ function writeWorkerPromptFile(feature, task, prompt, hiveDir) {
21503
+ const promptDir = path5.join(hiveDir, "features", feature, "tasks", task);
21504
+ const promptPath = path5.join(promptDir, "worker-prompt.md");
21505
+ if (!fs6.existsSync(promptDir)) {
21506
+ fs6.mkdirSync(promptDir, { recursive: true });
21507
+ }
21508
+ fs6.writeFileSync(promptPath, prompt, "utf-8");
21509
+ return promptPath;
21510
+ }
21511
+
20911
21512
  // src/background/types.ts
20912
21513
  var VALID_TRANSITIONS = {
20913
21514
  spawned: ["pending", "running", "error", "cancelled"],
@@ -21232,7 +21833,7 @@ class ConcurrencyManager {
21232
21833
  this.lastStartTimes.set(key, Date.now());
21233
21834
  return;
21234
21835
  }
21235
- return new Promise((resolve, reject) => {
21836
+ return new Promise((resolve2, reject) => {
21236
21837
  const queue = this.queues.get(key) ?? [];
21237
21838
  const entry = {
21238
21839
  resolve: () => {
@@ -21241,7 +21842,7 @@ class ConcurrencyManager {
21241
21842
  entry.settled = true;
21242
21843
  clearTimeout(entry.timeoutId);
21243
21844
  this.lastStartTimes.set(key, Date.now());
21244
- resolve();
21845
+ resolve2();
21245
21846
  },
21246
21847
  reject: (error45) => {
21247
21848
  if (entry.settled)
@@ -21372,7 +21973,7 @@ class ConcurrencyManager {
21372
21973
  const elapsed = Date.now() - lastStart;
21373
21974
  const delay2 = this.config.minDelayBetweenStartsMs - elapsed;
21374
21975
  if (delay2 > 0) {
21375
- await new Promise((resolve) => setTimeout(resolve, delay2));
21976
+ await new Promise((resolve2) => setTimeout(resolve2, delay2));
21376
21977
  }
21377
21978
  }
21378
21979
  }
@@ -21700,6 +22301,7 @@ class BackgroundManager {
21700
22301
  }
21701
22302
  this.store.updateStatus(task.taskId, "running");
21702
22303
  this.poller.start();
22304
+ const normalizedVariant = options.variant?.trim() || undefined;
21703
22305
  this.client.session.prompt({
21704
22306
  path: { id: sessionId },
21705
22307
  body: {
@@ -21708,7 +22310,8 @@ class BackgroundManager {
21708
22310
  tools: {
21709
22311
  background_task: false,
21710
22312
  delegate: false
21711
- }
22313
+ },
22314
+ ...normalizedVariant !== undefined && { variant: normalizedVariant }
21712
22315
  }
21713
22316
  }).catch((error45) => {
21714
22317
  this.updateStatus(task.taskId, "error", { errorMessage: error45.message });
@@ -21883,8 +22486,58 @@ Use \`background_output({ task_id: "${task.taskId}" })\` to retrieve the result.
21883
22486
  function createBackgroundManager(options) {
21884
22487
  return new BackgroundManager(options);
21885
22488
  }
22489
+ // src/utils/format.ts
22490
+ function formatElapsed(ms) {
22491
+ const totalSeconds = Math.max(0, Math.floor(ms / 1000));
22492
+ if (totalSeconds < 60) {
22493
+ return `${totalSeconds}s`;
22494
+ }
22495
+ const totalMinutes = Math.floor(totalSeconds / 60);
22496
+ const seconds = totalSeconds % 60;
22497
+ if (totalMinutes < 60) {
22498
+ return `${totalMinutes}m ${seconds}s`;
22499
+ }
22500
+ const hours = Math.floor(totalMinutes / 60);
22501
+ const minutes = totalMinutes % 60;
22502
+ return `${hours}h ${minutes}m`;
22503
+ }
22504
+ function formatRelativeTime(isoDate) {
22505
+ const timestamp = new Date(isoDate).getTime();
22506
+ const now = Date.now();
22507
+ const elapsedMs = Math.max(0, now - timestamp);
22508
+ const totalSeconds = Math.max(0, Math.floor(elapsedMs / 1000));
22509
+ if (totalSeconds < 60) {
22510
+ return `${totalSeconds}s ago`;
22511
+ }
22512
+ const totalMinutes = Math.floor(totalSeconds / 60);
22513
+ if (totalMinutes < 60) {
22514
+ return `${totalMinutes}m ago`;
22515
+ }
22516
+ const totalHours = Math.floor(totalMinutes / 60);
22517
+ return `${totalHours}h ago`;
22518
+ }
22519
+
22520
+ // src/hooks/variant-hook.ts
22521
+ var HIVE_AGENT_NAMES = [
22522
+ "hive-master",
22523
+ "architect-planner",
22524
+ "swarm-orchestrator",
22525
+ "scout-researcher",
22526
+ "forager-worker",
22527
+ "hygienic-reviewer"
22528
+ ];
22529
+ function isHiveAgent(agent) {
22530
+ return agent !== undefined && HIVE_AGENT_NAMES.includes(agent);
22531
+ }
22532
+ function normalizeVariant(variant) {
22533
+ if (variant === undefined)
22534
+ return;
22535
+ const trimmed2 = variant.trim();
22536
+ return trimmed2.length > 0 ? trimmed2 : undefined;
22537
+ }
22538
+
21886
22539
  // src/tools/background-tools.ts
21887
- function createBackgroundTools(manager, client) {
22540
+ function createBackgroundTools(manager, client, configService) {
21888
22541
  async function maybeFinalizeIfIdle(sessionId) {
21889
22542
  try {
21890
22543
  const statusFn = client.session.status;
@@ -21908,11 +22561,12 @@ function createBackgroundTools(manager, client) {
21908
22561
  } catch {}
21909
22562
  }
21910
22563
  return {
21911
- background_task: tool({
21912
- description: "Spawn a background agent task. Returns task_id for tracking. Use sync=true to wait for completion.",
22564
+ hive_background_task: tool({
22565
+ description: "Spawn a background agent task. Use sync=true to wait for completion (returns output). If sync=false (default), the parent session receives a completion <system-reminder> and you can call hive_background_output to fetch the result.",
21913
22566
  args: {
21914
22567
  agent: tool.schema.string().describe('Agent to use (e.g., "forager-worker", "scout-researcher")'),
21915
- prompt: tool.schema.string().describe("Task instructions/prompt"),
22568
+ prompt: tool.schema.string().optional().describe("Task instructions/prompt (required if promptFile not provided)"),
22569
+ promptFile: tool.schema.string().optional().describe("Path to file containing prompt (alternative to inline prompt)"),
21916
22570
  description: tool.schema.string().describe("Human-readable task description"),
21917
22571
  sync: tool.schema.boolean().optional().describe("Wait for completion (default: false)"),
21918
22572
  idempotencyKey: tool.schema.string().optional().describe("Key for safe retries"),
@@ -21924,6 +22578,7 @@ function createBackgroundTools(manager, client) {
21924
22578
  async execute({
21925
22579
  agent,
21926
22580
  prompt,
22581
+ promptFile,
21927
22582
  description,
21928
22583
  sync = false,
21929
22584
  idempotencyKey,
@@ -21933,9 +22588,41 @@ function createBackgroundTools(manager, client) {
21933
22588
  attempt
21934
22589
  }, toolContext) {
21935
22590
  const ctx = toolContext;
22591
+ let resolvedPrompt = prompt;
22592
+ if (promptFile) {
22593
+ const baseDir = workdir || process.cwd();
22594
+ const workspaceRoot = findWorkspaceRoot(baseDir) ?? baseDir;
22595
+ const fileResult = await resolvePromptFromFile(promptFile, workspaceRoot);
22596
+ if (fileResult.error) {
22597
+ const output = {
22598
+ provider: "hive",
22599
+ task_id: "",
22600
+ session_id: "",
22601
+ status: "error",
22602
+ error: `Failed to read prompt file: ${fileResult.error}`
22603
+ };
22604
+ return JSON.stringify(output, null, 2);
22605
+ }
22606
+ resolvedPrompt = fileResult.content;
22607
+ }
22608
+ if (!resolvedPrompt) {
22609
+ const output = {
22610
+ provider: "hive",
22611
+ task_id: "",
22612
+ session_id: "",
22613
+ status: "error",
22614
+ error: "Either prompt or promptFile is required"
22615
+ };
22616
+ return JSON.stringify(output, null, 2);
22617
+ }
22618
+ let variant;
22619
+ if (configService && isHiveAgent(agent)) {
22620
+ const agentConfig = configService.getAgentConfig(agent);
22621
+ variant = normalizeVariant(agentConfig.variant);
22622
+ }
21936
22623
  const result = await manager.spawn({
21937
22624
  agent,
21938
- prompt,
22625
+ prompt: resolvedPrompt,
21939
22626
  description,
21940
22627
  idempotencyKey,
21941
22628
  workdir,
@@ -21946,7 +22633,8 @@ function createBackgroundTools(manager, client) {
21946
22633
  hiveFeature: feature,
21947
22634
  hiveTaskFolder: hiveTask,
21948
22635
  sync,
21949
- attempt
22636
+ attempt,
22637
+ variant
21950
22638
  });
21951
22639
  if (result.error) {
21952
22640
  const output = {
@@ -22011,19 +22699,19 @@ function createBackgroundTools(manager, client) {
22011
22699
  done: false
22012
22700
  }, null, 2);
22013
22701
  }
22014
- await new Promise((resolve) => setTimeout(resolve, pollInterval));
22702
+ await new Promise((resolve2) => setTimeout(resolve2, pollInterval));
22015
22703
  }
22016
22704
  }
22017
22705
  }),
22018
- background_output: tool({
22019
- description: "Get output from background task. Use block=true to wait for new output.",
22706
+ hive_background_output: tool({
22707
+ description: "Get output from a background task. For sync=false tasks, wait for the completion <system-reminder> and then call with block=false to fetch the result; use block=true only when you need interim output. When blocking, pick a timeout based on task complexity (typically 30-120s).",
22020
22708
  args: {
22021
22709
  task_id: tool.schema.string().describe("Task ID to get output from"),
22022
22710
  block: tool.schema.boolean().optional().describe("Block waiting for new output (default: false)"),
22023
- timeout: tool.schema.number().optional().describe("Timeout in ms when blocking (default: 30000)"),
22711
+ timeout: tool.schema.number().optional().describe("Timeout in ms when blocking (default: 60000)"),
22024
22712
  cursor: tool.schema.string().optional().describe("Cursor for incremental output (message count)")
22025
22713
  },
22026
- async execute({ task_id, block = false, timeout = 30000, cursor }) {
22714
+ async execute({ task_id, block = false, timeout = 60000, cursor }) {
22027
22715
  const task = manager.getTask(task_id);
22028
22716
  if (!task) {
22029
22717
  return JSON.stringify({
@@ -22048,7 +22736,7 @@ function createBackgroundTools(manager, client) {
22048
22736
  if (afterFinalize && isTerminalStatus(afterFinalize.status)) {
22049
22737
  break;
22050
22738
  }
22051
- await new Promise((resolve) => setTimeout(resolve, pollInterval));
22739
+ await new Promise((resolve2) => setTimeout(resolve2, pollInterval));
22052
22740
  }
22053
22741
  }
22054
22742
  const current = manager.getTask(task_id);
@@ -22070,6 +22758,21 @@ function createBackgroundTools(manager, client) {
22070
22758
  }
22071
22759
  const output = await getTaskOutput(client, finalized.sessionId, cursorCount);
22072
22760
  const messageCount = finalized.progress?.messageCount ?? 0;
22761
+ const observationSnapshot = manager.getTaskObservation(task_id);
22762
+ const lastActivityAt = observationSnapshot?.lastActivityAt ?? null;
22763
+ const startedAt = finalized.startedAt ? new Date(finalized.startedAt).getTime() : Date.now();
22764
+ const elapsedMs = Date.now() - startedAt;
22765
+ const lastMessage = finalized.progress?.lastMessage;
22766
+ const lastMessagePreview = lastMessage ? `${lastMessage.slice(0, 200)}${lastMessage.length > 200 ? "..." : ""}` : null;
22767
+ const observation = {
22768
+ elapsedMs,
22769
+ elapsedFormatted: formatElapsed(elapsedMs),
22770
+ messageCount: observationSnapshot?.messageCount ?? 0,
22771
+ lastActivityAgo: lastActivityAt ? formatRelativeTime(lastActivityAt) : "never",
22772
+ lastActivityAt,
22773
+ lastMessagePreview,
22774
+ maybeStuck: observationSnapshot?.maybeStuck ?? false
22775
+ };
22073
22776
  return JSON.stringify({
22074
22777
  task_id: finalized.taskId,
22075
22778
  session_id: finalized.sessionId,
@@ -22077,11 +22780,12 @@ function createBackgroundTools(manager, client) {
22077
22780
  done: isTerminalStatus(finalized.status),
22078
22781
  output,
22079
22782
  cursor: messageCount.toString(),
22080
- progress: finalized.progress
22783
+ progress: finalized.progress,
22784
+ observation
22081
22785
  }, null, 2);
22082
22786
  }
22083
22787
  }),
22084
- background_cancel: tool({
22788
+ hive_background_cancel: tool({
22085
22789
  description: "Cancel running background task(s). Use all=true to cancel all tasks for current session.",
22086
22790
  args: {
22087
22791
  task_id: tool.schema.string().optional().describe("Specific task ID to cancel"),
@@ -22168,8 +22872,7 @@ async function getTaskOutput(client, sessionId, afterCount = 0) {
22168
22872
  }
22169
22873
 
22170
22874
  // src/index.ts
22171
- function formatSkillsXml() {
22172
- const skills = getBuiltinSkills();
22875
+ function formatSkillsXml(skills) {
22173
22876
  if (skills.length === 0)
22174
22877
  return "";
22175
22878
  const skillsXml = skills.map((skill) => {
@@ -22188,21 +22891,27 @@ function formatSkillsXml() {
22188
22891
  ${skillsXml}
22189
22892
  </available_skills>`;
22190
22893
  }
22191
- function createHiveSkillTool() {
22192
- const base = "Load a Hive skill to get detailed instructions for a specific workflow.";
22193
- const skills = getBuiltinSkills();
22194
- const description = skills.length === 0 ? base + `
22894
+ function createHiveSkillTool(filteredSkills) {
22895
+ const base = `Load a Hive skill to get detailed instructions for a specific workflow.
22195
22896
 
22196
- No Hive skills available.` : base + formatSkillsXml();
22897
+ Use this when a task matches an available skill's description. The descriptions below ("Use when...", "Use before...") are triggers; when one applies, you MUST load that skill before proceeding.`;
22898
+ const description = filteredSkills.length === 0 ? base + `
22899
+
22900
+ No Hive skills available.` : base + formatSkillsXml(filteredSkills);
22901
+ const availableNames = new Set(filteredSkills.map((s) => s.name));
22197
22902
  return tool({
22198
22903
  description,
22199
22904
  args: {
22200
22905
  name: tool.schema.string().describe("The skill name from available_skills")
22201
22906
  },
22202
22907
  async execute({ name }) {
22908
+ if (!availableNames.has(name)) {
22909
+ const available = filteredSkills.map((s) => s.name).join(", ");
22910
+ throw new Error(`Skill "${name}" not available. Available Hive skills: ${available || "none"}`);
22911
+ }
22203
22912
  const result = loadBuiltinSkill(name);
22204
22913
  if (!result.found || !result.skill) {
22205
- const available = skills.map((s) => s.name).join(", ");
22914
+ const available = filteredSkills.map((s) => s.name).join(", ");
22206
22915
  throw new Error(`Skill "${name}" not found. Available Hive skills: ${available || "none"}`);
22207
22916
  }
22208
22917
  const skill = result.skill;
@@ -22266,12 +22975,19 @@ Use \`hive_merge\` to explicitly integrate changes. Worktrees persist until manu
22266
22975
  **CRITICAL**: When resuming, a NEW worker spawns in the SAME worktree.
22267
22976
  The previous worker's progress is preserved. Include the user's decision in the \`decision\` parameter.
22268
22977
 
22269
- **For research**, use MCP tools or OpenCode Task:
22978
+ **Observation Polling (Recommended):**
22979
+ - Prefer completion notifications over polling
22980
+ - Use \`hive_worker_status()\` for observation-based spot checks
22981
+ - Avoid tight loops with \`hive_background_output\`; if needed, wait 30-60s between checks
22982
+ - If you suspect notifications did not deliver, do a single \`hive_worker_status()\` check first
22983
+ - If you need final results, call \`hive_background_output({ task_id, block: false })\` after the completion notice
22984
+
22985
+ **For research**, use MCP tools or parallel exploration:
22270
22986
  - \`grep_app_searchGitHub\` - Find code in OSS
22271
22987
  - \`context7_query-docs\` - Library documentation
22272
22988
  - \`websearch_web_search_exa\` - Web search via Exa
22273
22989
  - \`ast_grep_search\` - AST-based search
22274
- - \`task({ subagent_type: "scout", prompt: "..." })\` - Comprehensive research
22990
+ - For exploratory fan-out, load \`hive_skill("parallel-exploration")\` and use \`hive_background_task(agent: "scout-researcher", sync: false, ...)\`
22275
22991
 
22276
22992
  ### Planning Phase - Context Management REQUIRED
22277
22993
 
@@ -22300,16 +23016,22 @@ var plugin = async (ctx) => {
22300
23016
  const taskService = new TaskService(directory);
22301
23017
  const contextService = new ContextService(directory);
22302
23018
  const configService = new ConfigService;
22303
- const builtinMcps = createBuiltinMcps();
23019
+ const disabledMcps = configService.getDisabledMcps();
23020
+ const disabledSkills = configService.getDisabledSkills();
23021
+ const builtinMcps = createBuiltinMcps(disabledMcps);
23022
+ const filteredSkills = getFilteredSkills(disabledSkills);
23023
+ const effectiveAutoLoadSkills = configService.getAgentConfig("hive-master").autoLoadSkills ?? [];
22304
23024
  const worktreeService = new WorktreeService({
22305
23025
  baseDir: directory,
22306
- hiveDir: path5.join(directory, ".hive")
23026
+ hiveDir: path7.join(directory, ".hive")
22307
23027
  });
22308
23028
  const backgroundManager = createBackgroundManager({
22309
23029
  client,
22310
23030
  projectRoot: directory
22311
23031
  });
22312
- const backgroundTools = createBackgroundTools(backgroundManager, client);
23032
+ const delegateMode = configService.getDelegateMode();
23033
+ const useHiveBackground = delegateMode === "hive";
23034
+ const backgroundTools = createBackgroundTools(backgroundManager, client, configService);
22313
23035
  const isOmoSlimEnabled = () => {
22314
23036
  return configService.isOmoSlimEnabled();
22315
23037
  };
@@ -22334,10 +23056,10 @@ var plugin = async (ctx) => {
22334
23056
  }
22335
23057
  };
22336
23058
  const checkBlocked = (feature) => {
22337
- const fs9 = __require("fs");
22338
- const blockedPath = path5.join(directory, ".hive", "features", feature, "BLOCKED");
22339
- if (fs9.existsSync(blockedPath)) {
22340
- const reason = fs9.readFileSync(blockedPath, "utf-8").trim();
23059
+ const fs11 = __require("fs");
23060
+ const blockedPath = path7.join(directory, ".hive", "features", feature, "BLOCKED");
23061
+ if (fs11.existsSync(blockedPath)) {
23062
+ const reason = fs11.readFileSync(blockedPath, "utf-8").trim();
22341
23063
  return `⛔ BLOCKED by Beekeeper
22342
23064
 
22343
23065
  ${reason || "(No reason provided)"}
@@ -22348,8 +23070,24 @@ To unblock: Remove .hive/features/${feature}/BLOCKED`;
22348
23070
  return null;
22349
23071
  };
22350
23072
  return {
22351
- "experimental.chat.system.transform": async (_input, output) => {
23073
+ "experimental.chat.system.transform": async (input, output) => {
22352
23074
  output.system.push(HIVE_SYSTEM_PROMPT);
23075
+ const agentInput = input;
23076
+ const agentName = agentInput?.agent;
23077
+ if (agentName && isHiveAgent(agentName)) {
23078
+ const agentConfig = configService.getAgentConfig(agentName);
23079
+ const autoLoadSkills = agentConfig.autoLoadSkills ?? [];
23080
+ if (autoLoadSkills.length > 0) {
23081
+ for (const skillId of autoLoadSkills) {
23082
+ const skill = BUILTIN_SKILLS.find((entry) => entry.name === skillId);
23083
+ if (!skill) {
23084
+ console.warn("Unknown skill id", skillId);
23085
+ continue;
23086
+ }
23087
+ output.system.push(skill.template);
23088
+ }
23089
+ }
23090
+ }
22353
23091
  const activeFeature = resolveFeature();
22354
23092
  if (activeFeature) {
22355
23093
  const info = featureService.getInfo(activeFeature);
@@ -22369,12 +23107,28 @@ To unblock: Remove .hive/features/${feature}/BLOCKED`;
22369
23107
  }
22370
23108
  }
22371
23109
  },
23110
+ "chat.message": async (input, output) => {
23111
+ const { agent } = input;
23112
+ if (!agent)
23113
+ return;
23114
+ if (!isHiveAgent(agent))
23115
+ return;
23116
+ if (output.message.variant !== undefined)
23117
+ return;
23118
+ const agentConfig = configService.getAgentConfig(agent);
23119
+ const configuredVariant = normalizeVariant(agentConfig.variant);
23120
+ if (configuredVariant !== undefined) {
23121
+ output.message.variant = configuredVariant;
23122
+ }
23123
+ },
22372
23124
  mcp: builtinMcps,
22373
23125
  tool: {
22374
- hive_skill: createHiveSkillTool(),
22375
- background_task: backgroundTools.background_task,
22376
- background_output: backgroundTools.background_output,
22377
- background_cancel: backgroundTools.background_cancel,
23126
+ hive_skill: createHiveSkillTool(filteredSkills),
23127
+ ...useHiveBackground && {
23128
+ hive_background_task: backgroundTools.hive_background_task,
23129
+ hive_background_output: backgroundTools.hive_background_output,
23130
+ hive_background_cancel: backgroundTools.hive_background_cancel
23131
+ },
22378
23132
  hive_feature_create: tool({
22379
23133
  description: "Create a new feature and set it as active",
22380
23134
  args: {
@@ -22455,8 +23209,8 @@ NEXT: Ask your first clarifying question about this feature.`;
22455
23209
  constraint: tool.schema.string().optional().describe("Never/Always rule derived")
22456
23210
  },
22457
23211
  async execute({ feature, trouble, resolution, constraint }) {
22458
- const journalPath = path5.join(directory, ".hive", "journal.md");
22459
- if (!fs6.existsSync(journalPath)) {
23212
+ const journalPath = path7.join(directory, ".hive", "journal.md");
23213
+ if (!fs9.existsSync(journalPath)) {
22460
23214
  return `Error: journal.md not found. Create a feature first to initialize the journal.`;
22461
23215
  }
22462
23216
  const date5 = new Date().toISOString().split("T")[0];
@@ -22470,7 +23224,7 @@ ${constraint ? `**Constraint**: ${constraint}` : ""}
22470
23224
 
22471
23225
  ---
22472
23226
  `;
22473
- fs6.appendFileSync(journalPath, entry);
23227
+ fs9.appendFileSync(journalPath, entry);
22474
23228
  return `Journal entry added for ${feature}. ${constraint ? `Constraint: "${constraint}"` : ""}`;
22475
23229
  }
22476
23230
  }),
@@ -22625,9 +23379,29 @@ Reminder: start work with hive_exec_start to use its worktree, and ensure any su
22625
23379
  baseCommit: worktree.commit
22626
23380
  });
22627
23381
  const planResult = planService.read(feature);
22628
- const contextCompiled = contextService.compile(feature);
22629
23382
  const allTasks = taskService.list(feature);
22630
- const priorTasks = allTasks.filter((t) => t.status === "done").map((t) => `- ${t.folder}: ${t.summary || "No summary"}`);
23383
+ const rawContextFiles = contextService.list(feature).map((f) => ({
23384
+ name: f.name,
23385
+ content: f.content
23386
+ }));
23387
+ const rawPreviousTasks = allTasks.filter((t) => t.status === "done" && t.summary).map((t) => ({ name: t.folder, summary: t.summary }));
23388
+ const taskBudgetResult = applyTaskBudget(rawPreviousTasks, { ...DEFAULT_BUDGET, feature });
23389
+ const contextBudgetResult = applyContextBudget(rawContextFiles, { ...DEFAULT_BUDGET, feature });
23390
+ const contextFiles = contextBudgetResult.files.map((f) => ({
23391
+ name: f.name,
23392
+ content: f.content
23393
+ }));
23394
+ const previousTasks = taskBudgetResult.tasks.map((t) => ({
23395
+ name: t.name,
23396
+ summary: t.summary
23397
+ }));
23398
+ const truncationEvents = [
23399
+ ...taskBudgetResult.truncationEvents,
23400
+ ...contextBudgetResult.truncationEvents
23401
+ ];
23402
+ const priorTasksFormatted = previousTasks.map((t) => `- ${t.name}: ${t.summary}`).join(`
23403
+ `);
23404
+ const droppedTasksHint = taskBudgetResult.droppedTasksHint;
22631
23405
  let specContent = `# Task: ${task}
22632
23406
 
22633
23407
  `;
@@ -22654,32 +23428,28 @@ ${taskMatch[0].trim()}
22654
23428
  `;
22655
23429
  }
22656
23430
  }
22657
- if (contextCompiled) {
23431
+ if (contextFiles.length > 0) {
23432
+ const contextCompiled = contextFiles.map((f) => `## ${f.name}
23433
+
23434
+ ${f.content}`).join(`
23435
+
23436
+ ---
23437
+
23438
+ `);
22658
23439
  specContent += `## Context
22659
23440
 
22660
23441
  ${contextCompiled}
22661
23442
 
22662
23443
  `;
22663
23444
  }
22664
- if (priorTasks.length > 0) {
23445
+ if (priorTasksFormatted) {
22665
23446
  specContent += `## Completed Tasks
22666
23447
 
22667
- ${priorTasks.join(`
22668
- `)}
23448
+ ${priorTasksFormatted}
22669
23449
 
22670
23450
  `;
22671
23451
  }
22672
23452
  taskService.writeSpec(feature, task, specContent);
22673
- const contextFiles = [];
22674
- const contextDir = path5.join(directory, ".hive", "features", feature, "context");
22675
- if (fs6.existsSync(contextDir)) {
22676
- const files = fs6.readdirSync(contextDir).filter((f) => f.endsWith(".md"));
22677
- for (const file2 of files) {
22678
- const content = fs6.readFileSync(path5.join(contextDir, file2), "utf-8");
22679
- contextFiles.push({ name: file2, content });
22680
- }
22681
- }
22682
- const previousTasks = allTasks.filter((t) => t.status === "done" && t.summary).map((t) => ({ name: t.folder, summary: t.summary }));
22683
23453
  const workerPrompt = buildWorkerPrompt({
22684
23454
  feature,
22685
23455
  task,
@@ -22701,59 +23471,107 @@ ${priorTasks.join(`
22701
23471
  const attempt = (rawStatus?.workerSession?.attempt || 0) + 1;
22702
23472
  const idempotencyKey = `hive-${feature}-${task}-${attempt}`;
22703
23473
  taskService.patchBackgroundFields(feature, task, { idempotencyKey });
22704
- return JSON.stringify({
22705
- worktreePath: worktree.path,
22706
- branch: worktree.branch,
22707
- mode: "delegate",
22708
- agent,
22709
- delegationRequired: true,
22710
- backgroundTaskCall: {
22711
- agent,
22712
- prompt: workerPrompt,
22713
- description: `Hive: ${task}`,
22714
- sync: false,
22715
- workdir: worktree.path,
22716
- idempotencyKey,
22717
- feature,
22718
- task,
22719
- attempt
22720
- },
22721
- instructions: `## Delegation Required
23474
+ const contextContent = contextFiles.map((f) => f.content).join(`
22722
23475
 
22723
- You MUST now call the background_task tool to spawn a Forager (Worker/Coder) worker:
23476
+ `);
23477
+ const previousTasksContent = previousTasks.map((t) => `- **${t.name}**: ${t.summary}`).join(`
23478
+ `);
23479
+ const promptMeta = calculatePromptMeta({
23480
+ plan: planResult?.content || "",
23481
+ context: contextContent,
23482
+ previousTasks: previousTasksContent,
23483
+ spec: specContent,
23484
+ workerPrompt
23485
+ });
23486
+ const hiveDir = path7.join(directory, ".hive");
23487
+ const workerPromptPath = writeWorkerPromptFile(feature, task, workerPrompt, hiveDir);
23488
+ const relativePromptPath = path7.relative(directory, workerPromptPath);
23489
+ const PREVIEW_MAX_LENGTH = 200;
23490
+ const workerPromptPreview = workerPrompt.length > PREVIEW_MAX_LENGTH ? workerPrompt.slice(0, PREVIEW_MAX_LENGTH) + "..." : workerPrompt;
23491
+ const hiveBackgroundInstructions = `## Delegation Required
23492
+
23493
+ Call the hive_background_task tool to spawn a Forager (Worker/Coder) worker.
23494
+
23495
+ \`backgroundTaskCall\` contains the canonical tool arguments.
23496
+
23497
+ - Add \`sync: true\` if you need the result in this session.
23498
+ - Otherwise omit \`sync\`. Wait for the completion notification (no polling required). After the <system-reminder> arrives, call \`hive_background_output({ task_id: "<id>", block: false })\` once to fetch the final result.
23499
+
23500
+ Troubleshooting: if you see "Unknown parameter: workdir", your hive_background_task tool is not Hive's provider. Ensure agent-hive loads after other background_* tool providers, then re-run hive_exec_start.`;
23501
+ const taskToolInstructions = `## Delegation Required
23502
+
23503
+ Use OpenCode's built-in \`task\` tool to spawn a Forager (Worker/Coder) worker.
22724
23504
 
22725
23505
  \`\`\`
22726
- background_task({
22727
- agent: "forager-worker",
22728
- prompt: <the workerPrompt below>,
23506
+ task({
23507
+ subagent_type: "${agent}",
22729
23508
  description: "Hive: ${task}",
22730
- sync: false,
22731
- workdir: "${worktree.path}",
22732
- idempotencyKey: "${idempotencyKey}",
22733
- feature: "${feature}",
22734
- task: "${task}",
22735
- attempt: ${attempt}
23509
+ prompt: <read the file at ${relativePromptPath}>
22736
23510
  })
22737
23511
  \`\`\`
22738
23512
 
22739
- After spawning:
22740
- - Monitor with hive_worker_status
22741
- - Handle blockers when worker exits
22742
- - Merge completed work with hive_merge
22743
-
22744
- DO NOT do the work yourself. Delegate it.
22745
-
22746
- ## Troubleshooting
23513
+ Read the prompt file at \`${relativePromptPath}\` and pass its content to the task tool.
22747
23514
 
22748
- If background_task rejects workdir/idempotencyKey/feature/task/attempt parameters or the worker runs in the wrong directory:
22749
-
22750
- **Symptom**: "Unknown parameter: workdir" or worker operates on main repo instead of worktree
22751
- **Cause**: background_task tool is not Hive's provider (agent-hive plugin not loaded last)
22752
- **Fix**:
22753
- 1. Ensure agent-hive loads AFTER any other plugin that registers background_* tools
22754
- 2. Confirm tool outputs include \`provider: "hive"\`
22755
- 3. Re-run hive_exec_start and then background_task`,
22756
- workerPrompt
23515
+ Note: delegateMode is set to 'task' in agent_hive.json. To use Hive's background tools instead, set delegateMode to 'hive'.`;
23516
+ const delegationInstructions = useHiveBackground ? hiveBackgroundInstructions : taskToolInstructions;
23517
+ const responseBase = {
23518
+ worktreePath: worktree.path,
23519
+ branch: worktree.branch,
23520
+ mode: "delegate",
23521
+ delegateMode,
23522
+ agent,
23523
+ delegationRequired: true,
23524
+ workerPromptPath: relativePromptPath,
23525
+ workerPromptPreview,
23526
+ ...useHiveBackground && {
23527
+ backgroundTaskCall: {
23528
+ promptFile: workerPromptPath,
23529
+ description: `Hive: ${task}`,
23530
+ workdir: worktree.path,
23531
+ idempotencyKey,
23532
+ feature,
23533
+ task,
23534
+ attempt
23535
+ }
23536
+ },
23537
+ ...!useHiveBackground && {
23538
+ taskToolCall: {
23539
+ subagent_type: agent,
23540
+ description: `Hive: ${task}`,
23541
+ promptFile: relativePromptPath
23542
+ }
23543
+ },
23544
+ instructions: delegationInstructions
23545
+ };
23546
+ const jsonPayload = JSON.stringify(responseBase, null, 2);
23547
+ const payloadMeta = calculatePayloadMeta({
23548
+ jsonPayload,
23549
+ promptInlined: false,
23550
+ promptReferencedByFile: true
23551
+ });
23552
+ const sizeWarnings = checkWarnings(promptMeta, payloadMeta);
23553
+ const budgetWarnings = truncationEvents.map((event) => ({
23554
+ type: event.type,
23555
+ severity: "info",
23556
+ message: event.message,
23557
+ affected: event.affected,
23558
+ count: event.count
23559
+ }));
23560
+ const allWarnings = [...sizeWarnings, ...budgetWarnings];
23561
+ return JSON.stringify({
23562
+ ...responseBase,
23563
+ promptMeta,
23564
+ payloadMeta,
23565
+ budgetApplied: {
23566
+ maxTasks: DEFAULT_BUDGET.maxTasks,
23567
+ maxSummaryChars: DEFAULT_BUDGET.maxSummaryChars,
23568
+ maxContextChars: DEFAULT_BUDGET.maxContextChars,
23569
+ maxTotalContextChars: DEFAULT_BUDGET.maxTotalContextChars,
23570
+ tasksIncluded: previousTasks.length,
23571
+ tasksDropped: rawPreviousTasks.length - previousTasks.length,
23572
+ droppedTasksHint
23573
+ },
23574
+ warnings: allWarnings.length > 0 ? allWarnings : undefined
22757
23575
  }, null, 2);
22758
23576
  }
22759
23577
  }),
@@ -22880,6 +23698,7 @@ Use hive_merge to integrate changes. Worktree preserved at ${worktree?.path || "
22880
23698
  const STUCK_THRESHOLD = 10 * 60 * 1000;
22881
23699
  const HEARTBEAT_STALE_THRESHOLD = 5 * 60 * 1000;
22882
23700
  const now = Date.now();
23701
+ const PREVIEW_MAX_LENGTH = 200;
22883
23702
  const tasks = taskService.list(feature);
22884
23703
  const inProgressTasks = tasks.filter((t) => (t.status === "in_progress" || t.status === "blocked") && (!specificTask || t.folder === specificTask));
22885
23704
  if (inProgressTasks.length === 0) {
@@ -22889,9 +23708,13 @@ Use hive_merge to integrate changes. Worktree preserved at ${worktree?.path || "
22889
23708
  const worktree = await worktreeService.get(feature, t.folder);
22890
23709
  const rawStatus = taskService.getRawStatus(feature, t.folder);
22891
23710
  const workerSession = rawStatus?.workerSession;
23711
+ const backgroundRecord = backgroundManager.getTaskByHiveTask(feature, t.folder);
23712
+ const observation = backgroundRecord ? backgroundManager.getTaskObservation(backgroundRecord.taskId) : null;
22892
23713
  let maybeStuck = false;
22893
23714
  let lastActivityAt = null;
22894
- if (workerSession?.lastHeartbeatAt) {
23715
+ if (observation?.lastActivityAt) {
23716
+ lastActivityAt = new Date(observation.lastActivityAt).getTime();
23717
+ } else if (workerSession?.lastHeartbeatAt) {
22895
23718
  lastActivityAt = new Date(workerSession.lastHeartbeatAt).getTime();
22896
23719
  const heartbeatStale = now - lastActivityAt > HEARTBEAT_STALE_THRESHOLD;
22897
23720
  const noRecentMessages = !workerSession.messageCount || workerSession.messageCount === 0;
@@ -22900,10 +23723,23 @@ Use hive_merge to integrate changes. Worktree preserved at ${worktree?.path || "
22900
23723
  lastActivityAt = new Date(rawStatus.startedAt).getTime();
22901
23724
  maybeStuck = now - lastActivityAt > STUCK_THRESHOLD && t.status === "in_progress";
22902
23725
  }
23726
+ if (typeof observation?.maybeStuck === "boolean") {
23727
+ maybeStuck = observation.maybeStuck;
23728
+ }
23729
+ const startedAtIso = backgroundRecord?.startedAt || rawStatus?.startedAt || null;
23730
+ const startedAtMs = startedAtIso ? new Date(startedAtIso).getTime() : null;
23731
+ const elapsedMs = startedAtMs ? Math.max(0, now - startedAtMs) : 0;
23732
+ const lastActivityIso = observation?.lastActivityAt || workerSession?.lastHeartbeatAt || rawStatus?.startedAt || null;
23733
+ const lastActivityAgo = lastActivityIso ? formatRelativeTime(lastActivityIso) : "never";
23734
+ const messageCount = observation?.messageCount ?? backgroundRecord?.progress?.messageCount ?? workerSession?.messageCount ?? 0;
23735
+ const lastMessagePreview = backgroundRecord?.progress?.lastMessage ? backgroundRecord.progress.lastMessage.slice(0, PREVIEW_MAX_LENGTH) : null;
22903
23736
  return {
22904
23737
  task: t.folder,
22905
23738
  name: t.name,
22906
23739
  status: t.status,
23740
+ taskId: backgroundRecord?.taskId || workerSession?.taskId || null,
23741
+ description: backgroundRecord?.description || null,
23742
+ startedAt: startedAtIso,
22907
23743
  workerSession: workerSession || null,
22908
23744
  sessionId: workerSession?.sessionId || null,
22909
23745
  agent: workerSession?.agent || "inline",
@@ -22915,16 +23751,33 @@ Use hive_merge to integrate changes. Worktree preserved at ${worktree?.path || "
22915
23751
  worktreePath: worktree?.path || null,
22916
23752
  branch: worktree?.branch || null,
22917
23753
  maybeStuck,
23754
+ activity: {
23755
+ elapsedMs,
23756
+ elapsedFormatted: formatElapsed(elapsedMs),
23757
+ messageCount,
23758
+ lastActivityAgo,
23759
+ lastMessagePreview,
23760
+ maybeStuck
23761
+ },
22918
23762
  blocker: rawStatus?.blocker || null,
22919
23763
  summary: t.summary || null
22920
23764
  };
22921
23765
  }));
23766
+ const stuckWorkers = workers.filter((worker) => worker.activity?.maybeStuck).length;
23767
+ const hint = workers.some((w) => w.status === "blocked") ? 'Use hive_exec_start(task, continueFrom: "blocked", decision: answer) to resume blocked workers' : workers.some((w) => w.maybeStuck) ? "Some workers may be stuck. Use hive_background_output({ task_id }) to check output, or abort with hive_exec_abort." : "Workers in progress. Wait for the completion notification (no polling required). Use hive_worker_status for spot checks; use hive_background_output only if interim output is explicitly needed.";
23768
+ const guidance = stuckWorkers > 0 ? `
23769
+
23770
+ ⚠️ ${stuckWorkers} worker(s) may be stuck (no activity for 10+ minutes). Consider cancelling or investigating.` : "";
22922
23771
  return JSON.stringify({
22923
23772
  feature,
23773
+ delegateMode,
22924
23774
  omoSlimEnabled: isOmoSlimEnabled(),
22925
- backgroundTaskProvider: "hive",
23775
+ backgroundTaskProvider: useHiveBackground ? "hive" : "task",
22926
23776
  workers,
22927
- hint: workers.some((w) => w.status === "blocked") ? 'Use hive_exec_start(task, continueFrom: "blocked", decision: answer) to resume blocked workers' : workers.some((w) => w.maybeStuck) ? "Some workers may be stuck. Use background_output({ task_id }) to check output, or abort with hive_exec_abort." : "Workers in progress. Use hive_worker_status and background_output for live output."
23777
+ summary: {
23778
+ stuckWorkers
23779
+ },
23780
+ hint: hint + guidance
22928
23781
  }, null, 2);
22929
23782
  }
22930
23783
  }),
@@ -23095,12 +23948,12 @@ Files changed: ${result.filesChanged?.length || 0}`;
23095
23948
  const feature = resolveFeature(explicitFeature);
23096
23949
  if (!feature)
23097
23950
  return "Error: No feature specified.";
23098
- const taskDir = path5.join(directory, ".hive", "features", feature, "tasks", task);
23099
- if (!fs6.existsSync(taskDir)) {
23951
+ const taskDir = path7.join(directory, ".hive", "features", feature, "tasks", task);
23952
+ if (!fs9.existsSync(taskDir)) {
23100
23953
  return `Error: Task '${task}' not found in feature '${feature}'`;
23101
23954
  }
23102
- const reportPath = path5.join(taskDir, "report.md");
23103
- const existingReport = fs6.existsSync(reportPath) ? fs6.readFileSync(reportPath, "utf-8") : `# Task Report
23955
+ const reportPath = path7.join(taskDir, "report.md");
23956
+ const existingReport = fs9.existsSync(reportPath) ? fs9.readFileSync(reportPath, "utf-8") : `# Task Report
23104
23957
  `;
23105
23958
  const attemptCount = (existingReport.match(/## Attempt \d+/g) || []).length + 1;
23106
23959
  const timestamp = new Date().toISOString();
@@ -23114,9 +23967,9 @@ Files changed: ${result.filesChanged?.length || 0}`;
23114
23967
  ${summary}
23115
23968
 
23116
23969
  `;
23117
- fs6.writeFileSync(reportPath, newContent);
23118
- const pendingPath = path5.join(taskDir, "PENDING_REVIEW");
23119
- fs6.writeFileSync(pendingPath, JSON.stringify({
23970
+ fs9.writeFileSync(reportPath, newContent);
23971
+ const pendingPath = path7.join(taskDir, "PENDING_REVIEW");
23972
+ fs9.writeFileSync(pendingPath, JSON.stringify({
23120
23973
  attempt: attemptCount,
23121
23974
  requestedAt: timestamp,
23122
23975
  summary: summary.substring(0, 200) + (summary.length > 200 ? "..." : "")
@@ -23124,18 +23977,18 @@ ${summary}
23124
23977
  const pollInterval = 2000;
23125
23978
  const maxWait = 30 * 60 * 1000;
23126
23979
  const startTime = Date.now();
23127
- while (fs6.existsSync(pendingPath)) {
23980
+ while (fs9.existsSync(pendingPath)) {
23128
23981
  if (Date.now() - startTime > maxWait) {
23129
23982
  return "Review timed out after 30 minutes. Human did not respond.";
23130
23983
  }
23131
- await new Promise((resolve) => setTimeout(resolve, pollInterval));
23984
+ await new Promise((resolve2) => setTimeout(resolve2, pollInterval));
23132
23985
  }
23133
- const resultPath = path5.join(taskDir, "REVIEW_RESULT");
23134
- if (!fs6.existsSync(resultPath)) {
23986
+ const resultPath = path7.join(taskDir, "REVIEW_RESULT");
23987
+ if (!fs9.existsSync(resultPath)) {
23135
23988
  return "Review cancelled (PENDING_REVIEW removed but no REVIEW_RESULT).";
23136
23989
  }
23137
- const result = fs6.readFileSync(resultPath, "utf-8").trim();
23138
- fs6.appendFileSync(reportPath, `### Review Result
23990
+ const result = fs9.readFileSync(resultPath, "utf-8").trim();
23991
+ fs9.appendFileSync(reportPath, `### Review Result
23139
23992
 
23140
23993
  ${result}
23141
23994
 
@@ -23198,7 +24051,10 @@ Make the requested changes, then call hive_request_review again.`;
23198
24051
  question: "allow",
23199
24052
  skill: "allow",
23200
24053
  todowrite: "allow",
23201
- todoread: "allow"
24054
+ todoread: "allow",
24055
+ hive_background_task: "allow",
24056
+ hive_background_output: "allow",
24057
+ hive_background_cancel: "allow"
23202
24058
  }
23203
24059
  };
23204
24060
  const architectUserConfig = configService.getAgentConfig("architect-planner");
@@ -23214,7 +24070,10 @@ Make the requested changes, then call hive_request_review again.`;
23214
24070
  skill: "allow",
23215
24071
  todowrite: "allow",
23216
24072
  todoread: "allow",
23217
- webfetch: "allow"
24073
+ webfetch: "allow",
24074
+ hive_background_task: "allow",
24075
+ hive_background_output: "allow",
24076
+ hive_background_cancel: "allow"
23218
24077
  }
23219
24078
  };
23220
24079
  const swarmUserConfig = configService.getAgentConfig("swarm-orchestrator");
@@ -23227,7 +24086,10 @@ Make the requested changes, then call hive_request_review again.`;
23227
24086
  question: "allow",
23228
24087
  skill: "allow",
23229
24088
  todowrite: "allow",
23230
- todoread: "allow"
24089
+ todoread: "allow",
24090
+ hive_background_task: "allow",
24091
+ hive_background_output: "allow",
24092
+ hive_background_cancel: "allow"
23231
24093
  }
23232
24094
  };
23233
24095
  const scoutUserConfig = configService.getAgentConfig("scout-researcher");
@@ -23266,15 +24128,18 @@ Make the requested changes, then call hive_request_review again.`;
23266
24128
  skill: "allow"
23267
24129
  }
23268
24130
  };
23269
- const allAgents = {
23270
- "hive-master": hiveConfig,
23271
- "architect-planner": architectConfig,
23272
- "swarm-orchestrator": swarmConfig,
23273
- "scout-researcher": scoutConfig,
23274
- "forager-worker": foragerConfig,
23275
- "hygienic-reviewer": hygienicConfig
23276
- };
23277
- configService.registerAgentsInOpenCode(allAgents);
24131
+ const hiveConfigData = configService.get();
24132
+ const agentMode = hiveConfigData.agentMode ?? "unified";
24133
+ const allAgents = {};
24134
+ if (agentMode === "unified") {
24135
+ allAgents["hive-master"] = hiveConfig;
24136
+ } else {
24137
+ allAgents["architect-planner"] = architectConfig;
24138
+ allAgents["swarm-orchestrator"] = swarmConfig;
24139
+ allAgents["scout-researcher"] = scoutConfig;
24140
+ allAgents["forager-worker"] = foragerConfig;
24141
+ allAgents["hygienic-reviewer"] = hygienicConfig;
24142
+ }
23278
24143
  const configAgent = opencodeConfig.agent;
23279
24144
  if (!configAgent) {
23280
24145
  opencodeConfig.agent = allAgents;
@@ -23294,7 +24159,7 @@ Make the requested changes, then call hive_request_review again.`;
23294
24159
  delete configAgent["hygienic-reviewer"];
23295
24160
  Object.assign(configAgent, allAgents);
23296
24161
  }
23297
- opencodeConfig.default_agent = "hive-master";
24162
+ opencodeConfig.default_agent = agentMode === "unified" ? "hive-master" : "architect-planner";
23298
24163
  const configMcp = opencodeConfig.mcp;
23299
24164
  if (!configMcp) {
23300
24165
  opencodeConfig.mcp = builtinMcps;