throughline 0.3.12 → 0.3.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "throughline",
3
- "version": "0.3.12",
3
+ "version": "0.3.14",
4
4
  "type": "module",
5
5
  "description": "Claude Code hooks plugin for structured context compression (/clear-safe persistent memory)",
6
6
  "keywords": [
@@ -242,30 +242,29 @@ export function shouldForceFullRedraw(prevCols, currCols) {
242
242
  * 描画に使う列幅を解決する。
243
243
  *
244
244
  * 優先順:
245
- * 1. **stdout が TTY** かつ `process.stdout.columns` が 40 以上
245
+ * 1. **stdout が TTY** かつ `process.stdout.columns` が 1 以上
246
246
  * → その値から 1 引いたもの(末尾列での自動改行回避)
247
- * 2. `process.env.COLUMNS` が 40 以上 → その値 - 1
248
- * 3. それ以外 → 200 にフォールバック
247
+ * 2. `process.env.COLUMNS` が 1 以上 → その値 - 1
248
+ * 3. それ以外 → 80 にフォールバック
249
249
  *
250
- * TTY のとき columns を信用しない理由:
251
- * VSCode `type: process` タスクは stdout PTY ではなくパイプとして渡すため、
252
- * - 起動時の columns undefined / 0 / 12 のような極端な値になることがある
253
- * - ターミナル panel をドラッグで広げても SIGWINCH が届かず columns が更新されない
254
- * - 結果として起動時に狭かった幅のまま永久に truncate され続ける
255
- * `isTTY` が false の時点で columns 値は信頼できない契約だと割り切り、env.COLUMNS か
256
- * 固定 200 にフォールバックする。
250
+ * 歴史: 0.3.6〜0.3.12 までは `>= 40` の閾値を設けて「狂った小さい値は捨てる」挙動
251
+ * だった。しかし実際の VSCode task panel 30 cells 程度で起動することがあり (実測)、
252
+ * 真の columns=30 なのに閾値に引っかかって 200 フォールバックに倒れ、30 cell 端末に
253
+ * 200 cell の行を書いて 7 行に折り返し、`\x1b[NA` 7 倍 under-count して
254
+ * 描画が永遠に積み上がるバグの真因だった。
257
255
  *
258
- * 200 固定フォールバックは、truncateToCells 200 セル以下の実内容をそのまま通す
259
- * (伸長しない)ので過大でも副作用なし。
256
+ * 正の columns はすべて信頼する。真の幅に合わせて truncate すれば物理行 = 論理行
257
+ * が保証され、CUU 戻り先が正確になる。狭い terminal ではコンテンツが切り詰められるが、
258
+ * 積み上がりに比べれば遥かにマシ (ユーザーが panel を広げれば full UI が見える)。
260
259
  */
261
260
  export function resolveColumns() {
262
261
  if (process.stdout.isTTY) {
263
262
  const reported = typeof process.stdout.columns === 'number' ? process.stdout.columns : 0;
264
- if (reported >= 40) return reported - 1;
263
+ if (reported > 0) return Math.max(1, reported - 1);
265
264
  }
266
265
  const fromEnv = Number(process.env.COLUMNS);
267
- if (Number.isFinite(fromEnv) && fromEnv >= 40) return fromEnv - 1;
268
- return 200;
266
+ if (Number.isFinite(fromEnv) && fromEnv > 0) return Math.max(1, fromEnv - 1);
267
+ return 80;
269
268
  }
270
269
 
271
270
  function formatLine({ state, usage, isActive, now = Date.now() }) {
@@ -558,7 +557,13 @@ export function main() {
558
557
  }
559
558
 
560
559
  process.stdout.write(ANSI.hideCursor);
561
- process.stdout.write(color(ANSI.dim, `[Throughline] モニター起動 (state: ${getStateDir()}, Ctrl+C で終了)\n`));
560
+ // 起動時に実 runtime での TTY/columns/resolveColumns を出す。
561
+ // diag と runtime で値がズレる (PTY allocation タイミング違い等) を直視できるようにするため。
562
+ const startupCols = resolveColumns();
563
+ const ttyFlag = process.stdout.isTTY ? 'T' : '-';
564
+ process.stdout.write(color(ANSI.dim,
565
+ `[Throughline] モニター起動 [${ttyFlag} cols=${process.stdout.columns ?? '?'} clip=${startupCols}] Ctrl+C で終了\n`,
566
+ ));
562
567
 
563
568
  safeRenderFrame(args);
564
569
  // columns の最後に使った値。polling で resize 検知するために使う。
@@ -410,41 +410,46 @@ function withStdoutState({ isTTY, columns, envColumns }, fn) {
410
410
  }
411
411
  }
412
412
 
413
- test('resolveColumns: TTY かつ columns 40 以上 → その値 - 1', () => {
413
+ test('resolveColumns: TTY かつ columns が正値 → その値 - 1', () => {
414
414
  withStdoutState({ isTTY: true, columns: 120, envColumns: undefined }, () => {
415
415
  assert.equal(resolveColumns(), 119);
416
416
  });
417
417
  });
418
418
 
419
- test('resolveColumns: TTY なら columns が大きくても信用しない (env 200 も使う)', () => {
420
- // type: process タスクで columns 120 にセットされたが実際の幅とは連動しない、という状況。
421
- // env.COLUMNS も無ければ 200 フォールバック。
422
- withStdoutState({ isTTY: false, columns: 120, envColumns: undefined }, () => {
423
- assert.equal(resolveColumns(), 200);
419
+ test('resolveColumns: TTY かつ columns が狭い値 (VSCode task panel 等の実値) も信用する', () => {
420
+ // 0.3.6〜0.3.12 の閾値 40 バグを再現防止: 30 cells は実測ベースで正当な値
421
+ withStdoutState({ isTTY: true, columns: 30, envColumns: undefined }, () => {
422
+ assert.equal(resolveColumns(), 29);
424
423
  });
425
424
  });
426
425
 
427
- test('resolveColumns: TTY でも columns が小さすぎる値 (12 ) ならフォールバック 200', () => {
428
- withStdoutState({ isTTY: true, columns: 12, envColumns: undefined }, () => {
429
- assert.equal(resolveColumns(), 200);
426
+ test('resolveColumns: TTY かつ columns=1 1 にクランプ (columns-1=0 回避)', () => {
427
+ withStdoutState({ isTTY: true, columns: 1, envColumns: undefined }, () => {
428
+ assert.equal(resolveColumns(), 1);
429
+ });
430
+ });
431
+
432
+ test('resolveColumns: 非 TTY は columns を信用しない', () => {
433
+ withStdoutState({ isTTY: false, columns: 120, envColumns: undefined }, () => {
434
+ assert.equal(resolveColumns(), 80);
430
435
  });
431
436
  });
432
437
 
433
- test('resolveColumns: 非 TTY でも env.COLUMNS >= 40 があればそれを使う', () => {
438
+ test('resolveColumns: 非 TTY でも env.COLUMNS があればそれを使う', () => {
434
439
  withStdoutState({ isTTY: false, columns: undefined, envColumns: '150' }, () => {
435
440
  assert.equal(resolveColumns(), 149);
436
441
  });
437
442
  });
438
443
 
439
- test('resolveColumns: TTY で columns 未設定、env も無ければフォールバック 200', () => {
444
+ test('resolveColumns: TTY で columns 未設定、env も無ければフォールバック 80', () => {
440
445
  withStdoutState({ isTTY: true, columns: undefined, envColumns: undefined }, () => {
441
- assert.equal(resolveColumns(), 200);
446
+ assert.equal(resolveColumns(), 80);
442
447
  });
443
448
  });
444
449
 
445
- test('resolveColumns: 全てのソースが無効ならフォールバック 200', () => {
450
+ test('resolveColumns: 全てのソースが無効ならフォールバック 80', () => {
446
451
  withStdoutState({ isTTY: false, columns: undefined, envColumns: undefined }, () => {
447
- assert.equal(resolveColumns(), 200);
452
+ assert.equal(resolveColumns(), 80);
448
453
  });
449
454
  });
450
455