priiisk 0.1.19 → 0.1.21

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.
@@ -22394,13 +22394,13 @@ var require_headers = __commonJS({
22394
22394
  return headersList.sortedMap;
22395
22395
  }
22396
22396
  const headers = [];
22397
- const names = headersList.toSortedArray();
22397
+ const names2 = headersList.toSortedArray();
22398
22398
  const cookies = headersList.cookies;
22399
22399
  if (cookies === null || cookies.length === 1) {
22400
- return headersList.sortedMap = names;
22400
+ return headersList.sortedMap = names2;
22401
22401
  }
22402
- for (let i = 0; i < names.length; ++i) {
22403
- const { 0: name, 1: value5 } = names[i];
22402
+ for (let i = 0; i < names2.length; ++i) {
22403
+ const { 0: name, 1: value5 } = names2[i];
22404
22404
  if (name === "set-cookie") {
22405
22405
  for (let j = 0; j < cookies.length; ++j) {
22406
22406
  headers.push([name, cookies[j]]);
@@ -29363,10 +29363,10 @@ var require_code = __commonJS({
29363
29363
  }
29364
29364
  get names() {
29365
29365
  var _a3;
29366
- return (_a3 = this._names) !== null && _a3 !== void 0 ? _a3 : this._names = this._items.reduce((names, c) => {
29366
+ return (_a3 = this._names) !== null && _a3 !== void 0 ? _a3 : this._names = this._items.reduce((names2, c) => {
29367
29367
  if (c instanceof Name)
29368
- names[c.str] = (names[c.str] || 0) + 1;
29369
- return names;
29368
+ names2[c.str] = (names2[c.str] || 0) + 1;
29369
+ return names2;
29370
29370
  }, {});
29371
29371
  }
29372
29372
  };
@@ -29692,11 +29692,11 @@ var require_codegen = __commonJS({
29692
29692
  const rhs = this.rhs === void 0 ? "" : ` = ${this.rhs}`;
29693
29693
  return `${varKind} ${this.name}${rhs};` + _n;
29694
29694
  }
29695
- optimizeNames(names, constants3) {
29696
- if (!names[this.name.str])
29695
+ optimizeNames(names2, constants3) {
29696
+ if (!names2[this.name.str])
29697
29697
  return;
29698
29698
  if (this.rhs)
29699
- this.rhs = optimizeExpr(this.rhs, names, constants3);
29699
+ this.rhs = optimizeExpr(this.rhs, names2, constants3);
29700
29700
  return this;
29701
29701
  }
29702
29702
  get names() {
@@ -29713,15 +29713,15 @@ var require_codegen = __commonJS({
29713
29713
  render({ _n }) {
29714
29714
  return `${this.lhs} = ${this.rhs};` + _n;
29715
29715
  }
29716
- optimizeNames(names, constants3) {
29717
- if (this.lhs instanceof code_1.Name && !names[this.lhs.str] && !this.sideEffects)
29716
+ optimizeNames(names2, constants3) {
29717
+ if (this.lhs instanceof code_1.Name && !names2[this.lhs.str] && !this.sideEffects)
29718
29718
  return;
29719
- this.rhs = optimizeExpr(this.rhs, names, constants3);
29719
+ this.rhs = optimizeExpr(this.rhs, names2, constants3);
29720
29720
  return this;
29721
29721
  }
29722
29722
  get names() {
29723
- const names = this.lhs instanceof code_1.Name ? {} : { ...this.lhs.names };
29724
- return addExprNames(names, this.rhs);
29723
+ const names2 = this.lhs instanceof code_1.Name ? {} : { ...this.lhs.names };
29724
+ return addExprNames(names2, this.rhs);
29725
29725
  }
29726
29726
  };
29727
29727
  var AssignOp = class extends Assign {
@@ -29777,8 +29777,8 @@ var require_codegen = __commonJS({
29777
29777
  optimizeNodes() {
29778
29778
  return `${this.code}` ? this : void 0;
29779
29779
  }
29780
- optimizeNames(names, constants3) {
29781
- this.code = optimizeExpr(this.code, names, constants3);
29780
+ optimizeNames(names2, constants3) {
29781
+ this.code = optimizeExpr(this.code, names2, constants3);
29782
29782
  return this;
29783
29783
  }
29784
29784
  get names() {
@@ -29807,20 +29807,20 @@ var require_codegen = __commonJS({
29807
29807
  }
29808
29808
  return nodes.length > 0 ? this : void 0;
29809
29809
  }
29810
- optimizeNames(names, constants3) {
29810
+ optimizeNames(names2, constants3) {
29811
29811
  const { nodes } = this;
29812
29812
  let i = nodes.length;
29813
29813
  while (i--) {
29814
29814
  const n = nodes[i];
29815
- if (n.optimizeNames(names, constants3))
29815
+ if (n.optimizeNames(names2, constants3))
29816
29816
  continue;
29817
- subtractNames(names, n.names);
29817
+ subtractNames(names2, n.names);
29818
29818
  nodes.splice(i, 1);
29819
29819
  }
29820
29820
  return nodes.length > 0 ? this : void 0;
29821
29821
  }
29822
29822
  get names() {
29823
- return this.nodes.reduce((names, n) => addNames(names, n.names), {});
29823
+ return this.nodes.reduce((names2, n) => addNames(names2, n.names), {});
29824
29824
  }
29825
29825
  };
29826
29826
  var BlockNode = class extends ParentNode2 {
@@ -29865,20 +29865,20 @@ var require_codegen = __commonJS({
29865
29865
  return void 0;
29866
29866
  return this;
29867
29867
  }
29868
- optimizeNames(names, constants3) {
29868
+ optimizeNames(names2, constants3) {
29869
29869
  var _a3;
29870
- this.else = (_a3 = this.else) === null || _a3 === void 0 ? void 0 : _a3.optimizeNames(names, constants3);
29871
- if (!(super.optimizeNames(names, constants3) || this.else))
29870
+ this.else = (_a3 = this.else) === null || _a3 === void 0 ? void 0 : _a3.optimizeNames(names2, constants3);
29871
+ if (!(super.optimizeNames(names2, constants3) || this.else))
29872
29872
  return;
29873
- this.condition = optimizeExpr(this.condition, names, constants3);
29873
+ this.condition = optimizeExpr(this.condition, names2, constants3);
29874
29874
  return this;
29875
29875
  }
29876
29876
  get names() {
29877
- const names = super.names;
29878
- addExprNames(names, this.condition);
29877
+ const names2 = super.names;
29878
+ addExprNames(names2, this.condition);
29879
29879
  if (this.else)
29880
- addNames(names, this.else.names);
29881
- return names;
29880
+ addNames(names2, this.else.names);
29881
+ return names2;
29882
29882
  }
29883
29883
  };
29884
29884
  If.kind = "if";
@@ -29893,10 +29893,10 @@ var require_codegen = __commonJS({
29893
29893
  render(opts) {
29894
29894
  return `for(${this.iteration})` + super.render(opts);
29895
29895
  }
29896
- optimizeNames(names, constants3) {
29897
- if (!super.optimizeNames(names, constants3))
29896
+ optimizeNames(names2, constants3) {
29897
+ if (!super.optimizeNames(names2, constants3))
29898
29898
  return;
29899
- this.iteration = optimizeExpr(this.iteration, names, constants3);
29899
+ this.iteration = optimizeExpr(this.iteration, names2, constants3);
29900
29900
  return this;
29901
29901
  }
29902
29902
  get names() {
@@ -29917,8 +29917,8 @@ var require_codegen = __commonJS({
29917
29917
  return `for(${varKind} ${name}=${from}; ${name}<${to}; ${name}++)` + super.render(opts);
29918
29918
  }
29919
29919
  get names() {
29920
- const names = addExprNames(super.names, this.from);
29921
- return addExprNames(names, this.to);
29920
+ const names2 = addExprNames(super.names, this.from);
29921
+ return addExprNames(names2, this.to);
29922
29922
  }
29923
29923
  };
29924
29924
  var ForIter = class extends For {
@@ -29932,10 +29932,10 @@ var require_codegen = __commonJS({
29932
29932
  render(opts) {
29933
29933
  return `for(${this.varKind} ${this.name} ${this.loop} ${this.iterable})` + super.render(opts);
29934
29934
  }
29935
- optimizeNames(names, constants3) {
29936
- if (!super.optimizeNames(names, constants3))
29935
+ optimizeNames(names2, constants3) {
29936
+ if (!super.optimizeNames(names2, constants3))
29937
29937
  return;
29938
- this.iterable = optimizeExpr(this.iterable, names, constants3);
29938
+ this.iterable = optimizeExpr(this.iterable, names2, constants3);
29939
29939
  return this;
29940
29940
  }
29941
29941
  get names() {
@@ -29977,20 +29977,20 @@ var require_codegen = __commonJS({
29977
29977
  (_b = this.finally) === null || _b === void 0 ? void 0 : _b.optimizeNodes();
29978
29978
  return this;
29979
29979
  }
29980
- optimizeNames(names, constants3) {
29980
+ optimizeNames(names2, constants3) {
29981
29981
  var _a3, _b;
29982
- super.optimizeNames(names, constants3);
29983
- (_a3 = this.catch) === null || _a3 === void 0 ? void 0 : _a3.optimizeNames(names, constants3);
29984
- (_b = this.finally) === null || _b === void 0 ? void 0 : _b.optimizeNames(names, constants3);
29982
+ super.optimizeNames(names2, constants3);
29983
+ (_a3 = this.catch) === null || _a3 === void 0 ? void 0 : _a3.optimizeNames(names2, constants3);
29984
+ (_b = this.finally) === null || _b === void 0 ? void 0 : _b.optimizeNames(names2, constants3);
29985
29985
  return this;
29986
29986
  }
29987
29987
  get names() {
29988
- const names = super.names;
29988
+ const names2 = super.names;
29989
29989
  if (this.catch)
29990
- addNames(names, this.catch.names);
29990
+ addNames(names2, this.catch.names);
29991
29991
  if (this.finally)
29992
- addNames(names, this.finally.names);
29993
- return names;
29992
+ addNames(names2, this.finally.names);
29993
+ return names2;
29994
29994
  }
29995
29995
  };
29996
29996
  var Catch = class extends BlockNode {
@@ -30274,15 +30274,15 @@ var require_codegen = __commonJS({
30274
30274
  }
30275
30275
  };
30276
30276
  exports.CodeGen = CodeGen;
30277
- function addNames(names, from) {
30277
+ function addNames(names2, from) {
30278
30278
  for (const n in from)
30279
- names[n] = (names[n] || 0) + (from[n] || 0);
30280
- return names;
30279
+ names2[n] = (names2[n] || 0) + (from[n] || 0);
30280
+ return names2;
30281
30281
  }
30282
- function addExprNames(names, from) {
30283
- return from instanceof code_1._CodeOrName ? addNames(names, from.names) : names;
30282
+ function addExprNames(names2, from) {
30283
+ return from instanceof code_1._CodeOrName ? addNames(names2, from.names) : names2;
30284
30284
  }
30285
- function optimizeExpr(expr, names, constants3) {
30285
+ function optimizeExpr(expr, names2, constants3) {
30286
30286
  if (expr instanceof code_1.Name)
30287
30287
  return replaceName(expr);
30288
30288
  if (!canOptimize(expr))
@@ -30298,18 +30298,18 @@ var require_codegen = __commonJS({
30298
30298
  }, []));
30299
30299
  function replaceName(n) {
30300
30300
  const c = constants3[n.str];
30301
- if (c === void 0 || names[n.str] !== 1)
30301
+ if (c === void 0 || names2[n.str] !== 1)
30302
30302
  return n;
30303
- delete names[n.str];
30303
+ delete names2[n.str];
30304
30304
  return c;
30305
30305
  }
30306
30306
  function canOptimize(e) {
30307
- return e instanceof code_1._Code && e._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 && constants3[c.str] !== void 0);
30307
+ return e instanceof code_1._Code && e._items.some((c) => c instanceof code_1.Name && names2[c.str] === 1 && constants3[c.str] !== void 0);
30308
30308
  }
30309
30309
  }
30310
- function subtractNames(names, from) {
30310
+ function subtractNames(names2, from) {
30311
30311
  for (const n in from)
30312
- names[n] = (names[n] || 0) - (from[n] || 0);
30312
+ names2[n] = (names2[n] || 0) - (from[n] || 0);
30313
30313
  }
30314
30314
  function not3(x) {
30315
30315
  return typeof x == "boolean" || typeof x == "number" || x === null ? !x : (0, code_1._)`!${par2(x)}`;
@@ -30507,7 +30507,7 @@ var require_names = __commonJS({
30507
30507
  "use strict";
30508
30508
  Object.defineProperty(exports, "__esModule", { value: true });
30509
30509
  var codegen_1 = require_codegen();
30510
- var names = {
30510
+ var names2 = {
30511
30511
  // validation function arguments
30512
30512
  data: new codegen_1.Name("data"),
30513
30513
  // data passed to validation function
@@ -30536,7 +30536,7 @@ var require_names = __commonJS({
30536
30536
  jsonLen: new codegen_1.Name("jsonLen"),
30537
30537
  jsonPart: new codegen_1.Name("jsonPart")
30538
30538
  };
30539
- exports.default = names;
30539
+ exports.default = names2;
30540
30540
  }
30541
30541
  });
30542
30542
 
@@ -36336,7 +36336,7 @@ var require_which = __commonJS({
36336
36336
  opt = {};
36337
36337
  const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt);
36338
36338
  const found = [];
36339
- const step4 = (i) => new Promise((resolve8, reject) => {
36339
+ const step5 = (i) => new Promise((resolve8, reject) => {
36340
36340
  if (i === pathEnv.length)
36341
36341
  return opt.all && found.length ? resolve8(found) : reject(getNotFoundError(cmd));
36342
36342
  const ppRaw = pathEnv[i];
@@ -36347,7 +36347,7 @@ var require_which = __commonJS({
36347
36347
  });
36348
36348
  const subStep = (p, i, ii) => new Promise((resolve8, reject) => {
36349
36349
  if (ii === pathExt.length)
36350
- return resolve8(step4(i + 1));
36350
+ return resolve8(step5(i + 1));
36351
36351
  const ext = pathExt[ii];
36352
36352
  isexe(p + ext, { pathExt: pathExtExe }, (er, is3) => {
36353
36353
  if (!er && is3) {
@@ -36359,7 +36359,7 @@ var require_which = __commonJS({
36359
36359
  return resolve8(subStep(p, i, ii + 1));
36360
36360
  });
36361
36361
  });
36362
- return cb ? step4(0).then((res) => cb(null, res), cb) : step4(0);
36362
+ return cb ? step5(0).then((res) => cb(null, res), cb) : step5(0);
36363
36363
  };
36364
36364
  var whichSync = (cmd, opt) => {
36365
36365
  opt = opt || {};
@@ -51748,9 +51748,9 @@ var ScheduleImpl = class {
51748
51748
  initial;
51749
51749
  step;
51750
51750
  [ScheduleTypeId] = scheduleVariance;
51751
- constructor(initial, step4) {
51751
+ constructor(initial, step5) {
51752
51752
  this.initial = initial;
51753
- this.step = step4;
51753
+ this.step = step5;
51754
51754
  }
51755
51755
  pipe() {
51756
51756
  return pipeArguments(this, arguments);
@@ -51815,7 +51815,7 @@ var ScheduleDriverImpl = class {
51815
51815
  }))))));
51816
51816
  }
51817
51817
  };
51818
- var makeWithState = (initial, step4) => new ScheduleImpl(initial, step4);
51818
+ var makeWithState = (initial, step5) => new ScheduleImpl(initial, step5);
51819
51819
  var addDelay = /* @__PURE__ */ dual(2, (self, f) => addDelayEffect(self, (out) => sync(() => f(out))));
51820
51820
  var addDelayEffect = /* @__PURE__ */ dual(2, (self, f) => modifyDelayEffect(self, (out, duration5) => map11(f(out), (delay3) => sum(duration5, decode(delay3)))));
51821
51821
  var asVoid2 = (self) => map16(self, constVoid);
@@ -52011,8 +52011,8 @@ var withExecutionPlan = /* @__PURE__ */ dual(2, (effect3, plan) => suspend(() =>
52011
52011
  return flatMap7(whileLoop({
52012
52012
  while: () => i < plan.steps.length && (result === void 0 || isLeft2(result)),
52013
52013
  body: () => {
52014
- const step4 = plan.steps[i];
52015
- let nextEffect = effect_provide(effect3, step4.provide);
52014
+ const step5 = plan.steps[i];
52015
+ let nextEffect = effect_provide(effect3, step5.provide);
52016
52016
  if (result) {
52017
52017
  let attempted = false;
52018
52018
  const wrapped = nextEffect;
@@ -52021,9 +52021,9 @@ var withExecutionPlan = /* @__PURE__ */ dual(2, (effect3, plan) => suspend(() =>
52021
52021
  attempted = true;
52022
52022
  return result;
52023
52023
  });
52024
- nextEffect = scheduleDefectRefail(retry_Effect(nextEffect, scheduleFromStep(step4, false)));
52024
+ nextEffect = scheduleDefectRefail(retry_Effect(nextEffect, scheduleFromStep(step5, false)));
52025
52025
  } else {
52026
- const schedule3 = scheduleFromStep(step4, true);
52026
+ const schedule3 = scheduleFromStep(step5, true);
52027
52027
  nextEffect = schedule3 ? scheduleDefectRefail(retry_Effect(nextEffect, schedule3)) : nextEffect;
52028
52028
  }
52029
52029
  return either2(nextEffect);
@@ -52034,20 +52034,20 @@ var withExecutionPlan = /* @__PURE__ */ dual(2, (effect3, plan) => suspend(() =>
52034
52034
  }
52035
52035
  }), () => result);
52036
52036
  }));
52037
- var scheduleFromStep = (step4, first2) => {
52037
+ var scheduleFromStep = (step5, first2) => {
52038
52038
  if (!first2) {
52039
52039
  return fromRetryOptions({
52040
- schedule: step4.schedule ? step4.schedule : step4.attempts ? void 0 : once2,
52041
- times: step4.attempts,
52042
- while: step4.while
52040
+ schedule: step5.schedule ? step5.schedule : step5.attempts ? void 0 : once2,
52041
+ times: step5.attempts,
52042
+ while: step5.while
52043
52043
  });
52044
- } else if (step4.attempts === 1 || !(step4.schedule || step4.attempts)) {
52044
+ } else if (step5.attempts === 1 || !(step5.schedule || step5.attempts)) {
52045
52045
  return void 0;
52046
52046
  }
52047
52047
  return fromRetryOptions({
52048
- schedule: step4.schedule,
52049
- while: step4.while,
52050
- times: step4.attempts ? step4.attempts - 1 : void 0
52048
+ schedule: step5.schedule,
52049
+ while: step5.while,
52050
+ times: step5.attempts ? step5.attempts - 1 : void 0
52051
52051
  });
52052
52052
  };
52053
52053
 
@@ -62888,15 +62888,15 @@ var pick2 = (ast, keys6) => {
62888
62888
  switch (ast._tag) {
62889
62889
  case "TypeLiteral": {
62890
62890
  const pss = [];
62891
- const names = {};
62891
+ const names2 = {};
62892
62892
  for (const ps of ast.propertySignatures) {
62893
- names[ps.name] = null;
62893
+ names2[ps.name] = null;
62894
62894
  if (keys6.includes(ps.name)) {
62895
62895
  pss.push(ps);
62896
62896
  }
62897
62897
  }
62898
62898
  for (const key of keys6) {
62899
- if (!(key in names)) {
62899
+ if (!(key in names2)) {
62900
62900
  const ps = getTypeLiteralPropertySignature(ast, key);
62901
62901
  if (ps) {
62902
62902
  pss.push(ps);
@@ -74510,28 +74510,28 @@ function readStringJS(length4) {
74510
74510
  if (length4 > 64 && decoder2)
74511
74511
  return decoder2.decode(src.subarray(position, position += length4));
74512
74512
  const end6 = position + length4;
74513
- const units = [];
74513
+ const units3 = [];
74514
74514
  result = "";
74515
74515
  while (position < end6) {
74516
74516
  const byte1 = src[position++];
74517
74517
  if ((byte1 & 128) === 0) {
74518
- units.push(byte1);
74518
+ units3.push(byte1);
74519
74519
  } else if ((byte1 & 224) === 192) {
74520
74520
  const byte2 = src[position++] & 63;
74521
74521
  const codePoint = (byte1 & 31) << 6 | byte2;
74522
74522
  if (codePoint < 128) {
74523
- units.push(65533);
74523
+ units3.push(65533);
74524
74524
  } else {
74525
- units.push(codePoint);
74525
+ units3.push(codePoint);
74526
74526
  }
74527
74527
  } else if ((byte1 & 240) === 224) {
74528
74528
  const byte2 = src[position++] & 63;
74529
74529
  const byte3 = src[position++] & 63;
74530
74530
  const codePoint = (byte1 & 31) << 12 | byte2 << 6 | byte3;
74531
74531
  if (codePoint < 2048 || codePoint >= 55296 && codePoint <= 57343) {
74532
- units.push(65533);
74532
+ units3.push(65533);
74533
74533
  } else {
74534
- units.push(codePoint);
74534
+ units3.push(codePoint);
74535
74535
  }
74536
74536
  } else if ((byte1 & 248) === 240) {
74537
74537
  const byte2 = src[position++] & 63;
@@ -74539,25 +74539,25 @@ function readStringJS(length4) {
74539
74539
  const byte4 = src[position++] & 63;
74540
74540
  let unit = (byte1 & 7) << 18 | byte2 << 12 | byte3 << 6 | byte4;
74541
74541
  if (unit < 65536 || unit > 1114111) {
74542
- units.push(65533);
74542
+ units3.push(65533);
74543
74543
  } else if (unit > 65535) {
74544
74544
  unit -= 65536;
74545
- units.push(unit >>> 10 & 1023 | 55296);
74545
+ units3.push(unit >>> 10 & 1023 | 55296);
74546
74546
  unit = 56320 | unit & 1023;
74547
- units.push(unit);
74547
+ units3.push(unit);
74548
74548
  } else {
74549
- units.push(unit);
74549
+ units3.push(unit);
74550
74550
  }
74551
74551
  } else {
74552
- units.push(65533);
74552
+ units3.push(65533);
74553
74553
  }
74554
- if (units.length >= 4096) {
74555
- result += fromCharCode.apply(String, units);
74556
- units.length = 0;
74554
+ if (units3.length >= 4096) {
74555
+ result += fromCharCode.apply(String, units3);
74556
+ units3.length = 0;
74557
74557
  }
74558
74558
  }
74559
- if (units.length > 0) {
74560
- result += fromCharCode.apply(String, units);
74559
+ if (units3.length > 0) {
74560
+ result += fromCharCode.apply(String, units3);
74561
74561
  }
74562
74562
  return result;
74563
74563
  }
@@ -79446,7 +79446,7 @@ var make77 = /* @__PURE__ */ fnUntraced2(function* (shouldQuit = defaultShouldQu
79446
79446
  }))
79447
79447
  });
79448
79448
  const columns = sync4(() => stdout3.columns ?? 0);
79449
- const rows2 = sync4(() => stdout3.rows ?? 0);
79449
+ const rows = sync4(() => stdout3.rows ?? 0);
79450
79450
  const isTTY = sync4(() => Boolean(stdout3.isTTY));
79451
79451
  const readInput = gen2(function* () {
79452
79452
  yield* get15(rlRef);
@@ -79485,7 +79485,7 @@ var make77 = /* @__PURE__ */ fnUntraced2(function* (shouldQuit = defaultShouldQu
79485
79485
  }));
79486
79486
  return Terminal.of({
79487
79487
  columns,
79488
- rows: rows2,
79488
+ rows,
79489
79489
  isTTY,
79490
79490
  readInput,
79491
79491
  readLine,
@@ -79812,7 +79812,7 @@ var layerDotEnvAdd2 = layerDotEnvAdd;
79812
79812
  var layerDotEnv2 = layerDotEnv;
79813
79813
 
79814
79814
  // packages/config/src/loaders/mcpCredentials.ts
79815
- var loadReferencedMcpCredentials = (fs, names) => gen2(function* () {
79815
+ var loadReferencedMcpCredentials = (fs, names2) => gen2(function* () {
79816
79816
  const credentialsPath = yield* resolveCredentialsPath;
79817
79817
  const exists4 = yield* fs.exists(credentialsPath).pipe(
79818
79818
  mapError2(
@@ -79822,7 +79822,7 @@ var loadReferencedMcpCredentials = (fs, names) => gen2(function* () {
79822
79822
  })
79823
79823
  )
79824
79824
  );
79825
- if (!exists4 || names.length === 0) return {};
79825
+ if (!exists4 || names2.length === 0) return {};
79826
79826
  const provider = yield* PlatformConfigProvider_exports.fromDotEnv(credentialsPath).pipe(
79827
79827
  provideService2(FileSystem_exports.FileSystem, fs),
79828
79828
  mapError2(
@@ -79833,7 +79833,7 @@ var loadReferencedMcpCredentials = (fs, names) => gen2(function* () {
79833
79833
  )
79834
79834
  );
79835
79835
  return yield* forEach9(
79836
- names,
79836
+ names2,
79837
79837
  (name) => gen2(function* () {
79838
79838
  const value5 = yield* string3(name).pipe(
79839
79839
  option4,
@@ -81153,6 +81153,32 @@ var resolveDirectTools = (config3, role, override) => {
81153
81153
  return { tools, unknownBins };
81154
81154
  };
81155
81155
 
81156
+ // packages/config/src/resolvers/equipmentDescription.ts
81157
+ var names = (values4) => values4.length === 0 ? "none" : values4.join(", ");
81158
+ var mcpGrants = (equipment) => names(
81159
+ equipment.mcp.serverNames.map((serverName) => {
81160
+ const toolNames = equipment.mcp.toolNamesByServer?.[serverName];
81161
+ return toolNames === void 0 ? serverName : `${serverName} (${names(toolNames)})`;
81162
+ })
81163
+ );
81164
+ var equipmentDescriptionLines = (equipment, revision) => [
81165
+ `equipment r${String(revision)}: ${equipment.role ?? equipment.preset ?? "worker"}, ${equipment.readOnly ? "read-only" : "read/write"}`,
81166
+ `model: ${equipment.model ?? "default"}${equipment.thinkingLevel === void 0 ? "" : `, thinking ${equipment.thinkingLevel}`}`,
81167
+ `tools: ${names(
81168
+ [
81169
+ .../* @__PURE__ */ new Set([
81170
+ ...equipment.builtinTools,
81171
+ ...equipment.customToolNames.filter((name) => directToolBin(name) === void 0)
81172
+ ])
81173
+ ].sort()
81174
+ )}`,
81175
+ `direct: ${names(
81176
+ equipment.customToolNames.map((name) => directToolBin(name)).filter((bin) => bin !== void 0).sort()
81177
+ )}`,
81178
+ `mcp: ${mcpGrants(equipment)}`,
81179
+ `skills: ${names(equipment.skillNames)}`
81180
+ ];
81181
+
81156
81182
  // packages/config/src/resolvers/mcpConfigResolver.ts
81157
81183
  var dedupe4 = (items) => [...new Set(items)];
81158
81184
  var resolveServerNames = (config3, role, mcpOverride) => dedupe4(mcpOverride ?? (role !== void 0 ? config3?.roles?.[role]?.mcp ?? [] : []));
@@ -81177,11 +81203,11 @@ var collectEntryEnvRefs = (entry) => {
81177
81203
  const fromBearerTokenEnv = entry.bearerTokenEnv !== void 0 ? [entry.bearerTokenEnv] : [];
81178
81204
  return [...fromPatterns, ...fromBearerTokenEnv];
81179
81205
  };
81180
- var resolveNamedServers = (config3, names) => {
81206
+ var resolveNamedServers = (config3, names2) => {
81181
81207
  const catalog = config3?.mcpServers ?? {};
81182
81208
  const unknownServers = [];
81183
81209
  const servers = {};
81184
- for (const name of dedupe4(names)) {
81210
+ for (const name of dedupe4(names2)) {
81185
81211
  const entry = catalog[name];
81186
81212
  if (entry === void 0) unknownServers.push(name);
81187
81213
  else servers[name] = entry;
@@ -81549,6 +81575,27 @@ var ResolvedEquipmentSchema = Struct({
81549
81575
  )
81550
81576
  })
81551
81577
  });
81578
+ var WorkerUsageSchema = Struct({
81579
+ context: optional(
81580
+ Struct({
81581
+ tokens: NullOr(Number$),
81582
+ contextWindow: Number$,
81583
+ percent: NullOr(Number$)
81584
+ })
81585
+ ),
81586
+ tokens: Struct({
81587
+ input: Number$,
81588
+ output: Number$,
81589
+ cacheRead: Number$,
81590
+ cacheWrite: Number$,
81591
+ total: Number$
81592
+ }),
81593
+ cost: Number$,
81594
+ toolCalls: Number$,
81595
+ totalMessages: Number$,
81596
+ latestCacheHitRate: optional(Number$),
81597
+ model: optional(NonEmptyString5)
81598
+ });
81552
81599
  var WorkerSummarySchema = Struct({
81553
81600
  workerId: NonEmptyString5,
81554
81601
  alias: optional(NonEmptyString5),
@@ -81563,6 +81610,8 @@ var WorkerSummarySchema = Struct({
81563
81610
  * listings, which stay compact.
81564
81611
  */
81565
81612
  equipment: optional(ResolvedEquipmentSchema),
81613
+ /** Present for the same reason equipment is, and absent for the same reason. */
81614
+ usage: optional(WorkerUsageSchema),
81566
81615
  result: optional(Struct({ text: String$, completedAt: Number$ })),
81567
81616
  error: optional(Struct({ code: String$, message: String$ }))
81568
81617
  });
@@ -82104,7 +82153,7 @@ var HOST_BOOTSTRAP_ENVIRONMENT_NAMES = [
82104
82153
  ];
82105
82154
 
82106
82155
  // packages/camp-state/src/bootstrap/campHostVersion.ts
82107
- var PRIIISK_HOST_VERSION = "0.1.19";
82156
+ var PRIIISK_HOST_VERSION = "0.1.21";
82108
82157
 
82109
82158
  // packages/camp-state/src/bootstrap/campLaunch.ts
82110
82159
  var CampBootstrapError = class extends TaggedError("CampBootstrapError") {
@@ -82823,6 +82872,7 @@ var CampAskState = {
82823
82872
  expired: "expired",
82824
82873
  interrupted: "interrupted"
82825
82874
  };
82875
+ var CampAskRelease = { interrupt: "interrupt", drop: "drop" };
82826
82876
  var CampAskRouter = class extends Tag2("priiisk/CampKernel/CampAskRouter")() {
82827
82877
  };
82828
82878
 
@@ -83141,6 +83191,33 @@ var removeRegistration = (state, askId, registration) => modify4(
83141
83191
  (reply) => reply === void 0 ? _void : fail7(reply, askError("ask.close", "cancelled", askId)).pipe(asVoid3)
83142
83192
  )
83143
83193
  );
83194
+ var releaseWorkerRegistrations = (state, workerId, drop5) => currentTimeMillis2.pipe(
83195
+ flatMap10(
83196
+ (now2) => modify4(state, (current2) => {
83197
+ const entries2 = new Map(current2.entries);
83198
+ const cancelled = [];
83199
+ for (const [askId, entry] of current2.entries) {
83200
+ if (entry.request.workerId !== workerId) continue;
83201
+ const open3 = entry.state.kind === "pending" || entry.state.kind === "claimed";
83202
+ if (open3) cancelled.push({ askId, reply: entry.reply });
83203
+ if (drop5) entries2.delete(askId);
83204
+ else if (open3) {
83205
+ entries2.set(askId, { ...entry, state: { kind: "interrupted", interruptedAt: now2 } });
83206
+ }
83207
+ }
83208
+ return [cancelled, { ...current2, entries: entries2 }];
83209
+ })
83210
+ ),
83211
+ flatMap10(
83212
+ (cancelled) => forEach9(
83213
+ cancelled,
83214
+ (item) => fail7(item.reply, askError("ask.close", "cancelled", item.askId)).pipe(
83215
+ asVoid3
83216
+ ),
83217
+ { discard: true }
83218
+ )
83219
+ )
83220
+ );
83144
83221
  var rollbackClaim = (state, askId, claim, terminalPerWorker) => currentTimeMillis2.pipe(
83145
83222
  flatMap10(
83146
83223
  (now2) => modify4(
@@ -83346,6 +83423,7 @@ var makeInMemoryCampAskRouterWithOptions = (options2 = {}) => gen2(function* ()
83346
83423
  )
83347
83424
  ),
83348
83425
  restore: (snapshots) => restoreAskSnapshots(state, snapshots, terminalPerWorker),
83426
+ releaseWorker: (workerId, release) => releaseWorkerRegistrations(state, workerId, release === CampAskRelease.drop),
83349
83427
  open: (request2) => gen2(function* () {
83350
83428
  if (request2.totalTimeoutMs !== void 0 && (!Number.isSafeInteger(request2.totalTimeoutMs) || request2.totalTimeoutMs <= 0)) {
83351
83429
  return yield* fail9(askError("ask.open", "invalid_timeout", request2.askId));
@@ -83951,6 +84029,7 @@ var finalizeWorkerLifecycle = (runtime6, id3, resource, finalization, command =
83951
84029
  })
83952
84030
  )
83953
84031
  );
84032
+ yield* runtime6.asks.releaseWorker(id3, CampAskRelease.interrupt);
83954
84033
  if (isFailure3(finalizationExit)) {
83955
84034
  return yield* failCause8(finalizationExit.cause);
83956
84035
  }
@@ -84857,6 +84936,7 @@ var makeCampKernel = gen2(function* () {
84857
84936
  close: close3,
84858
84937
  forget: (command, identity4) => gen2(function* () {
84859
84938
  const forgotten = yield* runtime6.registry.forget(identity4);
84939
+ yield* runtime6.asks.releaseWorker(forgotten.id, CampAskRelease.drop);
84860
84940
  yield* publishKernelEvent(runtime6, {
84861
84941
  kind: "forgotten",
84862
84942
  worker: forgotten,
@@ -85971,7 +86051,7 @@ var indexMcpTools = (revision, tools) => ({
85971
86051
  revision,
85972
86052
  tools: new Map(tools.map((tool) => [tool.name, tool]))
85973
86053
  });
85974
- var indexCustomTools = (revision, names) => ({ revision, names: new Set(names) });
86054
+ var indexCustomTools = (revision, names2) => ({ revision, names: new Set(names2) });
85975
86055
  var equippedHostTool = (equipped, tool) => ({
85976
86056
  ...tool,
85977
86057
  execute: async (toolCallId, parameters3, signal, onUpdate, context8) => {
@@ -86040,13 +86120,13 @@ var resolvePiSessionTools = (options2, runtime6, input, sessionRef, equipped, eq
86040
86120
  (metadata) => toPiToolDefinition(equippedMcpTool(equipped, metadata))
86041
86121
  )
86042
86122
  ];
86043
- const names = [
86123
+ const names2 = [
86044
86124
  ...input.equipment.builtinTools,
86045
86125
  ...hostTools.granted,
86046
86126
  ...input.mcpCatalog.map((metadata) => metadata.name).filter((name) => grantedMcp.has(name))
86047
86127
  ];
86048
86128
  const registered = customTools.map((tool) => tool.name);
86049
- return new Set(registered).size === registered.length ? succeed8({ customTools, names }) : fail9(toolsError(input, { reason: "duplicate_tool_name" }));
86129
+ return new Set(registered).size === registered.length ? succeed8({ customTools, names: names2 }) : fail9(toolsError(input, { reason: "duplicate_tool_name" }));
86050
86130
  })
86051
86131
  );
86052
86132
  };
@@ -87084,9 +87164,19 @@ var resolvedEquipmentDto = (equipment) => ({
87084
87164
  ...equipment.mcp.toolNamesByServer === void 0 ? {} : { toolNamesByServer: equipment.mcp.toolNamesByServer }
87085
87165
  }
87086
87166
  });
87087
- var workerDetailFromRecord = (worker) => ({
87167
+ var workerUsageDto = (usage) => ({
87168
+ ...usage.context === void 0 ? {} : { context: usage.context },
87169
+ tokens: usage.tokens,
87170
+ cost: usage.cost,
87171
+ toolCalls: usage.toolCalls,
87172
+ totalMessages: usage.totalMessages,
87173
+ ...usage.latestCacheHitRate === void 0 ? {} : { latestCacheHitRate: usage.latestCacheHitRate },
87174
+ ...usage.model === void 0 ? {} : { model: usage.model }
87175
+ });
87176
+ var workerDetailFromRecord = (worker, usage = void 0) => ({
87088
87177
  ...workerSummaryFromRecord(worker),
87089
- equipment: resolvedEquipmentDto(worker.equipment)
87178
+ equipment: resolvedEquipmentDto(worker.equipment),
87179
+ ...usage === void 0 ? {} : { usage: workerUsageDto(usage) }
87090
87180
  });
87091
87181
  var workerSummaryFromRecord = (worker) => ({
87092
87182
  workerId: worker.id,
@@ -89444,8 +89534,8 @@ function cleanRegex(source) {
89444
89534
  const end6 = source.endsWith("$") ? source.length - 1 : source.length;
89445
89535
  return source.slice(start5, end6);
89446
89536
  }
89447
- function floatSafeRemainder(val, step4) {
89448
- const ratio = val / step4;
89537
+ function floatSafeRemainder(val, step5) {
89538
+ const ratio = val / step5;
89449
89539
  const roundedRatio = Math.round(ratio);
89450
89540
  const tolerance = Number.EPSILON * Math.max(Math.abs(ratio), 1);
89451
89541
  if (Math.abs(ratio - roundedRatio) < tolerance)
@@ -98002,7 +98092,7 @@ var Client = class extends Protocol2 {
98002
98092
  };
98003
98093
 
98004
98094
  // packages/mcp-backend/src/connections/clientIdentity.ts
98005
- var backendVersion = "0.1.19";
98095
+ var backendVersion = "0.1.21";
98006
98096
 
98007
98097
  // packages/mcp-backend/src/connections/mcpFailure.ts
98008
98098
  var McpFailure = class extends TaggedError("McpFailure") {
@@ -99716,14 +99806,14 @@ var StreamableHTTPClientTransport = class {
99716
99806
  // packages/mcp-backend/src/secrets/secretResolution.ts
99717
99807
  var ENV_REFERENCE = /\$\{([A-Za-z_][A-Za-z0-9_]*)\}|\$env:([A-Za-z_][A-Za-z0-9_]*)/g;
99718
99808
  var referencedEnvNames = (values4) => {
99719
- const names = /* @__PURE__ */ new Set();
99809
+ const names2 = /* @__PURE__ */ new Set();
99720
99810
  for (const value5 of values4) {
99721
99811
  for (const match16 of value5.matchAll(ENV_REFERENCE)) {
99722
99812
  const name = match16[1] ?? match16[2];
99723
- if (name !== void 0) names.add(name);
99813
+ if (name !== void 0) names2.add(name);
99724
99814
  }
99725
99815
  }
99726
- return names;
99816
+ return names2;
99727
99817
  };
99728
99818
  var interpolateEnv = (value5, secretEnv) => value5.replace(
99729
99819
  ENV_REFERENCE,
@@ -101788,10 +101878,16 @@ var makeWorkerReadRpcHandlers = ({
101788
101878
  map17((workers) => workers.map(workerSummaryFromRecord))
101789
101879
  ),
101790
101880
  WorkerStatus: (request2) => validateReady(request2).pipe(
101881
+ /*
101882
+ * Status answers with the snapshot rather than the registry record: usage
101883
+ * lives on the live session, and without it the orchestrator cannot tell
101884
+ * whether a worker is nearly full or what it has cost — it decided blind
101885
+ * whether to reuse one (priiisk-brk).
101886
+ */
101791
101887
  zipRight3(
101792
- operations.status(commandContext(request2), workerIdentityFromDto(request2.worker))
101888
+ operations.snapshot(commandContext(request2), workerIdentityFromDto(request2.worker))
101793
101889
  ),
101794
- map17(workerDetailFromRecord),
101890
+ map17((snapshot) => workerDetailFromRecord(snapshot.worker, snapshot.session?.usage)),
101795
101891
  mapError2(asWorkerFailure("status"))
101796
101892
  ),
101797
101893
  /*
@@ -102540,6 +102636,7 @@ var makeInitialCampUiState = (snapshot, presentationNow = 0) => ({
102540
102636
  screen: CampUiScreen.camp,
102541
102637
  focusedSlotId: "roster",
102542
102638
  detailVisible: false,
102639
+ inventoryVisible: false,
102543
102640
  presentationNow,
102544
102641
  drafts: /* @__PURE__ */ new Map(),
102545
102642
  scrollOffsets: /* @__PURE__ */ new Map(),
@@ -102665,6 +102762,10 @@ var makeCampUiStore = (initial, presentationNow = 0) => gen2(function* () {
102665
102762
  if (state.detailVisible === detailVisible) return state;
102666
102763
  return { ...state, detailVisible };
102667
102764
  }),
102765
+ setInventoryVisible: (inventoryVisible) => updateState((state) => {
102766
+ if (state.inventoryVisible === inventoryVisible) return state;
102767
+ return { ...state, inventoryVisible };
102768
+ }),
102668
102769
  setDetailBlockExpanded: (blockId, expanded) => updateState((state) => ({
102669
102770
  ...state,
102670
102771
  expandedDetailBlockIds: updateCampUiStringSet(
@@ -102702,9 +102803,16 @@ var makeCampUiStore = (initial, presentationNow = 0) => gen2(function* () {
102702
102803
  var makeCampUiComponentGroup = (components) => {
102703
102804
  const inputComponents = components.some((component) => component.handleInput !== void 0);
102704
102805
  const pointerComponents = components.some((component) => component.handlePointer !== void 0);
102806
+ const sizingComponents = components.some((component) => component.preferredRows !== void 0);
102705
102807
  const invalidatingComponents = components.some((component) => component.invalidate !== void 0);
102706
102808
  return {
102707
102809
  render: (viewport) => components.flatMap((component) => component.render(viewport)),
102810
+ ...sizingComponents ? {
102811
+ preferredRows: (width) => components.reduce(
102812
+ (total, component) => total + (component.preferredRows?.(width) ?? 0),
102813
+ 0
102814
+ )
102815
+ } : {},
102708
102816
  ...components.some((component) => component.focusable === true) ? { focusable: true } : {},
102709
102817
  ...inputComponents ? {
102710
102818
  handleInput: (input) => [...components].reverse().some((component) => component.handleInput?.(input) === true)
@@ -102732,14 +102840,14 @@ var emptyCampUiComponent = {
102732
102840
  // packages/host-ui/src/composition/campUiSlots.ts
102733
102841
  var CampUiSlot = {
102734
102842
  campHeader: "camp-header",
102735
- seat: "seat",
102843
+ activity: "activity",
102844
+ equipment: "equipment",
102736
102845
  resources: "resources",
102737
102846
  roster: "roster",
102738
102847
  sessionHeader: "session-header",
102739
102848
  transcript: "transcript",
102740
102849
  composer: "composer",
102741
- campFooter: "camp-footer",
102742
- sessionFooter: "session-footer",
102850
+ footer: "footer",
102743
102851
  overlay: "overlay"
102744
102852
  };
102745
102853
  var CampUiContributionStrategy = {
@@ -102903,6 +103011,7 @@ var makeCampUiIntentHandler = (options2) => type2().pipe(
102903
103011
  }),
102904
103012
  SelectWorker: ({ workerId }) => options2.controller.selectWorker(workerId),
102905
103013
  SetDraft: ({ workerId, draft }) => options2.controller.setDraft(workerId, draft),
103014
+ SetInventoryVisible: ({ visible }) => options2.controller.setInventoryVisible(visible),
102906
103015
  SetScrollOffset: ({ workerId, offset }) => options2.controller.setScrollOffset(workerId, offset),
102907
103016
  SetTranscriptVisible: ({ visible }) => options2.controller.setDetailVisible(visible),
102908
103017
  Steer: ({ workerId, message }) => message.trim() === "" ? _void : options2.backend.steer({ workerId, message }).pipe(
@@ -102965,13 +103074,16 @@ var findCampUiSpatialFocusTarget = (frame, currentSlotId, focusableSlotIds, dire
102965
103074
  // packages/host-ui/src/layout/campUiLayoutPolicy.ts
102966
103075
  var defaultCampUiLayoutPolicy = {
102967
103076
  leftMinimumWidth: 28,
102968
- leftMaximumWidth: 40,
102969
- sessionMinimumWidth: 52,
103077
+ rightMinimumWidth: 28,
103078
+ leftTrackWidthThreshold: 82,
103079
+ rightTrackWidthThreshold: 112,
103080
+ trackGapWidth: 1,
102970
103081
  wideMinimumHeight: 18,
102971
- leftRatio: 0.3,
103082
+ campHeaderHeight: 1,
102972
103083
  footerHeight: 3,
102973
103084
  sessionHeaderHeight: 1,
102974
- composerHeight: 3
103085
+ composerMinimumHeight: 1,
103086
+ composerMaximumHeight: 4
102975
103087
  };
102976
103088
 
102977
103089
  // packages/host-ui/src/layout/campUiSizing.ts
@@ -102979,17 +103091,86 @@ var CampUiSectionSizeKind = {
102979
103091
  fixed: "fixed",
102980
103092
  grow: "grow"
102981
103093
  };
102982
- var rows = (value5) => Math.max(0, Math.floor(value5));
103094
+ var CampUiTrackSizeKind = {
103095
+ fixed: "fixed",
103096
+ min: "min",
103097
+ fill: "fill"
103098
+ };
103099
+ var units = (value5) => Number.isFinite(value5) ? Math.max(0, Math.floor(value5)) : 0;
103100
+ var allocateCampUiTrackColumns = (availableColumns, sizes) => {
103101
+ const width = units(availableColumns);
103102
+ const allocated = sizes.map(() => 0);
103103
+ const visible = sizes.map(
103104
+ (size14) => size14.collapseBelow === void 0 || width >= units(size14.collapseBelow)
103105
+ );
103106
+ const minimumIndexes = [];
103107
+ const fillIndexes = [];
103108
+ let remaining = width;
103109
+ for (const [index, size14] of sizes.entries()) {
103110
+ if (visible[index] !== true) continue;
103111
+ if (size14.kind === CampUiTrackSizeKind.min) {
103112
+ minimumIndexes.push(index);
103113
+ continue;
103114
+ }
103115
+ if (size14.kind === CampUiTrackSizeKind.fill) {
103116
+ fillIndexes.push(index);
103117
+ continue;
103118
+ }
103119
+ const trackWidth = Math.min(remaining, units(size14.columns));
103120
+ allocated[index] = trackWidth;
103121
+ remaining -= trackWidth;
103122
+ }
103123
+ const maximumMinimum = Math.max(
103124
+ 0,
103125
+ ...minimumIndexes.map((index) => {
103126
+ const size14 = sizes[index];
103127
+ return size14?.kind === CampUiTrackSizeKind.min ? units(size14.minimumColumns) : 0;
103128
+ })
103129
+ );
103130
+ for (let column = 0; column < maximumMinimum && remaining > 0; column += 1) {
103131
+ for (const index of minimumIndexes) {
103132
+ const size14 = sizes[index];
103133
+ if (size14?.kind !== CampUiTrackSizeKind.min || column >= units(size14.minimumColumns)) continue;
103134
+ allocated[index] = (allocated[index] ?? 0) + 1;
103135
+ remaining -= 1;
103136
+ if (remaining === 0) break;
103137
+ }
103138
+ }
103139
+ const weighted = fillIndexes.flatMap((index) => {
103140
+ const size14 = sizes[index];
103141
+ const weight = size14?.kind === CampUiTrackSizeKind.fill ? Math.max(0, size14.weight) : 0;
103142
+ return weight > 0 ? [{ index, weight }] : [];
103143
+ });
103144
+ const totalWeight = weighted.reduce((total, item) => total + item.weight, 0);
103145
+ if (remaining > 0 && totalWeight > 0) {
103146
+ const distributable = remaining;
103147
+ const shares = weighted.map((item) => {
103148
+ const exact = distributable * item.weight / totalWeight;
103149
+ return { ...item, columns: Math.floor(exact), fraction: exact - Math.floor(exact) };
103150
+ });
103151
+ for (const share2 of shares) allocated[share2.index] = share2.columns;
103152
+ let roundingRemainder = distributable - shares.reduce((total, item) => total + item.columns, 0);
103153
+ const remainderOrder = [...shares].sort(
103154
+ (left3, right3) => right3.fraction - left3.fraction || left3.index - right3.index
103155
+ );
103156
+ for (const share2 of remainderOrder) {
103157
+ if (roundingRemainder === 0) break;
103158
+ allocated[share2.index] = (allocated[share2.index] ?? 0) + 1;
103159
+ roundingRemainder -= 1;
103160
+ }
103161
+ }
103162
+ return allocated;
103163
+ };
102983
103164
  var allocateCampUiSectionRows = (availableRows, sizes) => {
102984
103165
  const allocated = sizes.map(() => 0);
102985
- let remaining = rows(availableRows);
103166
+ let remaining = units(availableRows);
102986
103167
  const growIndexes = [];
102987
103168
  for (const [index, size14] of sizes.entries()) {
102988
103169
  if (size14.kind === CampUiSectionSizeKind.grow) {
102989
103170
  growIndexes.push(index);
102990
103171
  continue;
102991
103172
  }
102992
- const height = Math.min(remaining, rows(size14.rows));
103173
+ const height = Math.min(remaining, units(size14.rows));
102993
103174
  allocated[index] = height;
102994
103175
  remaining -= height;
102995
103176
  }
@@ -102997,13 +103178,13 @@ var allocateCampUiSectionRows = (availableRows, sizes) => {
102997
103178
  0,
102998
103179
  ...growIndexes.map((index) => {
102999
103180
  const size14 = sizes[index];
103000
- return size14?.kind === CampUiSectionSizeKind.grow ? rows(size14.minimumRows ?? 0) : 0;
103181
+ return size14?.kind === CampUiSectionSizeKind.grow ? units(size14.minimumRows ?? 0) : 0;
103001
103182
  })
103002
103183
  );
103003
103184
  for (let minimumRow = 0; minimumRow < maximumMinimum && remaining > 0; minimumRow += 1) {
103004
103185
  for (const index of growIndexes) {
103005
103186
  const size14 = sizes[index];
103006
- if (size14?.kind !== CampUiSectionSizeKind.grow || minimumRow >= rows(size14.minimumRows ?? 0)) {
103187
+ if (size14?.kind !== CampUiSectionSizeKind.grow || minimumRow >= units(size14.minimumRows ?? 0)) {
103007
103188
  continue;
103008
103189
  }
103009
103190
  allocated[index] = (allocated[index] ?? 0) + 1;
@@ -103029,10 +103210,14 @@ var allocateCampUiSectionRows = (availableRows, sizes) => {
103029
103210
  return allocated;
103030
103211
  };
103031
103212
  var defaultCampUiLeftSectionSizes = {
103032
- camp: { kind: CampUiSectionSizeKind.fixed, rows: 4 },
103213
+ camp: { kind: CampUiSectionSizeKind.fixed, rows: 3 },
103033
103214
  resources: { kind: CampUiSectionSizeKind.grow, weight: 1, minimumRows: 1 },
103034
103215
  workers: { kind: CampUiSectionSizeKind.grow, weight: 1, minimumRows: 1 }
103035
103216
  };
103217
+ var defaultCampUiRightSectionSizes = {
103218
+ activity: { kind: CampUiSectionSizeKind.grow, weight: 1, minimumRows: 2 },
103219
+ equipment: { kind: CampUiSectionSizeKind.fixed, rows: 7 }
103220
+ };
103036
103221
 
103037
103222
  // packages/host-ui/src/layout/campUiLayout.ts
103038
103223
  var CampUiLayoutMode = {
@@ -103041,31 +103226,47 @@ var CampUiLayoutMode = {
103041
103226
  };
103042
103227
  var region = (slotId, x, y, width, height) => width <= 0 || height <= 0 ? void 0 : { slotId, x, y, width, height };
103043
103228
  var compact2 = (items) => items.filter((item) => item !== void 0);
103044
- var fixedRows = (available, requested) => Math.min(Math.max(available, 0), Math.max(requested, 0));
103229
+ var units2 = (value5) => Number.isFinite(value5) ? Math.max(0, Math.floor(value5)) : 0;
103230
+ var fixedRows = (available, requested) => Math.min(units2(available), units2(requested));
103045
103231
  var leftSectionHeights = (bodyHeight, slots) => {
103046
103232
  const size14 = (slotId, fallback) => slots?.get(slotId)?.sectionSize ?? fallback;
103047
103233
  return allocateCampUiSectionRows(bodyHeight, [
103048
103234
  size14(CampUiSlot.campHeader, defaultCampUiLeftSectionSizes.camp),
103049
- size14(CampUiSlot.resources, defaultCampUiLeftSectionSizes.resources),
103050
103235
  size14(CampUiSlot.roster, defaultCampUiLeftSectionSizes.workers)
103051
103236
  ]);
103052
103237
  };
103238
+ var rightSectionHeights = (bodyHeight, width, slots) => {
103239
+ const minimumActivityRows = Math.min(units2(bodyHeight), 2);
103240
+ const fallback = defaultCampUiRightSectionSizes.equipment.rows;
103241
+ const preferred = units2(
103242
+ slots?.get(CampUiSlot.equipment)?.preferredRows?.(units2(width)) ?? fallback
103243
+ );
103244
+ const equipmentHeight = fixedRows(Math.max(0, bodyHeight - minimumActivityRows), preferred);
103245
+ return [Math.max(0, bodyHeight - equipmentHeight), equipmentHeight];
103246
+ };
103247
+ var composerHeight = (availableHeight, width, policy, slots) => {
103248
+ const maximum = units2(policy.composerMaximumHeight);
103249
+ const minimum = Math.min(maximum, units2(policy.composerMinimumHeight));
103250
+ const preferred = units2(
103251
+ slots?.get(CampUiSlot.composer)?.preferredRows?.(units2(width)) ?? minimum
103252
+ );
103253
+ return fixedRows(availableHeight, Math.max(minimum, Math.min(maximum, preferred)));
103254
+ };
103053
103255
  var makeNarrowFrame = (viewport, state, policy, slots) => {
103054
103256
  const footerHeight = fixedRows(viewport.height, policy.footerHeight);
103055
103257
  const bodyHeight = Math.max(0, viewport.height - footerHeight);
103056
103258
  const footerY = bodyHeight;
103057
103259
  const workerScreen = state.screen === CampUiScreen.worker && state.selectedWorkerId !== void 0;
103058
- const [campHeight = 0, resourcesHeight = 0, rosterHeight = 0] = workerScreen ? [] : leftSectionHeights(bodyHeight, slots);
103260
+ const [campHeight = 0, rosterHeight = 0] = workerScreen ? [] : leftSectionHeights(bodyHeight, slots);
103059
103261
  const sessionHeaderHeight = workerScreen ? fixedRows(bodyHeight, policy.sessionHeaderHeight) : 0;
103060
- const composerHeight = workerScreen ? fixedRows(bodyHeight - sessionHeaderHeight, policy.composerHeight) : 0;
103061
- const transcriptHeight = workerScreen ? bodyHeight - sessionHeaderHeight - composerHeight : 0;
103262
+ const inputHeight = workerScreen ? composerHeight(bodyHeight - sessionHeaderHeight, viewport.width, policy, slots) : 0;
103263
+ const transcriptHeight = workerScreen ? bodyHeight - sessionHeaderHeight - inputHeight : 0;
103062
103264
  return {
103063
103265
  mode: CampUiLayoutMode.narrow,
103064
103266
  dividers: [],
103065
103267
  regions: compact2([
103066
103268
  region(CampUiSlot.campHeader, 0, 0, viewport.width, campHeight),
103067
- region(CampUiSlot.resources, 0, campHeight, viewport.width, resourcesHeight),
103068
- region(CampUiSlot.roster, 0, campHeight + resourcesHeight, viewport.width, rosterHeight),
103269
+ region(CampUiSlot.roster, 0, campHeight, viewport.width, rosterHeight),
103069
103270
  region(CampUiSlot.sessionHeader, 0, 0, viewport.width, sessionHeaderHeight),
103070
103271
  region(CampUiSlot.transcript, 0, sessionHeaderHeight, viewport.width, transcriptHeight),
103071
103272
  region(
@@ -103073,57 +103274,79 @@ var makeNarrowFrame = (viewport, state, policy, slots) => {
103073
103274
  0,
103074
103275
  sessionHeaderHeight + transcriptHeight,
103075
103276
  viewport.width,
103076
- composerHeight
103277
+ inputHeight
103077
103278
  ),
103078
- region(
103079
- workerScreen ? CampUiSlot.sessionFooter : CampUiSlot.campFooter,
103080
- 0,
103081
- footerY,
103082
- viewport.width,
103083
- footerHeight
103084
- )
103279
+ region(CampUiSlot.footer, 0, footerY, viewport.width, footerHeight)
103085
103280
  ])
103086
103281
  };
103087
103282
  };
103088
103283
  var makeWideFrame = (viewport, policy, slots) => {
103089
- const footerHeight = fixedRows(viewport.height, policy.footerHeight);
103090
- const bodyHeight = Math.max(0, viewport.height - footerHeight);
103091
- const leftWidth = Math.max(
103092
- policy.leftMinimumWidth,
103093
- Math.min(
103094
- policy.leftMaximumWidth,
103095
- viewport.width - policy.sessionMinimumWidth - 1,
103096
- Math.floor(viewport.width * policy.leftRatio)
103097
- )
103098
- );
103099
- const rightX = leftWidth + 1;
103100
- const rightWidth = viewport.width - rightX;
103101
- const [campHeight = 0, resourcesHeight = 0, rosterHeight = 0] = leftSectionHeights(
103284
+ const campHeaderHeight = fixedRows(viewport.height, policy.campHeaderHeight);
103285
+ const footerHeight = fixedRows(viewport.height - campHeaderHeight, policy.footerHeight);
103286
+ const bodyHeight = Math.max(0, viewport.height - campHeaderHeight - footerHeight);
103287
+ const footerY = campHeaderHeight + bodyHeight;
103288
+ const [leftWidth = 0, leftGap = 0, centerWidth = 0, rightGap = 0, rightWidth = 0] = allocateCampUiTrackColumns(viewport.width, [
103289
+ {
103290
+ kind: CampUiTrackSizeKind.min,
103291
+ minimumColumns: policy.leftMinimumWidth,
103292
+ collapseBelow: policy.leftTrackWidthThreshold
103293
+ },
103294
+ {
103295
+ kind: CampUiTrackSizeKind.fixed,
103296
+ columns: policy.trackGapWidth,
103297
+ collapseBelow: policy.leftTrackWidthThreshold
103298
+ },
103299
+ { kind: CampUiTrackSizeKind.fill, weight: 1 },
103300
+ {
103301
+ kind: CampUiTrackSizeKind.fixed,
103302
+ columns: policy.trackGapWidth,
103303
+ collapseBelow: policy.rightTrackWidthThreshold
103304
+ },
103305
+ {
103306
+ kind: CampUiTrackSizeKind.min,
103307
+ minimumColumns: policy.rightMinimumWidth,
103308
+ collapseBelow: policy.rightTrackWidthThreshold
103309
+ }
103310
+ ]);
103311
+ const centerX2 = leftWidth + leftGap;
103312
+ const rightX = centerX2 + centerWidth + rightGap;
103313
+ const [activityHeight = 0, equipmentHeight = 0] = rightSectionHeights(
103102
103314
  bodyHeight,
103315
+ rightWidth,
103103
103316
  slots
103104
103317
  );
103105
103318
  const sessionHeaderHeight = fixedRows(bodyHeight, policy.sessionHeaderHeight);
103106
- const composerHeight = fixedRows(bodyHeight - sessionHeaderHeight, policy.composerHeight);
103107
- const transcriptHeight = bodyHeight - sessionHeaderHeight - composerHeight;
103108
- const footerY = bodyHeight;
103319
+ const inputHeight = composerHeight(bodyHeight - sessionHeaderHeight, centerWidth, policy, slots);
103320
+ const transcriptHeight = bodyHeight - sessionHeaderHeight - inputHeight;
103321
+ const bodyY = campHeaderHeight;
103109
103322
  return {
103110
103323
  mode: CampUiLayoutMode.wide,
103111
- dividers: viewport.height === 0 ? [] : [{ x: leftWidth, y: 0, height: viewport.height }],
103324
+ dividers: [],
103112
103325
  regions: compact2([
103113
- region(CampUiSlot.campHeader, 0, 0, leftWidth, campHeight),
103114
- region(CampUiSlot.resources, 0, campHeight, leftWidth, resourcesHeight),
103115
- region(CampUiSlot.roster, 0, campHeight + resourcesHeight, leftWidth, rosterHeight),
103116
- region(CampUiSlot.sessionHeader, rightX, 0, rightWidth, sessionHeaderHeight),
103117
- region(CampUiSlot.transcript, rightX, sessionHeaderHeight, rightWidth, transcriptHeight),
103326
+ region(CampUiSlot.campHeader, 0, 0, viewport.width, campHeaderHeight),
103327
+ region(CampUiSlot.roster, 0, bodyY, leftWidth, bodyHeight),
103328
+ region(CampUiSlot.sessionHeader, centerX2, bodyY, centerWidth, sessionHeaderHeight),
103329
+ region(
103330
+ CampUiSlot.transcript,
103331
+ centerX2,
103332
+ bodyY + sessionHeaderHeight,
103333
+ centerWidth,
103334
+ transcriptHeight
103335
+ ),
103118
103336
  region(
103119
103337
  CampUiSlot.composer,
103120
- rightX,
103121
- sessionHeaderHeight + transcriptHeight,
103122
- rightWidth,
103123
- composerHeight
103338
+ centerX2,
103339
+ bodyY + sessionHeaderHeight + transcriptHeight,
103340
+ centerWidth,
103341
+ inputHeight
103124
103342
  ),
103125
- region(CampUiSlot.campFooter, 0, footerY, leftWidth, footerHeight),
103126
- region(CampUiSlot.sessionFooter, rightX, footerY, rightWidth, footerHeight)
103343
+ region(CampUiSlot.activity, rightX, bodyY, rightWidth, activityHeight),
103344
+ region(CampUiSlot.equipment, rightX, bodyY + activityHeight, rightWidth, equipmentHeight),
103345
+ /*
103346
+ * One line across the whole width: two footers pinned to the corners split
103347
+ * along the track boundary and repeated what the worker cards already say.
103348
+ */
103349
+ region(CampUiSlot.footer, 0, footerY, viewport.width, footerHeight)
103127
103350
  ])
103128
103351
  };
103129
103352
  };
@@ -103131,11 +103354,10 @@ var makeDefaultCampUiLayout = (policy = defaultCampUiLayoutPolicy) => ({
103131
103354
  id: "default",
103132
103355
  resolve: (viewport, state, slots) => {
103133
103356
  const normalized = {
103134
- width: Math.max(0, viewport.width),
103135
- height: Math.max(0, viewport.height)
103357
+ width: units2(viewport.width),
103358
+ height: units2(viewport.height)
103136
103359
  };
103137
- const wideMinimumWidth = policy.leftMinimumWidth + 1 + policy.sessionMinimumWidth;
103138
- return normalized.width >= wideMinimumWidth && normalized.height >= policy.wideMinimumHeight ? makeWideFrame(normalized, policy, slots) : makeNarrowFrame(normalized, state, policy, slots);
103360
+ return normalized.height >= policy.wideMinimumHeight ? makeWideFrame(normalized, policy, slots) : makeNarrowFrame(normalized, state, policy, slots);
103139
103361
  }
103140
103362
  });
103141
103363
 
@@ -103217,7 +103439,6 @@ var jsonText = (value5) => {
103217
103439
  return String(value5);
103218
103440
  }
103219
103441
  };
103220
- var compactNumber = (value5) => new Intl.NumberFormat("en", { notation: "compact", maximumFractionDigits: 1 }).format(value5);
103221
103442
 
103222
103443
  // packages/host-ui/src/pi/shared/campUiVisual.ts
103223
103444
  var CampUiTone = {
@@ -103270,7 +103491,7 @@ var statePresentation = /* @__PURE__ */ new Map([
103270
103491
  ["idle", { tone: CampUiTone.neutral, glyph: CampUiGlyph.neutral }]
103271
103492
  ]);
103272
103493
  var styleCampUiTone = (tone, text4) => `${ansiByTone[tone]}${text4}\x1B[39m`;
103273
- var uniqueCampUiNames = (names) => [...new Set(names)].sort((left3, right3) => left3.localeCompare(right3));
103494
+ var uniqueCampUiNames = (names2) => [...new Set(names2)].sort((left3, right3) => left3.localeCompare(right3));
103274
103495
  var renderCampUiStatus = (label, tone, glyph = glyphByTone[tone]) => styleCampUiTone(tone, `${glyph} ${label}`);
103275
103496
  var renderCampUiState = (state) => {
103276
103497
  const presentation = statePresentation.get(state) ?? {
@@ -103309,7 +103530,7 @@ var fallbackWorkerPresentation = {
103309
103530
  glyph: CampUiGlyph.neutral
103310
103531
  };
103311
103532
  var attentionStates = /* @__PURE__ */ new Set(["waiting_for_orchestrator", "recovering", "retrying"]);
103312
- var renderCampUiWorkerState = (state, options2) => {
103533
+ var resolveCampUiWorkerState = (state, options2) => {
103313
103534
  const base = workerStatePresentation.get(state) ?? fallbackWorkerPresentation;
103314
103535
  const terminal = state === "completed" || state === "closed";
103315
103536
  const streamingLifts = !terminal && options2.streaming && !attentionStates.has(state);
@@ -103318,13 +103539,9 @@ var renderCampUiWorkerState = (state, options2) => {
103318
103539
  tone: CampUiTone.attention,
103319
103540
  glyph: CampUiGlyph.attention
103320
103541
  } : streamingLifts ? workerStatePresentation.get("running") : base;
103321
- const resolved = presentation ?? fallbackWorkerPresentation;
103322
- return renderCampUiStatus(resolved.label, resolved.tone, resolved.glyph);
103323
- };
103324
- var renderSelectedCampUiRow = (line, width) => {
103325
- const selected = getSelectListTheme().selectedText(fitCampUiLine(line, width));
103326
- return `\x1B[7m${selected}\x1B[27m`;
103542
+ return presentation ?? fallbackWorkerPresentation;
103327
103543
  };
103544
+ var campUiWorkerStateLabel = (state, options2) => resolveCampUiWorkerState(state, options2).label;
103328
103545
 
103329
103546
  // packages/host-ui/src/pi/blocks/campUiDirectedBlock.ts
103330
103547
  import { getMarkdownTheme, getSelectListTheme as getSelectListTheme2 } from "@earendil-works/pi-coding-agent";
@@ -103386,44 +103603,44 @@ var toneByState = {
103386
103603
  [CampAskState.expired]: CampUiTone.error,
103387
103604
  [CampAskState.interrupted]: CampUiTone.error
103388
103605
  };
103606
+ var campUiAskDetailBlock = (ask, model, width) => {
103607
+ const blockId = campUiAskBlockId(ask.askId);
103608
+ const mode = ask.blocking ? "blocking" : "non-blocking";
103609
+ const stateLabel = {
103610
+ [CampAskState.pending]: `pending \xB7 ${formatCampUiDuration(
103611
+ model.state.presentationNow - ask.openedAt
103612
+ )}`,
103613
+ [CampAskState.answered]: "answered",
103614
+ [CampAskState.expired]: "expired",
103615
+ [CampAskState.interrupted]: "interrupted"
103616
+ }[ask.state];
103617
+ const summary5 = {
103618
+ [CampAskState.pending]: `Awaiting orchestrator reply \xB7 ${ask.askId}`,
103619
+ [CampAskState.answered]: `${ask.answerSummary ?? "Answered"} \xB7 ${ask.askId}`,
103620
+ [CampAskState.expired]: `Expired \xB7 ${ask.askId}`,
103621
+ [CampAskState.interrupted]: `Interrupted by host restart \xB7 ${ask.askId}`
103622
+ }[ask.state];
103623
+ return {
103624
+ id: blockId,
103625
+ lines: renderCampUiDirectedBlock(
103626
+ {
103627
+ label: `Ask \xB7 to ${ask.controllerId} \xB7 ${mode} \xB7 ${stateLabel}`,
103628
+ markdown: ask.question,
103629
+ summary: summary5,
103630
+ tone: toneByState[ask.state],
103631
+ expanded: model.state.expandedDetailBlockIds.has(blockId),
103632
+ ...ask.state === CampAskState.answered ? { collapsedBodyLines: 0, showToggleHint: false } : {}
103633
+ },
103634
+ width
103635
+ ),
103636
+ toggleable: ask.state !== CampAskState.answered
103637
+ };
103638
+ };
103639
+ var isCampUiPendingAsk = (ask) => ask.state === CampAskState.pending;
103389
103640
  var campUiPendingAskBlockRenderer = {
103390
103641
  id: "pending-asks",
103391
103642
  order: 100,
103392
- render: ({ model, worker, width }) => {
103393
- return worker.asks.map((ask) => {
103394
- const blockId = campUiAskBlockId(ask.askId);
103395
- const mode = ask.blocking ? "blocking" : "non-blocking";
103396
- const stateLabel = {
103397
- [CampAskState.pending]: `pending \xB7 ${formatCampUiDuration(
103398
- model.state.presentationNow - ask.openedAt
103399
- )}`,
103400
- [CampAskState.answered]: "answered",
103401
- [CampAskState.expired]: "expired",
103402
- [CampAskState.interrupted]: "interrupted"
103403
- }[ask.state];
103404
- const summary5 = {
103405
- [CampAskState.pending]: `Awaiting orchestrator reply \xB7 ${ask.askId}`,
103406
- [CampAskState.answered]: `${ask.answerSummary ?? "Answered"} \xB7 ${ask.askId}`,
103407
- [CampAskState.expired]: `Expired \xB7 ${ask.askId}`,
103408
- [CampAskState.interrupted]: `Interrupted by host restart \xB7 ${ask.askId}`
103409
- }[ask.state];
103410
- return {
103411
- id: blockId,
103412
- lines: renderCampUiDirectedBlock(
103413
- {
103414
- label: `Ask \xB7 to ${ask.controllerId} \xB7 ${mode} \xB7 ${stateLabel}`,
103415
- markdown: ask.question,
103416
- summary: summary5,
103417
- tone: toneByState[ask.state],
103418
- expanded: model.state.expandedDetailBlockIds.has(blockId),
103419
- ...ask.state === CampAskState.answered ? { collapsedBodyLines: 0, showToggleHint: false } : {}
103420
- },
103421
- width
103422
- ),
103423
- toggleable: ask.state !== CampAskState.answered
103424
- };
103425
- });
103426
- }
103643
+ render: ({ model, worker, width }) => worker.asks.filter(isCampUiPendingAsk).map((ask) => campUiAskDetailBlock(ask, model, width))
103427
103644
  };
103428
103645
 
103429
103646
  // packages/host-ui/src/pi/blocks/campUiAssistantMessage.ts
@@ -103508,7 +103725,7 @@ var campUiResultSignature = (result) => result === void 0 ? "pending" : campUiMe
103508
103725
 
103509
103726
  // packages/host-ui/src/pi/blocks/campUiComposer.ts
103510
103727
  import { getMarkdownTheme as getMarkdownTheme3, getSelectListTheme as getSelectListTheme4 } from "@earendil-works/pi-coding-agent";
103511
- import { Editor, Key as Key2, matchesKey } from "@earendil-works/pi-tui";
103728
+ import { CURSOR_MARKER, Editor, Key as Key2, matchesKey } from "@earendil-works/pi-tui";
103512
103729
  var makeCampUiComposerComponent = (context8, tui) => {
103513
103730
  const markdownTheme = getMarkdownTheme3();
103514
103731
  const selectTheme = getSelectListTheme4();
@@ -103555,20 +103772,40 @@ var makeCampUiComposerComponent = (context8, tui) => {
103555
103772
  editors.set(workerId, created);
103556
103773
  return created;
103557
103774
  };
103775
+ const renderSelectedEditor = (width) => {
103776
+ const model = context8.readModel();
103777
+ const workerId = model.state.selectedWorkerId;
103778
+ const entry = selectedEditor();
103779
+ if (workerId === void 0 || entry === void 0) return void 0;
103780
+ const { editor } = entry;
103781
+ const focused = model.state.focusedSlotId === CampUiSlot.composer;
103782
+ editor.focused = focused;
103783
+ editor.borderColor = focused ? selectTheme.selectedPrefix : markdownTheme.codeBlockBorder;
103784
+ entry.setDraft(model.state.drafts.get(workerId) ?? "");
103785
+ editor.focused = true;
103786
+ let lines3;
103787
+ try {
103788
+ lines3 = editor.render(width).slice(1, -1);
103789
+ } finally {
103790
+ editor.focused = focused;
103791
+ }
103792
+ const cursorRow = lines3.findIndex((line) => line.includes(CURSOR_MARKER));
103793
+ return {
103794
+ cursorRow,
103795
+ lines: lines3.map((line) => focused ? line : line.replaceAll(CURSOR_MARKER, ""))
103796
+ };
103797
+ };
103558
103798
  return {
103559
103799
  focusable: true,
103800
+ preferredRows: (width) => renderSelectedEditor(width)?.lines.length ?? 1,
103560
103801
  render: (viewport) => {
103561
- const model = context8.readModel();
103562
- const workerId = model.state.selectedWorkerId;
103563
- const entry = selectedEditor();
103564
- if (workerId === void 0 || entry === void 0) {
103565
- return [selectTheme.description("worker not selected")];
103566
- }
103567
- const { editor } = entry;
103568
- editor.focused = model.state.focusedSlotId === CampUiSlot.composer;
103569
- editor.borderColor = editor.focused ? selectTheme.selectedPrefix : markdownTheme.codeBlockBorder;
103570
- entry.setDraft(model.state.drafts.get(workerId) ?? "");
103571
- return editor.render(viewport.width).slice(0, viewport.height);
103802
+ const rendered = renderSelectedEditor(viewport.width);
103803
+ if (rendered === void 0) return [selectTheme.description("worker not selected")];
103804
+ const start5 = rendered.cursorRow < 0 ? 0 : Math.min(
103805
+ Math.max(0, rendered.lines.length - viewport.height),
103806
+ Math.max(0, rendered.cursorRow - viewport.height + 1)
103807
+ );
103808
+ return rendered.lines.slice(start5, start5 + viewport.height);
103572
103809
  },
103573
103810
  handleInput: (input) => {
103574
103811
  const entry = selectedEditor();
@@ -103602,50 +103839,12 @@ var makeCampUiComposerComponent = (context8, tui) => {
103602
103839
  import { getSelectListTheme as getSelectListTheme8 } from "@earendil-works/pi-coding-agent";
103603
103840
  import { Key as Key3, matchesKey as matchesKey2 } from "@earendil-works/pi-tui";
103604
103841
 
103605
- // packages/host-ui/src/pi/blocks/campUiEquipmentBlock.ts
103606
- import { getMarkdownTheme as getMarkdownTheme4, UserMessageComponent } from "@earendil-works/pi-coding-agent";
103607
- var escapeMarkdown = (value5) => value5.replaceAll(/([\\`*_[\]{}()#+.!|>])/gu, "\\$1");
103608
- var renderNames = (names) => names.length === 0 ? "none" : names.map(escapeMarkdown).join(", ");
103609
- var renderMcpServers = (equipment) => renderNames(
103610
- equipment.mcp.serverNames.map((serverName) => {
103611
- const toolNames = equipment.mcp.toolNamesByServer?.[serverName];
103612
- return toolNames === void 0 ? serverName : `${serverName} (${toolNames.join(", ")})`;
103613
- })
103614
- );
103615
- var equipmentMarkdown = (equipment) => {
103616
- const role = equipment.role ?? equipment.preset ?? "unknown";
103617
- const tools = [.../* @__PURE__ */ new Set([...equipment.builtinTools, ...equipment.customToolNames])].sort();
103618
- const lines3 = [
103619
- `**Equipment \xB7 ${escapeMarkdown(role)}**`,
103620
- "",
103621
- `- **Tools:** ${renderNames(tools)}`,
103622
- `- **MCP:** ${renderMcpServers(equipment)}`,
103623
- `- **Skills:** ${renderNames(equipment.skillNames)}`,
103624
- `- **Access:** ${equipment.readOnly ? "read-only" : "read/write"}`
103625
- ];
103626
- return lines3.join("\n");
103627
- };
103628
- var campUiEquipmentBlockRenderer = {
103629
- id: "role-equipment",
103630
- order: -100,
103631
- render: ({ worker, width }) => [
103632
- {
103633
- id: "role-equipment",
103634
- lines: new UserMessageComponent(
103635
- equipmentMarkdown(worker.snapshot.worker.equipment),
103636
- getMarkdownTheme4(),
103637
- 0
103638
- ).render(width)
103639
- }
103640
- ]
103641
- };
103642
-
103643
103842
  // packages/host-ui/src/pi/blocks/campUiTranscriptBlocks.ts
103644
- import { getMarkdownTheme as getMarkdownTheme7, UserMessageComponent as UserMessageComponent2 } from "@earendil-works/pi-coding-agent";
103843
+ import { getMarkdownTheme as getMarkdownTheme6, UserMessageComponent } from "@earendil-works/pi-coding-agent";
103645
103844
  import { Markdown as Markdown4 } from "@earendil-works/pi-tui";
103646
103845
 
103647
103846
  // packages/host-ui/src/pi/shared/campUiPanel.ts
103648
- import { getMarkdownTheme as getMarkdownTheme5, getSelectListTheme as getSelectListTheme5 } from "@earendil-works/pi-coding-agent";
103847
+ import { getMarkdownTheme as getMarkdownTheme4, getSelectListTheme as getSelectListTheme5 } from "@earendil-works/pi-coding-agent";
103649
103848
  import { truncateToWidth as truncateToWidth3, visibleWidth as visibleWidth2 } from "@earendil-works/pi-tui";
103650
103849
  var rule = (start5, label, width, borderColor, labelColor) => {
103651
103850
  const prefix = `${borderColor(`${start5}\u2500 `)}${labelColor(label)}${borderColor(" ")}`;
@@ -103654,7 +103853,7 @@ var rule = (start5, label, width, borderColor, labelColor) => {
103654
103853
  };
103655
103854
  var renderCampUiPanel = (label, body, width) => {
103656
103855
  if (width <= 0) return [];
103657
- const borderColor = getMarkdownTheme5().codeBlockBorder;
103856
+ const borderColor = getMarkdownTheme4().codeBlockBorder;
103658
103857
  const labelColor = getSelectListTheme5().selectedText;
103659
103858
  if (width === 1) {
103660
103859
  return [borderColor("\u2502"), ...body.map(() => borderColor("\u2502")), borderColor("\u2570")];
@@ -103794,7 +103993,7 @@ var renderCampUiExploredGroup = (reads, width, expanded) => {
103794
103993
 
103795
103994
  // packages/host-ui/src/pi/blocks/campUiToolResult.ts
103796
103995
  import {
103797
- getMarkdownTheme as getMarkdownTheme6,
103996
+ getMarkdownTheme as getMarkdownTheme5,
103798
103997
  getSelectListTheme as getSelectListTheme7,
103799
103998
  truncateToVisualLines
103800
103999
  } from "@earendil-works/pi-coding-agent";
@@ -103865,13 +104064,13 @@ var renderCampUiToolResult = (result, width, expanded) => {
103865
104064
  ]);
103866
104065
  }
103867
104066
  const content = toolResultContent(result, true);
103868
- const lines3 = content === "" ? [] : new Markdown3(content, 0, 0, getMarkdownTheme6()).render(boundedWidth);
104067
+ const lines3 = content === "" ? [] : new Markdown3(content, 0, 0, getMarkdownTheme5()).render(boundedWidth);
103869
104068
  return keep([
103870
104069
  ...lines3,
103871
104070
  ...result.errorMessage === void 0 ? [] : [getSelectListTheme7().noMatch(`Error: ${result.errorMessage}`)],
103872
104071
  ...result.toolResultDetails === void 0 ? [] : [
103873
104072
  getSelectListTheme7().description("Details"),
103874
- ...new Markdown3(jsonText(result.toolResultDetails), 0, 0, getMarkdownTheme6()).render(
104073
+ ...new Markdown3(jsonText(result.toolResultDetails), 0, 0, getMarkdownTheme5()).render(
103875
104074
  boundedWidth
103876
104075
  )
103877
104076
  ],
@@ -103918,7 +104117,7 @@ var renderMessage = (message, width) => {
103918
104117
  ] : [];
103919
104118
  return [
103920
104119
  ...attribution,
103921
- ...new UserMessageComponent2(markdown2, getMarkdownTheme7(), 0).render(width)
104120
+ ...new UserMessageComponent(markdown2, getMarkdownTheme6(), 0).render(width)
103922
104121
  ];
103923
104122
  }
103924
104123
  if (message.role === "assistant") {
@@ -103932,11 +104131,11 @@ var renderMessage = (message, width) => {
103932
104131
  const suffix = message.errorMessage === void 0 ? "" : `
103933
104132
 
103934
104133
  Error: ${message.errorMessage}`;
103935
- return new Markdown4(`${prefix}${markdown}${suffix}`, 0, 0, getMarkdownTheme7()).render(width);
104134
+ return new Markdown4(`${prefix}${markdown}${suffix}`, 0, 0, getMarkdownTheme6()).render(width);
103936
104135
  };
103937
- var renderMarkdown = (markdown, width) => new Markdown4(markdown, 0, 0, getMarkdownTheme7()).render(Math.max(1, width));
103938
- var firstStringArgument = (parameters3, names) => {
103939
- for (const name of names) {
104136
+ var renderMarkdown = (markdown, width) => new Markdown4(markdown, 0, 0, getMarkdownTheme6()).render(Math.max(1, width));
104137
+ var firstStringArgument = (parameters3, names2) => {
104138
+ for (const name of names2) {
103940
104139
  const value5 = parameters3[name];
103941
104140
  if (typeof value5 === "string" && value5.trim() !== "") return value5;
103942
104141
  }
@@ -103983,7 +104182,7 @@ var exploredRead = (toolCall, path, result) => {
103983
104182
  ...errorMessage4 === void 0 ? {} : { errorMessage: errorMessage4 }
103984
104183
  };
103985
104184
  };
103986
- var renderTranscript = (transcript, width, expandedDetailBlockIds) => {
104185
+ var renderTranscript = (transcript, width, expandedDetailBlockIds, settledAsks) => {
103987
104186
  const results = /* @__PURE__ */ new Map();
103988
104187
  const callIds = /* @__PURE__ */ new Set();
103989
104188
  for (const message of transcript) {
@@ -104010,7 +104209,19 @@ var renderTranscript = (transcript, width, expandedDetailBlockIds) => {
104010
104209
  });
104011
104210
  group2 = [];
104012
104211
  };
104212
+ let nextAsk = 0;
104213
+ const flushAsksUntil = (timestamp) => {
104214
+ if (timestamp === void 0) return;
104215
+ while (nextAsk < settledAsks.length) {
104216
+ const pending3 = settledAsks[nextAsk];
104217
+ if (pending3 === void 0 || pending3.at > timestamp) return;
104218
+ closeGroup();
104219
+ blocks.push(pending3.block);
104220
+ nextAsk += 1;
104221
+ }
104222
+ };
104013
104223
  transcript.forEach((message, index) => {
104224
+ flushAsksUntil(message.timestamp);
104014
104225
  const messageId = message.id ?? String(index);
104015
104226
  if (message.role === "toolResult") {
104016
104227
  if (message.toolCallId !== void 0 && callIds.has(message.toolCallId)) return;
@@ -104057,21 +104268,26 @@ var renderTranscript = (transcript, width, expandedDetailBlockIds) => {
104057
104268
  }
104058
104269
  });
104059
104270
  closeGroup();
104271
+ for (const remaining of settledAsks.slice(nextAsk)) blocks.push(remaining.block);
104060
104272
  return blocks;
104061
104273
  };
104062
104274
  var campUiTranscriptBlockRenderer = {
104063
104275
  id: "transcript",
104064
104276
  order: 0,
104065
- render: ({ model, worker, width }) => renderTranscript(
104066
- worker.snapshot.session?.transcript ?? [],
104067
- width,
104068
- model.state.expandedDetailBlockIds
104069
- )
104277
+ render: (context8) => {
104278
+ const { model, worker, width } = context8;
104279
+ const settledAsks = worker.asks.filter((ask) => !isCampUiPendingAsk(ask)).map((ask) => ({ at: ask.openedAt, block: campUiAskDetailBlock(ask, model, width) })).sort((left3, right3) => left3.at - right3.at);
104280
+ return renderTranscript(
104281
+ worker.snapshot.session?.transcript ?? [],
104282
+ width,
104283
+ model.state.expandedDetailBlockIds,
104284
+ settledAsks
104285
+ );
104286
+ }
104070
104287
  };
104071
104288
 
104072
104289
  // packages/host-ui/src/pi/blocks/campUiDetail.ts
104073
104290
  var defaultCampUiDetailBlockRenderers = [
104074
- campUiEquipmentBlockRenderer,
104075
104291
  campUiTranscriptBlockRenderer,
104076
104292
  campUiPendingAskBlockRenderer
104077
104293
  ];
@@ -104210,12 +104426,261 @@ var makeCampUiDetailComponent = (context8, registry2 = defaultCampUiDetailBlockR
104210
104426
  };
104211
104427
  };
104212
104428
 
104213
- // packages/host-ui/src/pi/layout/campUiChrome.ts
104429
+ // packages/host-ui/src/pi/layout/campUiActivity.ts
104214
104430
  import { getSelectListTheme as getSelectListTheme9 } from "@earendil-works/pi-coding-agent";
104431
+ import { sliceByColumn, visibleWidth as visibleWidth3 } from "@earendil-works/pi-tui";
104432
+ var CampUiActivityAccess = {
104433
+ read: "read",
104434
+ edit: "edit",
104435
+ write: "write"
104436
+ };
104437
+ var accessByTool = /* @__PURE__ */ new Map([
104438
+ ["read", CampUiActivityAccess.read],
104439
+ ["edit", CampUiActivityAccess.edit],
104440
+ ["write", CampUiActivityAccess.write]
104441
+ ]);
104442
+ var accessRank = {
104443
+ read: 0,
104444
+ edit: 1,
104445
+ write: 2
104446
+ };
104447
+ var filePathArgument = (parameters3) => {
104448
+ for (const name of ["path", "file_path"]) {
104449
+ const value5 = parameters3[name];
104450
+ if (typeof value5 === "string" && value5.trim() !== "") return value5.trim();
104451
+ }
104452
+ return void 0;
104453
+ };
104454
+ var splitPath2 = (path) => {
104455
+ const separator = path.lastIndexOf("/");
104456
+ if (separator < 0) return { directory: ".", name: path };
104457
+ if (separator === 0) return { directory: "/", name: path.slice(1) || path };
104458
+ return { directory: path.slice(0, separator), name: path.slice(separator + 1) || path };
104459
+ };
104460
+ var collectCampUiActivityTree = (transcript) => {
104461
+ const directories = /* @__PURE__ */ new Map();
104462
+ const nodes = /* @__PURE__ */ new Map();
104463
+ for (const message of transcript) {
104464
+ for (const content of message.content) {
104465
+ if (content.kind !== "tool-call") continue;
104466
+ const access3 = accessByTool.get(content.toolName);
104467
+ if (access3 === void 0) continue;
104468
+ const path = filePathArgument(content.arguments);
104469
+ if (path === void 0) continue;
104470
+ const existing = nodes.get(path);
104471
+ if (existing !== void 0) {
104472
+ existing.count += 1;
104473
+ if (accessRank[access3] > accessRank[existing.access]) existing.access = access3;
104474
+ continue;
104475
+ }
104476
+ const { directory, name } = splitPath2(path);
104477
+ const node = { path, directory, name, access: access3, count: 1 };
104478
+ nodes.set(path, node);
104479
+ const group2 = directories.get(directory) ?? { path: directory, nodes: [] };
104480
+ if (!directories.has(directory)) directories.set(directory, group2);
104481
+ group2.nodes.push(node);
104482
+ }
104483
+ }
104484
+ return [...directories.values()].map((directory) => ({
104485
+ path: directory.path,
104486
+ nodes: directory.nodes.map((node) => ({ ...node }))
104487
+ }));
104488
+ };
104489
+ var CAMP_UI_ACTIVITY_MAX_VISIBLE_PATHS = 12;
104490
+ var ACTIVITY_COLUMNS_PER_VISIBLE_PATH = 4;
104491
+ var flattenedNodes = (tree) => tree.flatMap((directory) => directory.nodes);
104492
+ var renderedRowCount = (tree, selected, hidden) => {
104493
+ const directories = tree.filter(
104494
+ (directory) => directory.nodes.some((node) => selected.has(node))
104495
+ ).length;
104496
+ return selected.size + directories + (hidden > 0 ? 1 : 0);
104497
+ };
104498
+ var selectVisibleNodes2 = (tree, width, height) => {
104499
+ const nodes = flattenedNodes(tree);
104500
+ const selected = /* @__PURE__ */ new Set();
104501
+ const widthBudget = Math.max(
104502
+ 1,
104503
+ Math.floor(Math.max(0, width) / ACTIVITY_COLUMNS_PER_VISIBLE_PATH)
104504
+ );
104505
+ const nodeBudget = Math.min(CAMP_UI_ACTIVITY_MAX_VISIBLE_PATHS, widthBudget);
104506
+ const mutations = nodes.filter((node) => node.access !== CampUiActivityAccess.read);
104507
+ const reads = nodes.filter((node) => node.access === CampUiActivityAccess.read);
104508
+ const addVisible = (node) => {
104509
+ if (selected.size >= nodeBudget) return;
104510
+ const candidate = new Set(selected).add(node);
104511
+ const hidden = nodes.length - candidate.size;
104512
+ if (renderedRowCount(tree, candidate, hidden) <= Math.max(0, height)) selected.add(node);
104513
+ };
104514
+ for (const node of mutations) addVisible(node);
104515
+ if (mutations.some((node) => !selected.has(node))) return selected;
104516
+ for (const node of reads) addVisible(node);
104517
+ return selected;
104518
+ };
104519
+ var shortenTail = (value5, width) => {
104520
+ const available = Math.max(0, Math.floor(width));
104521
+ const valueWidth = visibleWidth3(value5);
104522
+ if (valueWidth <= available) return value5;
104523
+ if (available <= 0) return "";
104524
+ if (available === 1) return "\u2026";
104525
+ return `\u2026${sliceByColumn(value5, valueWidth - available + 1, available - 1, true)}`;
104526
+ };
104527
+ var accessPresentation = {
104528
+ read: { label: "read", glyph: "r", tone: CampUiTone.neutral },
104529
+ edit: { label: "edited", glyph: "~", tone: CampUiTone.attention },
104530
+ write: { label: "created", glyph: "+", tone: CampUiTone.success }
104531
+ };
104532
+ var nodeLine2 = (node, last5, width) => {
104533
+ const theme = getSelectListTheme9();
104534
+ const presentation = accessPresentation[node.access];
104535
+ const count4 = node.count > 1 ? ` \xD7${String(node.count)}` : "";
104536
+ const suffix = ` \xB7 ${presentation.label}${count4}`;
104537
+ const branch = last5 ? "\u2514\u2500" : "\u251C\u2500";
104538
+ const nameWidth = Math.max(1, width - visibleWidth3(`${branch} ${presentation.glyph} ${suffix}`));
104539
+ const name = shortenTail(node.name, nameWidth);
104540
+ return fitCampUiLine(
104541
+ `${theme.description(branch)} ${renderCampUiStatus(name, presentation.tone, presentation.glyph)}${theme.description(suffix)}`,
104542
+ width
104543
+ );
104544
+ };
104545
+ var hiddenSummary = (nodes) => {
104546
+ const parts2 = Object.values(CampUiActivityAccess).flatMap((access3) => {
104547
+ const count4 = nodes.filter((node) => node.access === access3).length;
104548
+ if (count4 === 0) return [];
104549
+ const label = accessPresentation[access3].label;
104550
+ return [`${String(count4)} ${label} ${count4 === 1 ? "path" : "paths"}`];
104551
+ });
104552
+ return `... ${parts2.join(" \xB7 ")} hidden`;
104553
+ };
104554
+ var renderCampUiActivityTree = (transcript, width, height) => {
104555
+ const theme = getSelectListTheme9();
104556
+ const tree = collectCampUiActivityTree(transcript);
104557
+ const nodes = flattenedNodes(tree);
104558
+ if (height <= 0) return [];
104559
+ if (nodes.length === 0) return [fitCampUiLine(theme.description("no file activity"), width)];
104560
+ const selected = selectVisibleNodes2(tree, width, height);
104561
+ const lines3 = [];
104562
+ for (const directory of tree) {
104563
+ const visible = directory.nodes.filter((node) => selected.has(node));
104564
+ if (visible.length === 0) continue;
104565
+ lines3.push(fitCampUiLine(theme.description(shortenTail(directory.path, width)), width));
104566
+ visible.forEach((node, index) => {
104567
+ lines3.push(nodeLine2(node, index === visible.length - 1, width));
104568
+ });
104569
+ }
104570
+ const hidden = nodes.filter((node) => !selected.has(node));
104571
+ if (hidden.length > 0) {
104572
+ lines3.push(fitCampUiLine(theme.description(hiddenSummary(hidden)), width));
104573
+ }
104574
+ return lines3;
104575
+ };
104576
+ var makeCampUiActivity = (context8) => ({
104577
+ render: (viewport) => {
104578
+ const model = context8.readModel();
104579
+ const workerId = model.state.selectedWorkerId;
104580
+ const worker = workerId === void 0 ? void 0 : findCampUiWorker(model.snapshot, workerId);
104581
+ return renderCampUiActivityTree(
104582
+ worker?.snapshot.session?.transcript ?? [],
104583
+ viewport.width,
104584
+ viewport.height
104585
+ );
104586
+ }
104587
+ });
104588
+
104589
+ // packages/host-ui/src/pi/layout/campUiChrome.ts
104590
+ import { getSelectListTheme as getSelectListTheme10 } from "@earendil-works/pi-coding-agent";
104591
+ import { truncateToWidth as truncateToWidth4, visibleWidth as visibleWidth4 } from "@earendil-works/pi-tui";
104592
+
104593
+ // packages/host-ui/src/pi/shared/campUiPulse.ts
104594
+ var BRAILLE_BASE = 10240;
104595
+ var DOT_BITS = [
104596
+ [1, 2, 4, 64],
104597
+ [8, 16, 32, 128]
104598
+ ];
104599
+ var ROWS_PER_CELL = 4;
104600
+ var LINES = 2;
104601
+ var LEVELS = ROWS_PER_CELL * LINES;
104602
+ var SAMPLES_PER_COLUMN = 2;
104603
+ var EMPTY_CELL = String.fromCharCode(BRAILLE_BASE);
104604
+ var emptyPulse = (columns) => {
104605
+ const blank = EMPTY_CELL.repeat(Math.max(0, columns));
104606
+ return [blank, blank];
104607
+ };
104608
+ var renderCampUiPulse = (samples, options2) => {
104609
+ const columns = Math.max(0, Math.floor(options2.columns));
104610
+ if (columns === 0 || samples.length === 0) return emptyPulse(columns);
104611
+ const window2 = samples.slice(-columns * SAMPLES_PER_COLUMN);
104612
+ const peak = options2.ceiling ?? Math.max(...window2);
104613
+ const scale2 = peak > 0 ? peak : 1;
104614
+ const cells = [new Array(columns).fill(0), new Array(columns).fill(0)];
104615
+ const offset = columns * SAMPLES_PER_COLUMN - window2.length;
104616
+ window2.forEach((value5, index) => {
104617
+ const position3 = offset + index;
104618
+ const column = Math.floor(position3 / SAMPLES_PER_COLUMN);
104619
+ const half = position3 % SAMPLES_PER_COLUMN;
104620
+ const height = Math.max(0, Math.min(LEVELS - 1, Math.round(value5 / scale2 * (LEVELS - 1))));
104621
+ const row = LEVELS - 1 - height;
104622
+ const line = Math.floor(row / ROWS_PER_CELL);
104623
+ const bits = DOT_BITS[half]?.[row % ROWS_PER_CELL];
104624
+ const target2 = cells[line];
104625
+ if (bits === void 0 || target2 === void 0) return;
104626
+ target2[column] = (target2[column] ?? 0) | bits;
104627
+ });
104628
+ const [upper, lower] = cells.map(
104629
+ (row) => row.map((bits) => String.fromCharCode(BRAILLE_BASE + bits)).join("")
104630
+ );
104631
+ return [upper ?? "", lower ?? ""];
104632
+ };
104633
+
104634
+ // packages/host-ui/src/pi/shared/campUiTone.ts
104635
+ var CampUiLevel = {
104636
+ /** An ordinary card: present, but not asking to be read. */
104637
+ resting: "resting",
104638
+ /** The cursor is on this card; its session is not open. */
104639
+ focused: "focused",
104640
+ /** The open card, whose session fills the centre. */
104641
+ selected: "selected"
104642
+ };
104643
+ var roleColors = {
104644
+ foreman: { r: 122, g: 192, b: 140 },
104645
+ wright: { r: 196, g: 96, b: 108 },
104646
+ assayer: { r: 214, g: 168, b: 96 },
104647
+ prospector: { r: 120, g: 178, b: 214 }
104648
+ };
104649
+ var UNKNOWN_ROLE = { r: 178, g: 178, b: 190 };
104650
+ var CampUiInk = {
104651
+ primary: { r: 216, g: 216, b: 228 },
104652
+ secondary: { r: 182, g: 182, b: 196 },
104653
+ muted: { r: 154, g: 154, b: 168 }
104654
+ };
104655
+ var levelSteps = {
104656
+ [CampUiLevel.selected]: { saturation: 1, brightness: 1 },
104657
+ [CampUiLevel.focused]: { saturation: 0.72, brightness: 0.96 },
104658
+ [CampUiLevel.resting]: { saturation: 0.45, brightness: 0.9 }
104659
+ };
104660
+ var luminance = ({ r, g, b }) => 0.2126 * r + 0.7152 * g + 0.0722 * b;
104661
+ var FOREGROUND_RESET = "\x1B[39m";
104662
+ var step4 = (color, level) => {
104663
+ const { saturation, brightness } = levelSteps[level];
104664
+ const grey = luminance(color);
104665
+ const blend = (channel) => Math.max(0, Math.min(255, Math.round((grey + (channel - grey) * saturation) * brightness)));
104666
+ return { r: blend(color.r), g: blend(color.g), b: blend(color.b) };
104667
+ };
104668
+ var foreground = (color) => `\x1B[38;2;${String(color.r)};${String(color.g)};${String(color.b)}m`;
104669
+ var campUiRoleColor = (role) => role === void 0 ? UNKNOWN_ROLE : roleColors[role] ?? UNKNOWN_ROLE;
104670
+ var campUiText = (text4, color, level) => `${foreground(step4(color, level))}${text4}${FOREGROUND_RESET}`;
104671
+ var campUiPulseText = (pulse, level, roleColor) => campUiText(pulse, level === CampUiLevel.selected ? roleColor : CampUiInk.secondary, level);
104672
+ var levelMarkers = {
104673
+ [CampUiLevel.selected]: "\u25CF",
104674
+ [CampUiLevel.focused]: "\u25CB",
104675
+ [CampUiLevel.resting]: " "
104676
+ };
104677
+ var campUiLevelMarkerText = (level, color) => level === CampUiLevel.resting ? levelMarkers[level] : campUiText(levelMarkers[level], color, level);
104678
+
104679
+ // packages/host-ui/src/pi/layout/campUiChrome.ts
104215
104680
  var makeCampUiCampHeader = (context8) => ({
104216
104681
  render: (viewport) => {
104217
104682
  const snapshot = context8.readModel().snapshot;
104218
- const theme = getSelectListTheme9();
104683
+ const theme = getSelectListTheme10();
104219
104684
  const mode = snapshot.placement === "external" ? "agentless" : "foreman";
104220
104685
  return [
104221
104686
  fitCampUiLine(theme.description(snapshot.displayName), viewport.width),
@@ -104226,55 +104691,158 @@ var makeCampUiCampHeader = (context8) => ({
104226
104691
  ];
104227
104692
  }
104228
104693
  });
104229
- var makeCampUiSeat = (context8) => ({
104230
- render: (viewport) => {
104231
- const snapshot = context8.readModel().snapshot;
104232
- const theme = getSelectListTheme9();
104233
- const external = snapshot.placement === "external";
104234
- const controller = snapshot.controllerConnected ? renderCampUiStatus("live", CampUiTone.success, CampUiGlyph.live) : renderCampUiStatus("lost", CampUiTone.error);
104235
- return [
104236
- fitCampUiLine(
104237
- external ? `${renderCampUiStatus("controller", CampUiTone.external)} ${theme.description("\xB7 external \xB7")} ${controller}` : `${renderCampUiStatus("foreman", CampUiTone.neutral)} ${theme.description("\xB7 session not reported \xB7")} ${controller}`,
104238
- viewport.width
104239
- )
104240
- ];
104241
- }
104242
- });
104694
+ var PULSE_WINDOW_MS = 12e4;
104695
+ var PULSE_CEILING = 4;
104696
+ var PULSE_SAMPLES_PER_COLUMN = 2;
104697
+ var rosterWidths = (width) => {
104698
+ const right3 = Math.min(17, Math.max(0, width - 17));
104699
+ const left3 = Math.min(11, Math.max(0, width - right3 - 6));
104700
+ return { left: left3, pulse: Math.max(0, width - left3 - right3 - 4), right: right3 };
104701
+ };
104702
+ var rightColumn = (text4, width) => {
104703
+ const fitted = truncateToWidth4(text4, width);
104704
+ return `${" ".repeat(Math.max(0, width - visibleWidth4(fitted)))}${fitted}`;
104705
+ };
104706
+ var pulseSamples = (timestamps, sampleCount, now2) => {
104707
+ if (sampleCount <= 0) return [];
104708
+ const samples = new Array(sampleCount).fill(0);
104709
+ const windowStart = now2 - PULSE_WINDOW_MS;
104710
+ const interval = PULSE_WINDOW_MS / sampleCount;
104711
+ for (const timestamp of timestamps) {
104712
+ if (timestamp < windowStart || timestamp > now2) continue;
104713
+ const index = Math.min(sampleCount - 1, Math.floor((timestamp - windowStart) / interval));
104714
+ samples[index] = (samples[index] ?? 0) + 1;
104715
+ }
104716
+ return samples;
104717
+ };
104718
+ var elapsedText = (updatedAt, now2) => {
104719
+ const seconds2 = Math.floor(Math.max(0, now2 - updatedAt) / 1e3);
104720
+ if (seconds2 < 60) return `${String(seconds2)}s`;
104721
+ const minutes2 = Math.floor(seconds2 / 60);
104722
+ if (minutes2 < 60) return `${String(minutes2)}m`;
104723
+ const hours2 = Math.floor(minutes2 / 60);
104724
+ if (hours2 < 24) return `${String(hours2)}h`;
104725
+ return `${String(Math.floor(hours2 / 24))}d`;
104726
+ };
104727
+ var percentText = (percent) => percent === null || percent === void 0 ? "\u2014" : `${percent.toFixed(0)}%`;
104728
+ var usageText = (entry, width) => {
104729
+ const usage = entry.snapshot.session?.usage;
104730
+ const context8 = percentText(usage?.context?.percent);
104731
+ const cache = usage?.latestCacheHitRate === void 0 ? usage === void 0 || usage.tokens.total === 0 ? "n/a" : "n/r" : percentText(usage.latestCacheHitRate);
104732
+ const cost = usage === void 0 ? "\u2014" : `$${usage.cost.toFixed(3)}`;
104733
+ const full = `${context8} ${cache} ${cost}`;
104734
+ if (visibleWidth4(full) <= width || usage === void 0) return full;
104735
+ const compactCost = `$${usage.cost.toFixed(2).replace(/^0/u, "")}`;
104736
+ return `${context8}${cache}${compactCost}`;
104737
+ };
104738
+ var stateText = (state, duration5, width) => {
104739
+ const full = `${state} ${duration5}`;
104740
+ return visibleWidth4(full) <= width ? full : state;
104741
+ };
104742
+ var modelText = (entry) => {
104743
+ const model = entry.snapshot.session?.usage?.model ?? entry.snapshot.worker.equipment.model;
104744
+ if (model === void 0) return "model unknown";
104745
+ return model.split("/").at(-1) ?? model;
104746
+ };
104747
+ var cardLine = (marker, left3, pulse, right3, widths, width) => fitCampUiLine(
104748
+ `${marker} ${fitCampUiLine(left3, widths.left)} ${fitCampUiLine(pulse, widths.pulse)} ${rightColumn(right3, widths.right)}`,
104749
+ width
104750
+ );
104751
+ var renderExternalControllerCard = (controllerConnected, width) => {
104752
+ const level = CampUiLevel.resting;
104753
+ const color = campUiRoleColor("foreman");
104754
+ const widths = rosterWidths(width);
104755
+ const neutral = (text4) => campUiText(text4, CampUiInk.secondary, level);
104756
+ return [
104757
+ cardLine(
104758
+ campUiLevelMarkerText(level, color),
104759
+ campUiText("controller", color, level),
104760
+ "",
104761
+ neutral("ext"),
104762
+ widths,
104763
+ width
104764
+ ),
104765
+ cardLine(
104766
+ " ",
104767
+ "",
104768
+ "",
104769
+ neutral(controllerConnected ? "lease live" : "lease lost"),
104770
+ widths,
104771
+ width
104772
+ )
104773
+ ];
104774
+ };
104775
+ var renderWorkerCard = (entry, selectedWorkerId, detailVisible, now2, width) => {
104776
+ const worker = entry.snapshot.worker;
104777
+ const session = entry.snapshot.session;
104778
+ const level = worker.id !== selectedWorkerId ? CampUiLevel.resting : detailVisible ? CampUiLevel.selected : CampUiLevel.focused;
104779
+ const roleColor = campUiRoleColor(worker.equipment.role);
104780
+ const widths = rosterWidths(width);
104781
+ const timestamps = (session?.transcript ?? []).flatMap(
104782
+ (message) => message.timestamp === void 0 ? [] : [message.timestamp]
104783
+ );
104784
+ const pulse = renderCampUiPulse(
104785
+ pulseSamples(timestamps, widths.pulse * PULSE_SAMPLES_PER_COLUMN, now2),
104786
+ { columns: widths.pulse, ceiling: PULSE_CEILING }
104787
+ );
104788
+ const pendingAsks = entry.asks.filter((ask) => ask.state === "pending").length;
104789
+ const state = campUiWorkerStateLabel(worker.state, {
104790
+ failed: entry.error !== void 0,
104791
+ pendingAsks,
104792
+ streaming: session?.isStreaming === true
104793
+ });
104794
+ const neutral = (text4) => campUiText(text4, CampUiInk.secondary, level);
104795
+ const name = worker.alias ?? worker.id.slice(0, 8);
104796
+ return [
104797
+ cardLine(
104798
+ campUiLevelMarkerText(level, roleColor),
104799
+ campUiText(name, roleColor, level),
104800
+ campUiPulseText(pulse[0], level, roleColor),
104801
+ neutral(modelText(entry)),
104802
+ widths,
104803
+ width
104804
+ ),
104805
+ cardLine(
104806
+ " ",
104807
+ neutral(stateText(state, elapsedText(worker.updatedAt, now2), widths.left)),
104808
+ campUiPulseText(pulse[1], level, roleColor),
104809
+ neutral(usageText(entry, widths.right)),
104810
+ widths,
104811
+ width
104812
+ )
104813
+ ];
104814
+ };
104243
104815
  var makeCampUiRoster = (context8) => ({
104244
104816
  focusable: true,
104245
104817
  render: (viewport) => {
104246
104818
  const model = context8.readModel();
104247
- const theme = getSelectListTheme9();
104248
- const focused = model.state.focusedSlotId === CampUiSlot.roster;
104249
- if (model.snapshot.workers.length === 0) {
104250
- return [theme.description("No workers")];
104251
- }
104252
- const workers = model.snapshot.workers.map((entry) => {
104253
- const worker = entry.snapshot.worker;
104254
- const selected = worker.id === model.state.selectedWorkerId;
104255
- const name = worker.alias ?? worker.id.slice(0, 8);
104256
- const session = entry.snapshot.session;
104257
- const active2 = uniqueCampUiNames([
104258
- ...session?.activeToolNames ?? [],
104259
- ...session?.pendingToolNames ?? []
104260
- ]);
104261
- const pendingAsks = entry.asks.filter((ask) => ask.state === "pending").length;
104262
- const tool = active2.length === 0 ? "" : styleCampUiTone(CampUiTone.active, ` ${active2.slice(0, 2).join(", ")}`);
104263
- const label = selected ? theme.selectedText(name) : name;
104264
- const role = theme.description(`(${worker.equipment.role ?? "unknown"})`);
104265
- const status2 = renderCampUiWorkerState(worker.state, {
104266
- failed: entry.error !== void 0,
104267
- pendingAsks,
104268
- streaming: session?.isStreaming === true
104269
- });
104270
- const line = `${status2} ${label} ${role}${tool}`;
104271
- return selected && focused ? renderSelectedCampUiRow(line, viewport.width) : fitCampUiLine(line, viewport.width);
104819
+ const external = model.snapshot.placement === CampUiPlacement.external;
104820
+ if (model.snapshot.workers.length === 0 && !external) {
104821
+ return [getSelectListTheme10().description("No workers")];
104822
+ }
104823
+ const controller = external ? renderExternalControllerCard(model.snapshot.controllerConnected, viewport.width) : [];
104824
+ const workers = model.snapshot.workers.flatMap((entry) => {
104825
+ const candidateNow = model.state.presentationNow;
104826
+ const now2 = Number.isFinite(candidateNow) ? candidateNow : entry.snapshot.worker.updatedAt;
104827
+ return renderWorkerCard(
104828
+ entry,
104829
+ model.state.selectedWorkerId,
104830
+ model.state.detailVisible,
104831
+ now2,
104832
+ viewport.width
104833
+ );
104272
104834
  });
104273
- return workers;
104835
+ return [...controller, ...workers];
104274
104836
  },
104275
104837
  handlePointer: (pointer) => {
104276
104838
  if (pointer.action !== "press" || pointer.button !== "left") return [];
104277
- const workerId = context8.readModel().snapshot.workers[pointer.y]?.snapshot.worker.id;
104839
+ const model = context8.readModel();
104840
+ const controllerRows = model.snapshot.placement === CampUiPlacement.external ? 2 : 0;
104841
+ if (pointer.y < controllerRows) {
104842
+ return [CampUiIntents.FocusSlot({ slotId: CampUiSlot.roster })];
104843
+ }
104844
+ const workerIndex = Math.floor((pointer.y - controllerRows) / 2);
104845
+ const workerId = model.snapshot.workers[workerIndex]?.snapshot.worker.id;
104278
104846
  if (workerId === void 0) return [];
104279
104847
  return [
104280
104848
  CampUiIntents.FocusSlot({ slotId: CampUiSlot.roster }),
@@ -104285,7 +104853,7 @@ var makeCampUiRoster = (context8) => ({
104285
104853
  var makeCampUiSessionHeader = (context8) => ({
104286
104854
  render: (viewport) => {
104287
104855
  const model = context8.readModel();
104288
- const theme = getSelectListTheme9();
104856
+ const theme = getSelectListTheme10();
104289
104857
  const workerId = model.state.selectedWorkerId;
104290
104858
  if (workerId === void 0) {
104291
104859
  return [fitCampUiLine(theme.description("Select a worker"), viewport.width)];
@@ -104306,29 +104874,63 @@ var makeCampUiSessionHeader = (context8) => ({
104306
104874
  ] : []
104307
104875
  });
104308
104876
 
104309
- // packages/host-ui/src/pi/layout/campUiFooter.ts
104310
- import { getMarkdownTheme as getMarkdownTheme8, getSelectListTheme as getSelectListTheme10 } from "@earendil-works/pi-coding-agent";
104311
- var aggregateCampUsage = (workers) => {
104312
- const usages = workers.flatMap(
104313
- (worker) => worker.snapshot.session?.usage === void 0 ? [] : [worker.snapshot.session.usage]
104877
+ // packages/host-ui/src/pi/layout/campUiEquipment.ts
104878
+ import { getSelectListTheme as getSelectListTheme11 } from "@earendil-works/pi-coding-agent";
104879
+ import { wrapTextWithAnsi } from "@earendil-works/pi-tui";
104880
+ var fullEquipmentLines = (equipment, revision, width) => {
104881
+ if (width <= 0) return [];
104882
+ const theme = getSelectListTheme11();
104883
+ return equipmentDescriptionLines(equipment, revision).flatMap(
104884
+ (line) => wrapTextWithAnsi(theme.description(line), width).map(
104885
+ (wrapped) => fitCampUiLine(wrapped, width)
104886
+ )
104314
104887
  );
104888
+ };
104889
+ var renderCampUiEquipment = (equipment, revision, width, height) => {
104890
+ const lines3 = fullEquipmentLines(equipment, revision, width);
104891
+ const available = Math.max(0, Math.floor(height));
104892
+ if (available === 0 || lines3.length === 0) return [];
104893
+ if (lines3.length <= available) return lines3;
104894
+ const shown = lines3.slice(0, Math.max(0, available - 1));
104895
+ const hidden = lines3.length - shown.length;
104896
+ const summary5 = getSelectListTheme11().description(
104897
+ `... ${String(hidden)} equipment ${hidden === 1 ? "line" : "lines"} hidden`
104898
+ );
104899
+ return [...shown, fitCampUiLine(summary5, width)];
104900
+ };
104901
+ var makeCampUiEquipment = (context8) => {
104902
+ const selectedWorker = () => {
104903
+ const model = context8.readModel();
104904
+ const workerId = model.state.selectedWorkerId;
104905
+ return workerId === void 0 ? void 0 : findCampUiWorker(model.snapshot, workerId);
104906
+ };
104907
+ const fullLines = (width) => {
104908
+ const worker = selectedWorker();
104909
+ return worker === void 0 ? [fitCampUiLine(getSelectListTheme11().description("no worker selected"), width)] : fullEquipmentLines(
104910
+ worker.snapshot.worker.equipment,
104911
+ worker.snapshot.worker.equipmentVersion,
104912
+ width
104913
+ );
104914
+ };
104315
104915
  return {
104316
- cost: usages.reduce((total, usage) => total + usage.cost, 0),
104317
- reportedWorkers: usages.length,
104318
- tokens: usages.reduce((total, usage) => total + usage.tokens.total, 0),
104319
- totalWorkers: workers.length
104916
+ preferredRows: (width) => fullLines(width).length,
104917
+ render: (viewport) => {
104918
+ const worker = selectedWorker();
104919
+ if (worker === void 0) return fullLines(viewport.width).slice(0, viewport.height);
104920
+ return renderCampUiEquipment(
104921
+ worker.snapshot.worker.equipment,
104922
+ worker.snapshot.worker.equipmentVersion,
104923
+ viewport.width,
104924
+ viewport.height
104925
+ );
104926
+ }
104320
104927
  };
104321
104928
  };
104322
- var aggregateUsageText = (usage) => {
104323
- const partial4 = usage.reportedWorkers < usage.totalWorkers;
104324
- const coverage = partial4 ? ` \xB7 ${usage.reportedWorkers}/${usage.totalWorkers} reported` : "";
104325
- if (usage.totalWorkers > 0 && usage.reportedWorkers === 0) {
104326
- return `tokens unknown \xB7 cost unknown${coverage}`;
104327
- }
104328
- const lowerBound = partial4 ? "\u2265" : "";
104329
- return `\u2193 ${lowerBound}${compactNumber(usage.tokens)} tokens \xB7 ${lowerBound}$${usage.cost.toFixed(3)}${coverage}`;
104330
- };
104331
- var footerDivider = (width) => fitCampUiLine(getMarkdownTheme8().codeBlockBorder("\u2500".repeat(width)), width);
104929
+
104930
+ // packages/host-ui/src/pi/layout/campUiFooter.ts
104931
+ import { getMarkdownTheme as getMarkdownTheme7, getSelectListTheme as getSelectListTheme12 } from "@earendil-works/pi-coding-agent";
104932
+ import { sliceByColumn as sliceByColumn2, visibleWidth as visibleWidth5 } from "@earendil-works/pi-tui";
104933
+ var footerDivider = (width) => fitCampUiLine(getMarkdownTheme7().codeBlockBorder("\u2500".repeat(width)), width);
104332
104934
  var retryText = (retryAt, attempt, now2) => {
104333
104935
  if (retryAt === void 0) return attempt === void 0 ? "" : `attempt ${String(attempt)}`;
104334
104936
  const seconds2 = Math.max(0, Math.ceil((retryAt - now2) / 1e3));
@@ -104339,56 +104941,73 @@ var diagnosticText = (value5) => {
104339
104941
  const normalized = value5?.replaceAll(/\s+/gu, " ").trim();
104340
104942
  return normalized === "" ? void 0 : normalized;
104341
104943
  };
104342
- var makeCampUiCampFooter = (context8) => ({
104944
+ var workerCountText = (workers) => {
104945
+ if (workers.length === 0) return "no workers";
104946
+ const working = workers.filter(
104947
+ (worker) => worker.snapshot.worker.state === CampWorkerState.running
104948
+ ).length;
104949
+ const waiting = workers.filter((worker) => worker.asks.some(isPendingAsk)).length;
104950
+ const parts2 = [
104951
+ `${String(workers.length)} ${workers.length === 1 ? "worker" : "workers"}`,
104952
+ ...working === 0 ? [] : [`${String(working)} working`],
104953
+ ...waiting === 0 ? [] : [`${String(waiting)} waiting`]
104954
+ ];
104955
+ return parts2.join(" \xB7 ");
104956
+ };
104957
+ var isPendingAsk = (ask) => ask.state === "pending";
104958
+ var shortenPath = (value5, width) => {
104959
+ const available = Math.max(0, Math.floor(width));
104960
+ if (available <= 0) return "";
104961
+ if (visibleWidth5(value5) <= available) return value5;
104962
+ if (available === 1) return "\u2026";
104963
+ const kept = available - 1;
104964
+ return `\u2026${sliceByColumn2(value5, visibleWidth5(value5) - kept, kept, true)}`;
104965
+ };
104966
+ var makeCampUiFooter = (context8) => ({
104343
104967
  render: (viewport) => {
104344
104968
  const model = context8.readModel();
104345
- const theme = getSelectListTheme10();
104346
- const health = model.snapshot.health;
104347
- const usage = aggregateUsageText(aggregateCampUsage(model.snapshot.workers));
104969
+ const theme = getSelectListTheme12();
104970
+ const snapshot = model.snapshot;
104971
+ const health = snapshot.health;
104348
104972
  const actionError = diagnosticText(model.state.lastActionError);
104349
104973
  const healthSummary = diagnosticText(health.message);
104350
104974
  const healthMessage = health.code === void 0 ? healthSummary : healthSummary === void 0 ? health.code : `${health.code} \xB7 ${healthSummary}`;
104351
104975
  const healthTone = health.status === CampUiHealthStatus.failed ? CampUiTone.error : CampUiTone.attention;
104352
- const diagnostic = actionError !== void 0 ? `${renderCampUiStatus("action error", CampUiTone.error)} ${theme.description(`\xB7 ${actionError}`)}` : healthMessage !== void 0 ? styleCampUiTone(healthTone, healthMessage) : health.status === CampUiHealthStatus.ready ? "" : renderCampUiStatus(health.status, healthTone);
104353
104976
  const retry5 = retryText(health.retryAt, health.attempt, model.state.presentationNow);
104354
- return [
104355
- footerDivider(viewport.width),
104356
- joinCampUiColumns(diagnostic, theme.description(usage), viewport.width),
104357
- fitCampUiLine(retry5 === "" ? "" : theme.description(retry5), viewport.width)
104977
+ const diagnostic = actionError !== void 0 ? `${renderCampUiStatus("action error", CampUiTone.error)} ${theme.description(`\xB7 ${actionError}`)}` : healthMessage !== void 0 ? styleCampUiTone(healthTone, healthMessage) : health.status === CampUiHealthStatus.ready ? "" : renderCampUiStatus(health.status, healthTone);
104978
+ const branch = snapshot.projectBranch === null ? "" : ` \xB7 ${snapshot.projectBranch}`;
104979
+ const version2 = `v${snapshot.hostVersion}`;
104980
+ const candidates = [
104981
+ { right: [workerCountText(snapshot.workers), version2, retry5], branch },
104982
+ { right: [workerCountText(snapshot.workers), version2], branch },
104983
+ { right: [version2], branch },
104984
+ { right: [version2], branch: "" }
104358
104985
  ];
104359
- }
104360
- });
104361
- var makeCampUiSessionFooter = (context8) => ({
104362
- render: (viewport) => {
104363
- const model = context8.readModel();
104364
- const theme = getSelectListTheme10();
104365
- const workerId = model.state.selectedWorkerId;
104366
- const worker = workerId === void 0 ? void 0 : findCampUiWorker(model.snapshot, workerId);
104367
- const usage = worker?.snapshot.session?.usage;
104368
- const tokenText = usage === void 0 ? "tokens unknown" : `\u2193 ${compactNumber(usage.tokens.total)} tokens`;
104369
- const costText = usage === void 0 ? "cost unknown" : `$${usage.cost.toFixed(3)}`;
104370
- const cacheText = usage?.latestCacheHitRate === void 0 ? usage === void 0 || usage.tokens.total === 0 ? "cache n/a" : "cache not reported" : `cache ${usage.latestCacheHitRate.toFixed(0)}%`;
104371
- const contextText = usage?.context?.percent === null || usage?.context?.percent === void 0 ? "context unknown" : `context ${usage.context.percent.toFixed(0)}%`;
104372
- const modelText = usage?.model ?? worker?.snapshot.worker.equipment.model ?? "model unknown";
104373
- const thinking = worker?.snapshot.session?.thinkingLevel ?? worker?.snapshot.worker.equipment.thinkingLevel ?? "unknown";
104374
- const identity4 = worker === void 0 ? theme.description("worker not selected") : `${theme.selectedText(worker.snapshot.worker.alias ?? worker.snapshot.worker.id.slice(0, 8))} ${theme.description(`\xB7 ${worker.snapshot.worker.cwd}`)}`;
104375
- const branch = worker === void 0 || model.snapshot.projectBranch === null ? "" : theme.description(`branch ${model.snapshot.projectBranch}`);
104986
+ const MINIMUM_PATH_COLUMNS = 8;
104987
+ const chosen = candidates.find((candidate) => {
104988
+ const rightWidth = visibleWidth5(candidate.right.filter((part) => part !== "").join(" \xB7 "));
104989
+ const room = viewport.width - rightWidth - 3 - visibleWidth5(candidate.branch);
104990
+ return room >= MINIMUM_PATH_COLUMNS;
104991
+ }) ?? candidates[candidates.length - 1];
104992
+ const right3 = (chosen ?? candidates[0])?.right.filter((part) => part !== "").join(" \xB7 ") ?? "";
104993
+ const chosenBranch = chosen?.branch ?? "";
104994
+ const leftBudget = Math.max(0, viewport.width - visibleWidth5(right3) - 3);
104995
+ const path = shortenPath(
104996
+ snapshot.projectScope,
104997
+ Math.max(0, leftBudget - visibleWidth5(chosenBranch))
104998
+ );
104999
+ const left3 = diagnostic === "" ? theme.description(`${path}${chosenBranch}`) : `${diagnostic} ${theme.description(`\xB7 ${path}${chosenBranch}`)}`;
104376
105000
  return [
104377
105001
  footerDivider(viewport.width),
104378
- branch === "" ? fitCampUiLine(identity4, viewport.width) : joinCampUiColumns(identity4, branch, viewport.width),
104379
- joinCampUiColumns(
104380
- theme.description(`${tokenText} \xB7 ${costText} \xB7 ${cacheText} \xB7 ${contextText}`),
104381
- theme.description(`${modelText} \xB7 effort ${thinking}`),
104382
- viewport.width
104383
- )
105002
+ joinCampUiColumns(left3, theme.description(right3), viewport.width)
104384
105003
  ];
104385
105004
  }
104386
105005
  });
104387
105006
 
104388
105007
  // packages/host-ui/src/pi/layout/campUiResources.ts
104389
- import { getSelectListTheme as getSelectListTheme11 } from "@earendil-works/pi-coding-agent";
105008
+ import { getSelectListTheme as getSelectListTheme13 } from "@earendil-works/pi-coding-agent";
104390
105009
  var renderResourceTree = (label, value5, tone, width) => {
104391
- const theme = getSelectListTheme11();
105010
+ const theme = getSelectListTheme13();
104392
105011
  const lines3 = [
104393
105012
  theme.description(label),
104394
105013
  `${theme.description("\u2514\u2500")} ${renderCampUiStatus(value5, tone)}`
@@ -104396,6 +105015,7 @@ var renderResourceTree = (label, value5, tone, width) => {
104396
105015
  return lines3.map((line) => fitCampUiLine(line, width));
104397
105016
  };
104398
105017
  var makeCampUiResources = (context8) => ({
105018
+ preferredRows: () => 10,
104399
105019
  render: (viewport) => {
104400
105020
  const model = context8.readModel();
104401
105021
  const snapshot = model.snapshot;
@@ -104406,8 +105026,8 @@ var makeCampUiResources = (context8) => ({
104406
105026
  const partial4 = !inventory.complete;
104407
105027
  const resourceText = (items) => {
104408
105028
  if (!resourcesReported) return "not reported";
104409
- const names = uniqueCampUiNames(items.map((item) => item.name));
104410
- const value5 = names.length === 0 ? "none loaded" : names.join(", ");
105029
+ const names2 = uniqueCampUiNames(items.map((item) => item.name));
105030
+ const value5 = names2.length === 0 ? "none loaded" : names2.join(", ");
104411
105031
  return partial4 ? `${value5} \xB7 partial` : value5;
104412
105032
  };
104413
105033
  const mcpNames = uniqueCampUiNames(equipment.flatMap((item) => item.mcp.serverNames));
@@ -104429,27 +105049,29 @@ var makeCampUiResources = (context8) => ({
104429
105049
  ...missingMcpHealth ? ["health not reported"] : []
104430
105050
  ];
104431
105051
  const mcpText = !equipmentReported ? "not reported" : mcpNames.length === 0 ? "none configured" : `${mcpNames.join(", ")}${mcpNotes.length === 0 ? "" : ` \xB7 ${mcpNotes.join(", ")}`}`;
104432
- return [
105052
+ const contentWidth = Math.max(1, viewport.width - 2);
105053
+ const body = [
104433
105054
  ...renderResourceTree(
104434
105055
  "Context",
104435
105056
  resourceText(inventory.contextFiles),
104436
105057
  inventory.contextFiles.length > 0 ? CampUiTone.success : CampUiTone.neutral,
104437
- viewport.width
105058
+ contentWidth
104438
105059
  ),
104439
105060
  ...renderResourceTree(
104440
105061
  "Extensions",
104441
105062
  resourceText(inventory.extensions),
104442
105063
  inventory.extensions.length > 0 ? CampUiTone.success : CampUiTone.neutral,
104443
- viewport.width
105064
+ contentWidth
104444
105065
  ),
104445
105066
  ...renderResourceTree(
104446
105067
  "Skills",
104447
105068
  resourceText(inventory.skills),
104448
105069
  inventory.skills.length > 0 ? CampUiTone.success : CampUiTone.neutral,
104449
- viewport.width
105070
+ contentWidth
104450
105071
  ),
104451
- ...renderResourceTree("MCP", mcpText, mcpTone, viewport.width)
105072
+ ...renderResourceTree("MCP", mcpText, mcpTone, contentWidth)
104452
105073
  ];
105074
+ return renderCampUiPanel("Camp inventory \xB7 Esc to close", body, viewport.width);
104453
105075
  }
104454
105076
  });
104455
105077
 
@@ -104461,14 +105083,14 @@ var makeDefaultCampUiContributions = (tui, detailBlocks) => [
104461
105083
  mount: (context8) => succeed8(makeCampUiCampHeader(context8))
104462
105084
  },
104463
105085
  {
104464
- id: "default-seat",
104465
- slotId: CampUiSlot.seat,
104466
- mount: (context8) => succeed8(makeCampUiSeat(context8))
105086
+ id: "default-activity",
105087
+ slotId: CampUiSlot.activity,
105088
+ mount: (context8) => succeed8(makeCampUiActivity(context8))
104467
105089
  },
104468
105090
  {
104469
- id: "default-resources",
104470
- slotId: CampUiSlot.resources,
104471
- mount: (context8) => succeed8(makeCampUiResources(context8))
105091
+ id: "default-equipment",
105092
+ slotId: CampUiSlot.equipment,
105093
+ mount: (context8) => succeed8(makeCampUiEquipment(context8))
104472
105094
  },
104473
105095
  {
104474
105096
  id: "default-roster",
@@ -104491,29 +105113,29 @@ var makeDefaultCampUiContributions = (tui, detailBlocks) => [
104491
105113
  mount: (context8) => succeed8(makeCampUiComposerComponent(context8, tui))
104492
105114
  },
104493
105115
  {
104494
- id: "default-camp-footer",
104495
- slotId: CampUiSlot.campFooter,
104496
- mount: (context8) => succeed8(makeCampUiCampFooter(context8))
105116
+ id: "default-footer",
105117
+ slotId: CampUiSlot.footer,
105118
+ mount: (context8) => succeed8(makeCampUiFooter(context8))
104497
105119
  },
104498
105120
  {
104499
- id: "default-session-footer",
104500
- slotId: CampUiSlot.sessionFooter,
104501
- mount: (context8) => succeed8(makeCampUiSessionFooter(context8))
105121
+ id: "default-inventory-overlay",
105122
+ slotId: CampUiSlot.overlay,
105123
+ mount: (context8) => succeed8(makeCampUiResources(context8))
104502
105124
  }
104503
105125
  ];
104504
105126
 
104505
105127
  // packages/host-ui/src/pi/layout/campUiSection.ts
104506
- import { getMarkdownTheme as getMarkdownTheme9, getSelectListTheme as getSelectListTheme12 } from "@earendil-works/pi-coding-agent";
104507
- import { visibleWidth as visibleWidth3 } from "@earendil-works/pi-tui";
105128
+ import { getMarkdownTheme as getMarkdownTheme8, getSelectListTheme as getSelectListTheme14 } from "@earendil-works/pi-coding-agent";
105129
+ import { visibleWidth as visibleWidth6 } from "@earendil-works/pi-tui";
104508
105130
  var renderHeader = (header, width) => {
104509
- const theme = getMarkdownTheme9();
104510
- const selectTheme = getSelectListTheme12();
105131
+ const theme = getMarkdownTheme8();
105132
+ const selectTheme = getSelectListTheme14();
104511
105133
  const rule2 = header.focused === true ? selectTheme.selectedPrefix : theme.codeBlockBorder;
104512
105134
  const title = header.focused === true ? selectTheme.selectedText : theme.heading;
104513
105135
  const ruleCharacter = header.focused === true ? "\u2501" : "\u2500";
104514
105136
  const detail = header.detail === void 0 ? "" : ` ${selectTheme.description(header.detail)}`;
104515
105137
  const label = `${rule2(ruleCharacter.repeat(2))} ${title(header.title)}${detail} `;
104516
- const ruleWidth = Math.max(0, width - visibleWidth3(label));
105138
+ const ruleWidth = Math.max(0, width - visibleWidth6(label));
104517
105139
  return fitCampUiLine(`${label}${rule2(ruleCharacter.repeat(ruleWidth))}`, width);
104518
105140
  };
104519
105141
  var makeCampUiSection = (options2) => {
@@ -104525,6 +105147,7 @@ var makeCampUiSection = (options2) => {
104525
105147
  const disposableComponents = components.some((component) => component.dispose !== void 0);
104526
105148
  return {
104527
105149
  sectionSize: options2.size,
105150
+ ...options2.preferredRows === void 0 ? {} : { preferredRows: options2.preferredRows },
104528
105151
  ...components.some((component) => component.focusable === true) ? { focusable: true } : {},
104529
105152
  render: (viewport) => {
104530
105153
  if (viewport.height <= 0) {
@@ -104590,28 +105213,38 @@ var decorateDefaultCampUiSections = (context8, slots) => {
104590
105213
  {
104591
105214
  component: component(CampUiSlot.campHeader),
104592
105215
  size: { kind: CampUiSectionSizeKind.fixed, rows: 2 }
104593
- },
104594
- {
104595
- component: component(CampUiSlot.seat),
104596
- size: { kind: CampUiSectionSizeKind.grow, weight: 1, minimumRows: 1 }
104597
105216
  }
104598
105217
  ]
104599
105218
  })
104600
105219
  );
104601
- decorated.delete(CampUiSlot.seat);
104602
105220
  decorated.set(
104603
- CampUiSlot.resources,
105221
+ CampUiSlot.activity,
104604
105222
  makeCampUiSection({
104605
- header: () => ({ title: "Resources" }),
104606
- size: defaultCampUiLeftSectionSizes.resources,
105223
+ header: () => ({ title: "Activity" }),
105224
+ size: defaultCampUiRightSectionSizes.activity,
104607
105225
  children: [
104608
105226
  {
104609
- component: component(CampUiSlot.resources),
105227
+ component: component(CampUiSlot.activity),
104610
105228
  size: { kind: CampUiSectionSizeKind.grow, weight: 1 }
104611
105229
  }
104612
105230
  ]
104613
105231
  })
104614
105232
  );
105233
+ const equipment = component(CampUiSlot.equipment);
105234
+ decorated.set(
105235
+ CampUiSlot.equipment,
105236
+ makeCampUiSection({
105237
+ header: () => ({ title: "Equipment" }),
105238
+ size: defaultCampUiRightSectionSizes.equipment,
105239
+ children: [
105240
+ {
105241
+ component: equipment,
105242
+ size: { kind: CampUiSectionSizeKind.grow, weight: 1 }
105243
+ }
105244
+ ],
105245
+ preferredRows: (width) => 1 + (equipment.preferredRows?.(width) ?? defaultCampUiRightSectionSizes.equipment.rows - 1)
105246
+ })
105247
+ );
104615
105248
  decorated.set(
104616
105249
  CampUiSlot.roster,
104617
105250
  makeCampUiSection({
@@ -104637,7 +105270,7 @@ import { initTheme } from "@earendil-works/pi-coding-agent";
104637
105270
  import { ProcessTerminal, TUI } from "@earendil-works/pi-tui";
104638
105271
 
104639
105272
  // packages/host-ui/src/pi/piCampUiRoot.ts
104640
- import { getMarkdownTheme as getMarkdownTheme10 } from "@earendil-works/pi-coding-agent";
105273
+ import { getMarkdownTheme as getMarkdownTheme9 } from "@earendil-works/pi-coding-agent";
104641
105274
  import { Key as Key4, matchesKey as matchesKey3 } from "@earendil-works/pi-tui";
104642
105275
 
104643
105276
  // packages/host-ui/src/pi/runtime/campUiPointerInput.ts
@@ -104766,7 +105399,7 @@ var PiCampUiRoot = class {
104766
105399
  segments.push({
104767
105400
  x: divider.x,
104768
105401
  width: 1,
104769
- text: getMarkdownTheme10().codeBlockBorder("\u2502")
105402
+ text: getMarkdownTheme9().codeBlockBorder("\u2502")
104770
105403
  });
104771
105404
  }
104772
105405
  }
@@ -104813,6 +105446,14 @@ var PiCampUiRoot = class {
104813
105446
  if (focusedSlotId !== model.state.focusedSlotId) {
104814
105447
  this.context.emit(CampUiIntents.FocusSlot({ slotId: focusedSlotId }));
104815
105448
  }
105449
+ if (model.state.inventoryVisible && matchesKey3(input, Key4.escape)) {
105450
+ this.context.emit(CampUiIntents.SetInventoryVisible({ visible: false }));
105451
+ return;
105452
+ }
105453
+ if (focusedSlotId !== CampUiSlot.composer && input === "i") {
105454
+ this.context.emit(CampUiIntents.SetInventoryVisible({ visible: true }));
105455
+ return;
105456
+ }
104816
105457
  if (this.slots.get(focusedSlotId)?.handleInput?.(input) === true) return;
104817
105458
  if (matchesKey3(input, Key4.escape)) {
104818
105459
  if (focusedSlotId === CampUiSlot.composer) {
@@ -104898,19 +105539,67 @@ var PiCampUiRoot = class {
104898
105539
  }
104899
105540
  };
104900
105541
 
105542
+ // packages/host-ui/src/pi/runtime/campUiFrameScheduler.ts
105543
+ var DEFAULT_MINIMUM_INTERVAL_MS = 1e3;
105544
+ var DEFAULT_MAXIMUM_INTERVAL_MS = 8e3;
105545
+ var DEFAULT_EXPENSIVE_FRAME_MS = 120;
105546
+ var CAMP_UI_REDUCED_MOTION_ENV = "PRIIISK_REDUCED_MOTION";
105547
+ var campUiReducedMotionFromEnv = (environment2) => {
105548
+ const value5 = environment2[CAMP_UI_REDUCED_MOTION_ENV]?.trim().toLowerCase();
105549
+ return value5 !== void 0 && value5 !== "" && value5 !== "0" && value5 !== "false";
105550
+ };
105551
+ var makeCampUiFrameScheduler = (options2 = {}) => gen2(function* () {
105552
+ const minimum = Math.max(
105553
+ 1,
105554
+ Math.floor(options2.minimumIntervalMs ?? DEFAULT_MINIMUM_INTERVAL_MS)
105555
+ );
105556
+ const maximum = Math.max(
105557
+ minimum,
105558
+ Math.floor(options2.maximumIntervalMs ?? DEFAULT_MAXIMUM_INTERVAL_MS)
105559
+ );
105560
+ const expensive = Math.max(
105561
+ 1,
105562
+ Math.floor(options2.expensiveFrameMs ?? DEFAULT_EXPENSIVE_FRAME_MS)
105563
+ );
105564
+ const reducedMotion = options2.reducedMotion === true;
105565
+ const pending3 = yield* make25(false);
105566
+ const interval = yield* make25(minimum);
105567
+ return {
105568
+ request: reducedMotion ? _void : set5(pending3, true),
105569
+ intervalMs: get11(interval),
105570
+ run: (frame) => reducedMotion ? never3 : forever3(
105571
+ gen2(function* () {
105572
+ yield* sleep4(millis(yield* get11(interval)));
105573
+ const requested = yield* getAndSet2(pending3, false);
105574
+ if (!requested) return;
105575
+ const startedAt = yield* currentTimeMillis2;
105576
+ yield* frame;
105577
+ const cost = (yield* currentTimeMillis2) - startedAt;
105578
+ yield* update3(
105579
+ interval,
105580
+ (current2) => cost > expensive ? Math.min(maximum, current2 * 2) : Math.max(minimum, Math.floor(current2 / 2))
105581
+ );
105582
+ })
105583
+ )
105584
+ };
105585
+ });
105586
+
104901
105587
  // packages/host-ui/src/pi/runtime/campUiPresentationClock.ts
104902
105588
  var hasPendingCampUiAsk = (model) => model.snapshot.workers.some(
104903
105589
  (worker) => worker.asks.some((ask) => ask.state === CampAskState.pending)
104904
105590
  );
104905
- var runCampUiPresentationClock = (readModel, controller) => forever3(
104906
- sleep4("1 second").pipe(
104907
- zipRight3(
104908
- suspend4(
104909
- () => hasPendingCampUiAsk(readModel()) ? currentTimeMillis2.pipe(flatMap10(controller.setPresentationNow)) : _void
104910
- )
104911
- )
104912
- )
104913
- );
105591
+ var runCampUiPresentationClock = (readModel, controller, scheduler2) => gen2(function* () {
105592
+ const frames = scheduler2 ?? (yield* makeCampUiFrameScheduler({
105593
+ reducedMotion: campUiReducedMotionFromEnv(process.env)
105594
+ }));
105595
+ const advance = suspend4(
105596
+ () => hasPendingCampUiAsk(readModel()) ? currentTimeMillis2.pipe(flatMap10(controller.setPresentationNow)) : _void
105597
+ );
105598
+ return yield* zipRight3(
105599
+ frames.request,
105600
+ frames.run(zipRight3(advance, frames.request))
105601
+ );
105602
+ });
104914
105603
 
104915
105604
  // packages/host-ui/src/pi/runtime/campUiSubscriptionRetry.ts
104916
105605
  var CAMP_UI_SUBSCRIPTION_MAX_RETRIES = 4;
@@ -105028,6 +105717,22 @@ var mountPiCampUi = (options2) => gen2(function* () {
105028
105717
  );
105029
105718
  tui.addChild(root);
105030
105719
  tui.setFocus(root);
105720
+ const inventory = slots.get(CampUiSlot.overlay);
105721
+ const inventoryOverlay = inventory === void 0 ? void 0 : tui.showOverlay(
105722
+ {
105723
+ render: (width) => [
105724
+ ...inventory.render({ width, height: Math.max(0, terminal.rows) })
105725
+ ],
105726
+ invalidate: () => inventory.invalidate?.()
105727
+ },
105728
+ {
105729
+ width: "60%",
105730
+ minWidth: 36,
105731
+ margin: 1,
105732
+ visible: () => current2.state.inventoryVisible,
105733
+ nonCapturing: true
105734
+ }
105735
+ );
105031
105736
  yield* sync4(() => {
105032
105737
  terminal.setTitle(initial.displayName);
105033
105738
  terminal.clearScreen();
@@ -105044,6 +105749,9 @@ var mountPiCampUi = (options2) => gen2(function* () {
105044
105749
  )
105045
105750
  )
105046
105751
  );
105752
+ if (inventoryOverlay !== void 0) {
105753
+ yield* addFinalizer3(() => sync4(() => inventoryOverlay.hide()));
105754
+ }
105047
105755
  yield* forkScoped2(
105048
105756
  gen2(function* () {
105049
105757
  for (let attempt = 0; attempt < 25; attempt += 1) {
@@ -105121,7 +105829,7 @@ var mountPiCampUi = (options2) => gen2(function* () {
105121
105829
  });
105122
105830
 
105123
105831
  // packages/host-ui/src/pi/run-selector/campRunSelector.ts
105124
- import { getMarkdownTheme as getMarkdownTheme11, getSelectListTheme as getSelectListTheme13, initTheme as initTheme2 } from "@earendil-works/pi-coding-agent";
105832
+ import { getMarkdownTheme as getMarkdownTheme10, getSelectListTheme as getSelectListTheme15, initTheme as initTheme2 } from "@earendil-works/pi-coding-agent";
105125
105833
  import {
105126
105834
  Key as Key5,
105127
105835
  matchesKey as matchesKey4,
@@ -105208,6 +105916,7 @@ var makeHostCampUiSnapshot = (options2, revision, activityRevisions) => gen2(fun
105208
105916
  return {
105209
105917
  displayName: `priiisk-camp-${options2.project.name.replaceAll(/[^a-zA-Z0-9_-]+/gu, "-")}-${options2.project.hash.slice(0, 5)}`,
105210
105918
  projectScope: options2.project.cwd,
105919
+ hostVersion: PRIIISK_HOST_VERSION,
105211
105920
  generation: options2.runtime.generation,
105212
105921
  revision: nextRevision,
105213
105922
  placement: options2.placement ?? CampUiPlacement.external,