priiisk 0.1.23 → 0.1.24

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.
@@ -23,7 +23,7 @@ import {
23
23
  resolveCampSurface,
24
24
  saveCampManifest,
25
25
  startingCampManifest
26
- } from "./chunk-ECYZGNL3.js";
26
+ } from "./chunk-FUL25M5E.js";
27
27
  import {
28
28
  get as get4,
29
29
  make as make10,
@@ -106,7 +106,7 @@ import {
106
106
  vsep,
107
107
  weak,
108
108
  white
109
- } from "./chunk-HRCEXDLT.js";
109
+ } from "./chunk-42AGXKI6.js";
110
110
  import {
111
111
  CampCommandFailure,
112
112
  CampHostReadiness,
@@ -127,10 +127,10 @@ import {
127
127
  withCampRpc,
128
128
  withCampRpcSession,
129
129
  withConsole
130
- } from "./chunk-G3ITCVKS.js";
130
+ } from "./chunk-ZIIUZJRV.js";
131
131
  import {
132
132
  PRIIISK_CLI_VERSION
133
- } from "./chunk-HOYW7OPN.js";
133
+ } from "./chunk-SZWJI5KL.js";
134
134
  import {
135
135
  BadArgument,
136
136
  BaseProto,
@@ -19260,7 +19260,7 @@ var campResumeListCommand = Command_exports2.make(
19260
19260
  )
19261
19261
  ).pipe(Command_exports2.withDescription("Lists saved runs of this project that resume can restore."));
19262
19262
  var runIdArgument = Args_exports.text({ name: "runId" }).pipe(Args_exports.optional);
19263
- var selectCampRunOnDemand = (items) => promise(() => import("./chunk-J77LDB4Q.js")).pipe(
19263
+ var selectCampRunOnDemand = (items) => promise(() => import("./chunk-Z22GSS46.js")).pipe(
19264
19264
  flatMap3((ui) => ui.selectCampRun({ items }))
19265
19265
  );
19266
19266
  var selectAndResume = (json) => {
@@ -19333,7 +19333,7 @@ var rootCommand = Command_exports2.make(
19333
19333
  ).pipe(Command_exports2.withDescription("Runs and observes a camp of collaborating workers."));
19334
19334
 
19335
19335
  // packages/cli/src/commands/doctorCommand.ts
19336
- var runDoctorOnDemand = promise(() => import("./chunk-QO2YENTD.js")).pipe(
19336
+ var runDoctorOnDemand = promise(() => import("./chunk-AHGQRHTS.js")).pipe(
19337
19337
  flatMap3((doctor) => doctor.runDoctor)
19338
19338
  );
19339
19339
  var statusLabel = {
@@ -20062,7 +20062,7 @@ var stdioCommand = Command_exports2.make("stdio", { consumer: consumerOption3 },
20062
20062
  );
20063
20063
  var mcpCommand = Command_exports2.make("mcp", { consumer: consumerOption3 }, ({ consumer }) => {
20064
20064
  const consumerId = getOrUndefined(consumer);
20065
- return promise(() => import("./chunk-MJZ7FPJI.js")).pipe(
20065
+ return promise(() => import("./chunk-5SZUTATM.js")).pipe(
20066
20066
  flatMap3(
20067
20067
  (adapter) => adapter.runCampMcpSession(
20068
20068
  (argumentsList) => runCliCommand([process.execPath, "priiisk", ...argumentsList]),
@@ -20102,7 +20102,7 @@ var command = rootCommand.pipe(
20102
20102
  );
20103
20103
  var cli = Command_exports2.run(command, {
20104
20104
  name: "priiisk camp control",
20105
- version: "0.1.23"
20105
+ version: "0.1.24"
20106
20106
  });
20107
20107
  var quietDiagnostics = (json, effect2) => json ? consoleWith(
20108
20108
  (console2) => withConsole({ ...console2, error: () => _void })(effect2)
@@ -5,7 +5,7 @@ import {
5
5
  TypeId,
6
6
  error,
7
7
  log
8
- } from "./chunk-G3ITCVKS.js";
8
+ } from "./chunk-ZIIUZJRV.js";
9
9
  import {
10
10
  _void,
11
11
  cached,
@@ -3,14 +3,14 @@ const require = __priiiskCreateRequire(import.meta.url);
3
3
  import {
4
4
  errorPayload,
5
5
  makeCapturedConsole
6
- } from "./chunk-HRCEXDLT.js";
6
+ } from "./chunk-42AGXKI6.js";
7
7
  import {
8
8
  withCampRpcSession,
9
9
  withConsole
10
- } from "./chunk-G3ITCVKS.js";
10
+ } from "./chunk-ZIIUZJRV.js";
11
11
  import {
12
12
  PRIIISK_CLI_VERSION
13
- } from "./chunk-HOYW7OPN.js";
13
+ } from "./chunk-SZWJI5KL.js";
14
14
  import {
15
15
  _await2 as _await,
16
16
  addFinalizer2 as addFinalizer,
@@ -21,7 +21,7 @@ import {
21
21
  loadCampManifest,
22
22
  makeDoctorReport,
23
23
  resolveCampSurface
24
- } from "./chunk-ECYZGNL3.js";
24
+ } from "./chunk-FUL25M5E.js";
25
25
  import {
26
26
  CampSessionError,
27
27
  CampTurnStopReason
@@ -33,8 +33,8 @@ import {
33
33
  PRIIISK_PROTOCOL_PACKAGE_VERSION,
34
34
  PRIIISK_PROTOCOL_VERSION,
35
35
  withCampRpc
36
- } from "./chunk-G3ITCVKS.js";
37
- import "./chunk-HOYW7OPN.js";
36
+ } from "./chunk-ZIIUZJRV.js";
37
+ import "./chunk-SZWJI5KL.js";
38
38
  import {
39
39
  DirectToolSandboxKind,
40
40
  FileSystem_exports,
@@ -10,7 +10,7 @@ import {
10
10
  CampHealthComponentStatus,
11
11
  CampHealthSnapshotSchema,
12
12
  CliSurfaceSelectionError
13
- } from "./chunk-G3ITCVKS.js";
13
+ } from "./chunk-ZIIUZJRV.js";
14
14
  import {
15
15
  Array$,
16
16
  Boolean$,
@@ -135,7 +135,7 @@ var makeDoctorReport = (checks, checkedAt, projectHash) => ({
135
135
  var doctorErrorMessage = (cause) => (cause instanceof Error ? cause.message : String(cause)).slice(-2048);
136
136
 
137
137
  // packages/camp-state/src/bootstrap/campHostVersion.ts
138
- var PRIIISK_HOST_VERSION = "0.1.23";
138
+ var PRIIISK_HOST_VERSION = "0.1.24";
139
139
 
140
140
  // packages/surface/src/domain/surfaceModel.ts
141
141
  var NonEmptyString = String$.pipe(minLength(1));
@@ -2,7 +2,7 @@ import { createRequire as __priiiskCreateRequire } from "node:module";
2
2
  const require = __priiiskCreateRequire(import.meta.url);
3
3
 
4
4
  // packages/cli/src/domain/cliVersion.ts
5
- var PRIIISK_CLI_VERSION = "0.1.23";
5
+ var PRIIISK_CLI_VERSION = "0.1.24";
6
6
 
7
7
  export {
8
8
  PRIIISK_CLI_VERSION
@@ -27,7 +27,6 @@ import {
27
27
  flatMap3 as flatMap,
28
28
  forEach,
29
29
  forever,
30
- forkScoped,
31
30
  gen,
32
31
  get4 as get,
33
32
  getAndSet,
@@ -299,6 +298,15 @@ var makeCampUiComponentGroup = (components) => {
299
298
  return [];
300
299
  }
301
300
  } : {},
301
+ ...components.some((component) => component.lowestVisibleBlockId !== void 0) ? {
302
+ lowestVisibleBlockId: () => {
303
+ for (const component of [...components].reverse()) {
304
+ const blockId = component.lowestVisibleBlockId?.();
305
+ if (blockId !== void 0) return blockId;
306
+ }
307
+ return void 0;
308
+ }
309
+ } : {},
302
310
  ...invalidatingComponents ? {
303
311
  invalidate: () => {
304
312
  for (const component of components) component.invalidate?.();
@@ -1793,6 +1801,11 @@ var defaultCampUiDetailBlockRenderers = [
1793
1801
  campUiPendingAskBlockRenderer
1794
1802
  ];
1795
1803
  var sameCampUiDetailBlockSet = (left, right) => left.size === right.size && [...left].every((blockId) => right.has(blockId));
1804
+ var campUiScrollTarget = (stored, maximumOffset, delta) => {
1805
+ const visible = Math.min(stored, maximumOffset);
1806
+ const target = Math.min(maximumOffset, Math.max(0, visible + delta));
1807
+ return target === visible ? void 0 : target;
1808
+ };
1796
1809
  var makeCampUiDetailComponent = (context, registry = defaultCampUiDetailBlockRenderers) => {
1797
1810
  const renderState = /* @__PURE__ */ new Map();
1798
1811
  const detailCache = /* @__PURE__ */ new Map();
@@ -1848,17 +1861,20 @@ var makeCampUiDetailComponent = (context, registry = defaultCampUiDetailBlockRen
1848
1861
  previous.expandedDetailBlockIds,
1849
1862
  model.state.expandedDetailBlockIds
1850
1863
  ) ? Math.max(0, lines.length - previous.lineCount) : 0;
1851
- const focusedOffset = focusedRange === void 0 ? void 0 : Math.max(
1864
+ const maximumOffset = Math.max(0, lines.length - viewport.height);
1865
+ maximumScrollOffset = maximumOffset;
1866
+ const readerOffset = offset > 0 ? offset + growth : 0;
1867
+ const readerEnd = Math.max(0, lines.length - Math.min(maximumOffset, readerOffset));
1868
+ const readerStart = Math.max(0, readerEnd - viewport.height);
1869
+ const focusedOffset = focusedRange === void 0 || focusedLine !== void 0 && focusedLine >= readerStart && focusedLine < readerEnd ? void 0 : Math.max(
1852
1870
  0,
1853
1871
  lines.length - Math.min(lines.length, focusedRange.start + viewport.height)
1854
1872
  );
1855
- const maximumOffset = Math.max(0, lines.length - viewport.height);
1856
- maximumScrollOffset = maximumOffset;
1857
- const desiredOffset = focusedOffset ?? (offset > 0 ? offset + growth : 0);
1858
- const lockedOffset = Math.min(maximumOffset, desiredOffset);
1859
- if (lockedOffset !== offset) {
1860
- context.emit(CampUiIntents.SetScrollOffset({ workerId, offset: lockedOffset }));
1873
+ const desiredOffset = focusedOffset ?? readerOffset;
1874
+ if (desiredOffset !== offset) {
1875
+ context.emit(CampUiIntents.SetScrollOffset({ workerId, offset: desiredOffset }));
1861
1876
  }
1877
+ const lockedOffset = Math.min(maximumOffset, desiredOffset);
1862
1878
  renderState.set(workerId, {
1863
1879
  width: viewport.width,
1864
1880
  lineCount: lines.length,
@@ -1875,12 +1891,13 @@ var makeCampUiDetailComponent = (context, registry = defaultCampUiDetailBlockRen
1875
1891
  return lines.slice(start, end);
1876
1892
  },
1877
1893
  /*
1878
- * An arrow first moves the selection between expandable blocks, and then
1879
- * keeps reading: past the last block it scrolls a line at a time, so a long
1880
- * history is reachable to its first message. Handing focus away at the last
1881
- * block left the transcript stuck wherever the blocks happened to end
1882
- * (priiisk-nss.6.41). Only the end of the content passes the arrow on to
1883
- * spatial navigation.
1894
+ * Reading and working with blocks are two different things, and the arrow
1895
+ * belongs to reading. While no block is focused an arrow scrolls a line, the
1896
+ * same as the wheel which matters beyond taste: DEC alternate-scroll sends
1897
+ * the wheel as those very bytes, so a transcript where the arrow meant
1898
+ * something else could only accept the wheel from terminals that speak the
1899
+ * kitty protocol. Block selection is entered explicitly (Enter) and left
1900
+ * explicitly (Esc); inside it the arrow walks blocks (priiisk-uhb).
1884
1901
  */
1885
1902
  handleInput: (input) => {
1886
1903
  const delta = matchesKey2(input, Key2.up) ? -1 : matchesKey2(input, Key2.down) ? 1 : void 0;
@@ -1888,30 +1905,38 @@ var makeCampUiDetailComponent = (context, registry = defaultCampUiDetailBlockRen
1888
1905
  const model = context.readModel();
1889
1906
  const workerId = campUiOpenedWorkerId(model.state);
1890
1907
  if (workerId === void 0) return false;
1891
- const focusedBlockId = model.state.focusedDetailBlockId;
1892
- const current = renderedRanges.findIndex((range) => range.id === focusedBlockId);
1893
- const next = current < 0 ? delta < 0 ? renderedRanges.length - 1 : 0 : current + delta;
1894
- const target = renderedRanges[next];
1895
- if (target !== void 0) {
1896
- context.emit(CampUiIntents.FocusDetailBlock({ blockId: target.id }));
1897
- return true;
1908
+ const current = renderedRanges.findIndex(
1909
+ (range) => range.id === model.state.focusedDetailBlockId
1910
+ );
1911
+ if (current >= 0) {
1912
+ const target = renderedRanges[current + delta];
1913
+ if (target !== void 0) {
1914
+ context.emit(CampUiIntents.FocusDetailBlock({ blockId: target.id }));
1915
+ return true;
1916
+ }
1898
1917
  }
1899
- const offset = model.state.scrollOffsets.get(workerId) ?? 0;
1900
- const scrolled = delta < 0 ? offset + 1 : offset - 1;
1901
- if (scrolled < 0 || scrolled > maximumScrollOffset) return false;
1902
- context.emit(CampUiIntents.ScrollWorker({ workerId, delta: delta < 0 ? 1 : -1 }));
1918
+ const stored = model.state.scrollOffsets.get(workerId) ?? 0;
1919
+ const scrolled = campUiScrollTarget(stored, maximumScrollOffset, delta < 0 ? 1 : -1);
1920
+ if (scrolled === void 0) return false;
1921
+ context.emit(CampUiIntents.ScrollWorker({ workerId, delta: scrolled - stored }));
1903
1922
  return true;
1904
1923
  },
1924
+ /**
1925
+ * The block on screen the reader would reach first, used when entering block
1926
+ * selection: the mode starts where the eye already is instead of rewinding
1927
+ * the history to either end.
1928
+ */
1929
+ lowestVisibleBlockId: () => visibleRanges.at(-1)?.blockId,
1905
1930
  handlePointer: (pointer) => {
1906
1931
  const workerId = campUiOpenedWorkerId(context.readModel().state);
1907
1932
  if (workerId === void 0) return [];
1908
1933
  if (pointer.action === "wheel") {
1934
+ const stored = context.readModel().state.scrollOffsets.get(workerId) ?? 0;
1935
+ const wheelDelta = pointer.direction === "up" ? 3 : -3;
1936
+ const target2 = campUiScrollTarget(stored, maximumScrollOffset, wheelDelta) ?? Math.min(stored, maximumScrollOffset);
1909
1937
  return [
1910
1938
  CampUiIntents.FocusSlot({ slotId: CampUiSlot.transcript }),
1911
- CampUiIntents.ScrollWorker({
1912
- workerId,
1913
- delta: pointer.direction === "up" ? 3 : -3
1914
- })
1939
+ CampUiIntents.ScrollWorker({ workerId, delta: target2 - stored })
1915
1940
  ];
1916
1941
  }
1917
1942
  if (pointer.action !== "press" || pointer.button !== "left") return [];
@@ -2869,7 +2894,7 @@ var PiCampUiRoot = class {
2869
2894
  const wheelDirection = this.wheelDirectionFromInput?.(input);
2870
2895
  if (wheelDirection !== void 0) {
2871
2896
  const model2 = this.context.readModel();
2872
- const workerId2 = model2.state.selectedWorkerId;
2897
+ const workerId2 = campUiOpenedWorkerId(model2.state);
2873
2898
  const transcriptVisible = this.frame?.regions.some((region2) => region2.slotId === CampUiSlot.transcript) === true;
2874
2899
  if (workerId2 !== void 0 && transcriptVisible) {
2875
2900
  this.context.emit(
@@ -2893,6 +2918,10 @@ var PiCampUiRoot = class {
2893
2918
  this.context.emit(CampUiIntents.FocusSlot({ slotId: CampUiSlot.transcript }));
2894
2919
  return;
2895
2920
  }
2921
+ if (focusedSlotId === CampUiSlot.transcript && model.state.focusedDetailBlockId !== void 0) {
2922
+ this.context.emit(CampUiIntents.FocusDetailBlock({}));
2923
+ return;
2924
+ }
2896
2925
  if (model.state.openedWorkerId !== void 0) {
2897
2926
  this.context.emit(CampUiIntents.CloseWorker());
2898
2927
  this.context.emit(CampUiIntents.FocusDetailBlock({}));
@@ -2920,10 +2949,16 @@ var PiCampUiRoot = class {
2920
2949
  this.context.emit(CampUiIntents.NextPendingAsk());
2921
2950
  return;
2922
2951
  }
2923
- if (focusedSlotId === CampUiSlot.transcript && model.state.focusedDetailBlockId !== void 0 && matchesKey3(input, Key3.enter)) {
2924
- this.context.emit(
2925
- CampUiIntents.ToggleDetailBlock({ blockId: model.state.focusedDetailBlockId })
2926
- );
2952
+ if (focusedSlotId === CampUiSlot.transcript && matchesKey3(input, Key3.enter)) {
2953
+ const focusedBlockId = model.state.focusedDetailBlockId;
2954
+ if (focusedBlockId !== void 0) {
2955
+ this.context.emit(CampUiIntents.ToggleDetailBlock({ blockId: focusedBlockId }));
2956
+ return;
2957
+ }
2958
+ const entryBlockId = this.slots.get(CampUiSlot.transcript)?.lowestVisibleBlockId?.();
2959
+ if (entryBlockId !== void 0) {
2960
+ this.context.emit(CampUiIntents.FocusDetailBlock({ blockId: entryBlockId }));
2961
+ }
2927
2962
  return;
2928
2963
  }
2929
2964
  if (focusedSlotId === CampUiSlot.roster || focusedSlotId === CampUiSlot.equipment) {
@@ -2956,7 +2991,7 @@ var PiCampUiRoot = class {
2956
2991
  return;
2957
2992
  }
2958
2993
  }
2959
- const workerId = model.state.selectedWorkerId;
2994
+ const workerId = campUiOpenedWorkerId(model.state);
2960
2995
  if (focusedSlotId === CampUiSlot.transcript && workerId !== void 0 && matchesKey3(input, Key3.end)) {
2961
2996
  this.context.emit(CampUiIntents.JumpToWorkerTail({ workerId }));
2962
2997
  return;
@@ -2975,6 +3010,9 @@ var PiCampUiRoot = class {
2975
3010
  }
2976
3011
  const direction = focusDirectionFromInput(input);
2977
3012
  if (direction === void 0) return;
3013
+ if (focusedSlotId === CampUiSlot.transcript && (direction === CampUiFocusDirection.up || direction === CampUiFocusDirection.down)) {
3014
+ return;
3015
+ }
2978
3016
  const target = findCampUiSpatialFocusTarget(
2979
3017
  this.frame,
2980
3018
  focusedSlotId,
@@ -3084,12 +3122,12 @@ var makeCampUiTerminalModes = (terminal) => {
3084
3122
  alternateScreenActive = false;
3085
3123
  }
3086
3124
  },
3087
- tryEnableAlternateScroll: () => {
3088
- if (alternateScrollActive) return true;
3089
- if (!alternateScreenActive || !terminal.kittyProtocolActive) return false;
3090
- terminal.write(ENABLE_ALTERNATE_SCROLL);
3091
- alternateScrollActive = true;
3092
- return true;
3125
+ setAlternateScroll: (wanted) => {
3126
+ if (!alternateScreenActive) return;
3127
+ const active = wanted || terminal.kittyProtocolActive;
3128
+ if (active === alternateScrollActive) return;
3129
+ terminal.write(active ? ENABLE_ALTERNATE_SCROLL : DISABLE_ALTERNATE_SCROLL);
3130
+ alternateScrollActive = active;
3093
3131
  },
3094
3132
  wheelDirection: (input) => {
3095
3133
  if (!alternateScrollActive) return void 0;
@@ -3182,14 +3220,10 @@ var mountPiCampUi = (options) => gen(function* () {
3182
3220
  )
3183
3221
  )
3184
3222
  );
3185
- yield* forkScoped(
3186
- gen(function* () {
3187
- for (let attempt = 0; attempt < 25; attempt += 1) {
3188
- if (yield* sync(() => terminalModes.tryEnableAlternateScroll())) return;
3189
- yield* sleep("10 millis");
3190
- }
3191
- })
3192
- );
3223
+ const syncAlternateScroll = (model) => {
3224
+ terminalModes.setAlternateScroll(model.state.focusedSlotId === CampUiSlot.transcript);
3225
+ };
3226
+ yield* sync(() => syncAlternateScroll(current));
3193
3227
  const fibers = yield* make3();
3194
3228
  yield* run(
3195
3229
  fibers,
@@ -3197,6 +3231,7 @@ var mountPiCampUi = (options) => gen(function* () {
3197
3231
  runForEach(
3198
3232
  (model) => sync(() => {
3199
3233
  current = model;
3234
+ syncAlternateScroll(model);
3200
3235
  tui.requestRender();
3201
3236
  })
3202
3237
  )
@@ -2,7 +2,7 @@ import { createRequire as __priiiskCreateRequire } from "node:module";
2
2
  const require = __priiiskCreateRequire(import.meta.url);
3
3
  import {
4
4
  PRIIISK_CLI_VERSION
5
- } from "./chunk-HOYW7OPN.js";
5
+ } from "./chunk-SZWJI5KL.js";
6
6
  import {
7
7
  Array$,
8
8
  Boolean$,
@@ -5138,7 +5138,7 @@ var make11 = (...rpcs) => makeProto2({
5138
5138
 
5139
5139
  // packages/protocol/src/domain/protocolVersion.ts
5140
5140
  var PRIIISK_PROTOCOL_VERSION = "12";
5141
- var PRIIISK_PROTOCOL_PACKAGE_VERSION = "0.1.23";
5141
+ var PRIIISK_PROTOCOL_PACKAGE_VERSION = "0.1.24";
5142
5142
  var ProtocolVersionSchema = String$.pipe(minLength(1));
5143
5143
 
5144
5144
  // packages/protocol/src/domain/protocolIdentifiers.ts
@@ -82167,7 +82167,7 @@ var HOST_BOOTSTRAP_ENVIRONMENT_NAMES = [
82167
82167
  ];
82168
82168
 
82169
82169
  // packages/camp-state/src/bootstrap/campHostVersion.ts
82170
- var PRIIISK_HOST_VERSION = "0.1.23";
82170
+ var PRIIISK_HOST_VERSION = "0.1.24";
82171
82171
 
82172
82172
  // packages/camp-state/src/bootstrap/campLaunch.ts
82173
82173
  var CampBootstrapError = class extends TaggedError("CampBootstrapError") {
@@ -98106,7 +98106,7 @@ var Client = class extends Protocol2 {
98106
98106
  };
98107
98107
 
98108
98108
  // packages/mcp-backend/src/connections/clientIdentity.ts
98109
- var backendVersion = "0.1.23";
98109
+ var backendVersion = "0.1.24";
98110
98110
 
98111
98111
  // packages/mcp-backend/src/connections/mcpFailure.ts
98112
98112
  var McpFailure = class extends TaggedError("McpFailure") {
@@ -102865,6 +102865,15 @@ var makeCampUiComponentGroup = (components) => {
102865
102865
  return [];
102866
102866
  }
102867
102867
  } : {},
102868
+ ...components.some((component) => component.lowestVisibleBlockId !== void 0) ? {
102869
+ lowestVisibleBlockId: () => {
102870
+ for (const component of [...components].reverse()) {
102871
+ const blockId = component.lowestVisibleBlockId?.();
102872
+ if (blockId !== void 0) return blockId;
102873
+ }
102874
+ return void 0;
102875
+ }
102876
+ } : {},
102868
102877
  ...invalidatingComponents ? {
102869
102878
  invalidate: () => {
102870
102879
  for (const component of components) component.invalidate?.();
@@ -104337,6 +104346,11 @@ var defaultCampUiDetailBlockRenderers = [
104337
104346
  campUiPendingAskBlockRenderer
104338
104347
  ];
104339
104348
  var sameCampUiDetailBlockSet = (left3, right3) => left3.size === right3.size && [...left3].every((blockId) => right3.has(blockId));
104349
+ var campUiScrollTarget = (stored, maximumOffset, delta) => {
104350
+ const visible = Math.min(stored, maximumOffset);
104351
+ const target2 = Math.min(maximumOffset, Math.max(0, visible + delta));
104352
+ return target2 === visible ? void 0 : target2;
104353
+ };
104340
104354
  var makeCampUiDetailComponent = (context8, registry2 = defaultCampUiDetailBlockRenderers) => {
104341
104355
  const renderState = /* @__PURE__ */ new Map();
104342
104356
  const detailCache = /* @__PURE__ */ new Map();
@@ -104392,17 +104406,20 @@ var makeCampUiDetailComponent = (context8, registry2 = defaultCampUiDetailBlockR
104392
104406
  previous2.expandedDetailBlockIds,
104393
104407
  model.state.expandedDetailBlockIds
104394
104408
  ) ? Math.max(0, lines3.length - previous2.lineCount) : 0;
104395
- const focusedOffset = focusedRange === void 0 ? void 0 : Math.max(
104409
+ const maximumOffset = Math.max(0, lines3.length - viewport.height);
104410
+ maximumScrollOffset = maximumOffset;
104411
+ const readerOffset = offset > 0 ? offset + growth : 0;
104412
+ const readerEnd = Math.max(0, lines3.length - Math.min(maximumOffset, readerOffset));
104413
+ const readerStart = Math.max(0, readerEnd - viewport.height);
104414
+ const focusedOffset = focusedRange === void 0 || focusedLine !== void 0 && focusedLine >= readerStart && focusedLine < readerEnd ? void 0 : Math.max(
104396
104415
  0,
104397
104416
  lines3.length - Math.min(lines3.length, focusedRange.start + viewport.height)
104398
104417
  );
104399
- const maximumOffset = Math.max(0, lines3.length - viewport.height);
104400
- maximumScrollOffset = maximumOffset;
104401
- const desiredOffset = focusedOffset ?? (offset > 0 ? offset + growth : 0);
104402
- const lockedOffset = Math.min(maximumOffset, desiredOffset);
104403
- if (lockedOffset !== offset) {
104404
- context8.emit(CampUiIntents.SetScrollOffset({ workerId, offset: lockedOffset }));
104418
+ const desiredOffset = focusedOffset ?? readerOffset;
104419
+ if (desiredOffset !== offset) {
104420
+ context8.emit(CampUiIntents.SetScrollOffset({ workerId, offset: desiredOffset }));
104405
104421
  }
104422
+ const lockedOffset = Math.min(maximumOffset, desiredOffset);
104406
104423
  renderState.set(workerId, {
104407
104424
  width: viewport.width,
104408
104425
  lineCount: lines3.length,
@@ -104419,12 +104436,13 @@ var makeCampUiDetailComponent = (context8, registry2 = defaultCampUiDetailBlockR
104419
104436
  return lines3.slice(start5, end6);
104420
104437
  },
104421
104438
  /*
104422
- * An arrow first moves the selection between expandable blocks, and then
104423
- * keeps reading: past the last block it scrolls a line at a time, so a long
104424
- * history is reachable to its first message. Handing focus away at the last
104425
- * block left the transcript stuck wherever the blocks happened to end
104426
- * (priiisk-nss.6.41). Only the end of the content passes the arrow on to
104427
- * spatial navigation.
104439
+ * Reading and working with blocks are two different things, and the arrow
104440
+ * belongs to reading. While no block is focused an arrow scrolls a line, the
104441
+ * same as the wheel which matters beyond taste: DEC alternate-scroll sends
104442
+ * the wheel as those very bytes, so a transcript where the arrow meant
104443
+ * something else could only accept the wheel from terminals that speak the
104444
+ * kitty protocol. Block selection is entered explicitly (Enter) and left
104445
+ * explicitly (Esc); inside it the arrow walks blocks (priiisk-uhb).
104428
104446
  */
104429
104447
  handleInput: (input) => {
104430
104448
  const delta = matchesKey2(input, Key3.up) ? -1 : matchesKey2(input, Key3.down) ? 1 : void 0;
@@ -104432,30 +104450,38 @@ var makeCampUiDetailComponent = (context8, registry2 = defaultCampUiDetailBlockR
104432
104450
  const model = context8.readModel();
104433
104451
  const workerId = campUiOpenedWorkerId(model.state);
104434
104452
  if (workerId === void 0) return false;
104435
- const focusedBlockId = model.state.focusedDetailBlockId;
104436
- const current2 = renderedRanges.findIndex((range3) => range3.id === focusedBlockId);
104437
- const next3 = current2 < 0 ? delta < 0 ? renderedRanges.length - 1 : 0 : current2 + delta;
104438
- const target2 = renderedRanges[next3];
104439
- if (target2 !== void 0) {
104440
- context8.emit(CampUiIntents.FocusDetailBlock({ blockId: target2.id }));
104441
- return true;
104453
+ const current2 = renderedRanges.findIndex(
104454
+ (range3) => range3.id === model.state.focusedDetailBlockId
104455
+ );
104456
+ if (current2 >= 0) {
104457
+ const target2 = renderedRanges[current2 + delta];
104458
+ if (target2 !== void 0) {
104459
+ context8.emit(CampUiIntents.FocusDetailBlock({ blockId: target2.id }));
104460
+ return true;
104461
+ }
104442
104462
  }
104443
- const offset = model.state.scrollOffsets.get(workerId) ?? 0;
104444
- const scrolled = delta < 0 ? offset + 1 : offset - 1;
104445
- if (scrolled < 0 || scrolled > maximumScrollOffset) return false;
104446
- context8.emit(CampUiIntents.ScrollWorker({ workerId, delta: delta < 0 ? 1 : -1 }));
104463
+ const stored = model.state.scrollOffsets.get(workerId) ?? 0;
104464
+ const scrolled = campUiScrollTarget(stored, maximumScrollOffset, delta < 0 ? 1 : -1);
104465
+ if (scrolled === void 0) return false;
104466
+ context8.emit(CampUiIntents.ScrollWorker({ workerId, delta: scrolled - stored }));
104447
104467
  return true;
104448
104468
  },
104469
+ /**
104470
+ * The block on screen the reader would reach first, used when entering block
104471
+ * selection: the mode starts where the eye already is instead of rewinding
104472
+ * the history to either end.
104473
+ */
104474
+ lowestVisibleBlockId: () => visibleRanges.at(-1)?.blockId,
104449
104475
  handlePointer: (pointer) => {
104450
104476
  const workerId = campUiOpenedWorkerId(context8.readModel().state);
104451
104477
  if (workerId === void 0) return [];
104452
104478
  if (pointer.action === "wheel") {
104479
+ const stored = context8.readModel().state.scrollOffsets.get(workerId) ?? 0;
104480
+ const wheelDelta = pointer.direction === "up" ? 3 : -3;
104481
+ const target3 = campUiScrollTarget(stored, maximumScrollOffset, wheelDelta) ?? Math.min(stored, maximumScrollOffset);
104453
104482
  return [
104454
104483
  CampUiIntents.FocusSlot({ slotId: CampUiSlot.transcript }),
104455
- CampUiIntents.ScrollWorker({
104456
- workerId,
104457
- delta: pointer.direction === "up" ? 3 : -3
104458
- })
104484
+ CampUiIntents.ScrollWorker({ workerId, delta: target3 - stored })
104459
104485
  ];
104460
104486
  }
104461
104487
  if (pointer.action !== "press" || pointer.button !== "left") return [];
@@ -105413,7 +105439,7 @@ var PiCampUiRoot = class {
105413
105439
  const wheelDirection = this.wheelDirectionFromInput?.(input);
105414
105440
  if (wheelDirection !== void 0) {
105415
105441
  const model2 = this.context.readModel();
105416
- const workerId2 = model2.state.selectedWorkerId;
105442
+ const workerId2 = campUiOpenedWorkerId(model2.state);
105417
105443
  const transcriptVisible = this.frame?.regions.some((region2) => region2.slotId === CampUiSlot.transcript) === true;
105418
105444
  if (workerId2 !== void 0 && transcriptVisible) {
105419
105445
  this.context.emit(
@@ -105437,6 +105463,10 @@ var PiCampUiRoot = class {
105437
105463
  this.context.emit(CampUiIntents.FocusSlot({ slotId: CampUiSlot.transcript }));
105438
105464
  return;
105439
105465
  }
105466
+ if (focusedSlotId === CampUiSlot.transcript && model.state.focusedDetailBlockId !== void 0) {
105467
+ this.context.emit(CampUiIntents.FocusDetailBlock({}));
105468
+ return;
105469
+ }
105440
105470
  if (model.state.openedWorkerId !== void 0) {
105441
105471
  this.context.emit(CampUiIntents.CloseWorker());
105442
105472
  this.context.emit(CampUiIntents.FocusDetailBlock({}));
@@ -105464,10 +105494,16 @@ var PiCampUiRoot = class {
105464
105494
  this.context.emit(CampUiIntents.NextPendingAsk());
105465
105495
  return;
105466
105496
  }
105467
- if (focusedSlotId === CampUiSlot.transcript && model.state.focusedDetailBlockId !== void 0 && matchesKey3(input, Key4.enter)) {
105468
- this.context.emit(
105469
- CampUiIntents.ToggleDetailBlock({ blockId: model.state.focusedDetailBlockId })
105470
- );
105497
+ if (focusedSlotId === CampUiSlot.transcript && matchesKey3(input, Key4.enter)) {
105498
+ const focusedBlockId = model.state.focusedDetailBlockId;
105499
+ if (focusedBlockId !== void 0) {
105500
+ this.context.emit(CampUiIntents.ToggleDetailBlock({ blockId: focusedBlockId }));
105501
+ return;
105502
+ }
105503
+ const entryBlockId = this.slots.get(CampUiSlot.transcript)?.lowestVisibleBlockId?.();
105504
+ if (entryBlockId !== void 0) {
105505
+ this.context.emit(CampUiIntents.FocusDetailBlock({ blockId: entryBlockId }));
105506
+ }
105471
105507
  return;
105472
105508
  }
105473
105509
  if (focusedSlotId === CampUiSlot.roster || focusedSlotId === CampUiSlot.equipment) {
@@ -105500,7 +105536,7 @@ var PiCampUiRoot = class {
105500
105536
  return;
105501
105537
  }
105502
105538
  }
105503
- const workerId = model.state.selectedWorkerId;
105539
+ const workerId = campUiOpenedWorkerId(model.state);
105504
105540
  if (focusedSlotId === CampUiSlot.transcript && workerId !== void 0 && matchesKey3(input, Key4.end)) {
105505
105541
  this.context.emit(CampUiIntents.JumpToWorkerTail({ workerId }));
105506
105542
  return;
@@ -105519,6 +105555,9 @@ var PiCampUiRoot = class {
105519
105555
  }
105520
105556
  const direction = focusDirectionFromInput(input);
105521
105557
  if (direction === void 0) return;
105558
+ if (focusedSlotId === CampUiSlot.transcript && (direction === CampUiFocusDirection.up || direction === CampUiFocusDirection.down)) {
105559
+ return;
105560
+ }
105522
105561
  const target2 = findCampUiSpatialFocusTarget(
105523
105562
  this.frame,
105524
105563
  focusedSlotId,
@@ -105628,12 +105667,12 @@ var makeCampUiTerminalModes = (terminal) => {
105628
105667
  alternateScreenActive = false;
105629
105668
  }
105630
105669
  },
105631
- tryEnableAlternateScroll: () => {
105632
- if (alternateScrollActive) return true;
105633
- if (!alternateScreenActive || !terminal.kittyProtocolActive) return false;
105634
- terminal.write(ENABLE_ALTERNATE_SCROLL);
105635
- alternateScrollActive = true;
105636
- return true;
105670
+ setAlternateScroll: (wanted) => {
105671
+ if (!alternateScreenActive) return;
105672
+ const active2 = wanted || terminal.kittyProtocolActive;
105673
+ if (active2 === alternateScrollActive) return;
105674
+ terminal.write(active2 ? ENABLE_ALTERNATE_SCROLL : DISABLE_ALTERNATE_SCROLL);
105675
+ alternateScrollActive = active2;
105637
105676
  },
105638
105677
  wheelDirection: (input) => {
105639
105678
  if (!alternateScrollActive) return void 0;
@@ -105726,14 +105765,10 @@ var mountPiCampUi = (options2) => gen2(function* () {
105726
105765
  )
105727
105766
  )
105728
105767
  );
105729
- yield* forkScoped2(
105730
- gen2(function* () {
105731
- for (let attempt = 0; attempt < 25; attempt += 1) {
105732
- if (yield* sync4(() => terminalModes.tryEnableAlternateScroll())) return;
105733
- yield* sleep4("10 millis");
105734
- }
105735
- })
105736
- );
105768
+ const syncAlternateScroll = (model) => {
105769
+ terminalModes.setAlternateScroll(model.state.focusedSlotId === CampUiSlot.transcript);
105770
+ };
105771
+ yield* sync4(() => syncAlternateScroll(current2));
105737
105772
  const fibers = yield* make65();
105738
105773
  yield* run6(
105739
105774
  fibers,
@@ -105741,6 +105776,7 @@ var mountPiCampUi = (options2) => gen2(function* () {
105741
105776
  runForEach2(
105742
105777
  (model) => sync4(() => {
105743
105778
  current2 = model;
105779
+ syncAlternateScroll(model);
105744
105780
  tui.requestRender();
105745
105781
  })
105746
105782
  )
package/dist/priiisk.js CHANGED
@@ -3,7 +3,7 @@ import { createRequire as __priiiskCreateRequire } from "node:module";
3
3
  const require = __priiiskCreateRequire(import.meta.url);
4
4
  import {
5
5
  PRIIISK_CLI_VERSION
6
- } from "./chunk-HOYW7OPN.js";
6
+ } from "./chunk-SZWJI5KL.js";
7
7
  import "./chunk-7UPFIIZD.js";
8
8
 
9
9
  // packages/cli/src/bin/priiisk.ts
@@ -42,4 +42,4 @@ var prepareCompileCacheDirectory = () => {
42
42
  // packages/cli/src/bin/priiisk.ts
43
43
  var directory = prepareCompileCacheDirectory();
44
44
  if (directory !== void 0) enableCompileCache(directory);
45
- await import("./chunk-BZPGK4ZH.js");
45
+ await import("./chunk-37CJ4QRE.js");
package/package.json CHANGED
@@ -1,25 +1,25 @@
1
1
  {
2
2
  "name": "priiisk",
3
- "version": "0.1.23",
3
+ "version": "0.1.24",
4
4
  "description": "CLI for running and observing a camp of collaborating agents",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "priiisk": "./dist/priiisk.js"
8
8
  },
9
9
  "files": [
10
+ "dist/chunk-37CJ4QRE.js",
11
+ "dist/chunk-42AGXKI6.js",
12
+ "dist/chunk-5SZUTATM.js",
10
13
  "dist/chunk-7OL53RZ7.js",
11
14
  "dist/chunk-7OL53RZ7.js.LEGAL.txt",
12
15
  "dist/chunk-7UPFIIZD.js",
13
- "dist/chunk-BZPGK4ZH.js",
14
- "dist/chunk-ECYZGNL3.js",
15
- "dist/chunk-G3ITCVKS.js",
16
- "dist/chunk-HOYW7OPN.js",
17
- "dist/chunk-HRCEXDLT.js",
18
- "dist/chunk-J77LDB4Q.js",
19
- "dist/chunk-MJZ7FPJI.js",
16
+ "dist/chunk-AHGQRHTS.js",
17
+ "dist/chunk-AHGQRHTS.js.LEGAL.txt",
18
+ "dist/chunk-FUL25M5E.js",
20
19
  "dist/chunk-QDMSPX34.js",
21
- "dist/chunk-QO2YENTD.js",
22
- "dist/chunk-QO2YENTD.js.LEGAL.txt",
20
+ "dist/chunk-SZWJI5KL.js",
21
+ "dist/chunk-Z22GSS46.js",
22
+ "dist/chunk-ZIIUZJRV.js",
23
23
  "dist/priiisk-host.js",
24
24
  "dist/priiisk-host.js.LEGAL.txt",
25
25
  "dist/priiisk.js",