throughline 0.3.9 → 0.3.10

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.9",
3
+ "version": "0.3.10",
4
4
  "type": "module",
5
5
  "description": "Claude Code hooks plugin for structured context compression (/clear-safe persistent memory)",
6
6
  "keywords": [
@@ -33,12 +33,6 @@ let lastTimeAgoRefresh = Date.now();
33
33
  const ANSI = {
34
34
  hideCursor: '\x1b[?25l',
35
35
  showCursor: '\x1b[?25h',
36
- // オルタネートスクリーンバッファ (htop / vim / less が使うやつ)。
37
- // プライマリバッファでの `\x1b[2J` は xterm.js だと「描画済み行をスクロール履歴に
38
- // 押し上げる」挙動になり、狭い VSCode task terminal で描画が永遠に積み上がる
39
- // 症状を引き起こす。alt バッファならスクロール履歴に残らず真にクリアできる。
40
- enterAltScreen: '\x1b[?1049h',
41
- leaveAltScreen: '\x1b[?1049l',
42
36
  clearLine: '\x1b[2K',
43
37
  clearScreen: '\x1b[2J\x1b[H',
44
38
  clearBelow: '\x1b[0J', // 現在位置から画面末尾までをクリア
@@ -447,18 +441,12 @@ function renderFrame(args) {
447
441
  }
448
442
 
449
443
  // --- 起動 ---
450
- let terminalRestored = false;
451
- /**
452
- * 終了時に端末状態を元に戻す:
453
- * - オルタネートスクリーンバッファから抜ける (起動前の画面に戻る)
454
- * - カーソル表示を復活
455
- * 2 回以上呼ばれても安全 (冪等)。
456
- */
444
+ let cursorRestored = false;
457
445
  function restoreCursor() {
458
- if (terminalRestored) return;
459
- terminalRestored = true;
446
+ if (cursorRestored) return;
447
+ cursorRestored = true;
460
448
  try {
461
- process.stdout.write(ANSI.leaveAltScreen + ANSI.showCursor);
449
+ process.stdout.write(ANSI.showCursor);
462
450
  } catch {
463
451
  // stdout がすでに閉じていても無視
464
452
  }
@@ -484,9 +472,7 @@ export function main() {
484
472
  process.exit(2);
485
473
  }
486
474
 
487
- // オルタネートスクリーンバッファに入る → プライマリ画面を保存、クリア時に履歴に残らない。
488
- // これにより「1 セッション」ヘッダが再描画のたびに積み上がる不具合を根絶できる。
489
- process.stdout.write(ANSI.enterAltScreen + ANSI.hideCursor);
475
+ process.stdout.write(ANSI.hideCursor);
490
476
  process.stdout.write(color(ANSI.dim, `[Throughline] モニター起動 (state: ${getStateDir()}, Ctrl+C で終了)\n`));
491
477
 
492
478
  safeRenderFrame(args);
@@ -105,27 +105,25 @@ export function hasMonitorTask(obj) {
105
105
  /**
106
106
  * 生成する VSCode タスク定義を組み立てる。
107
107
  *
108
- * type: 'process' を選ぶ理由: shell は Windows の .cmd shim や PATH 解決に
109
- * 依存して失敗しうる。process command を直接起動するため堅い。
110
- * command には Node 実行ファイルの絶対パスを入れ、args throughline.mjs
111
- * 絶対パスと 'monitor' サブコマンドを渡す。
108
+ * type: 'shell' を選ぶ理由:
109
+ * VSCode の type: 'process' は子プロセスの stdout を生パイプで渡すため、
110
+ * isTTY=false となり真の columns が取れず、`\x1b[2J\x1b[H` alt screen
111
+ * 期待通りに動かず、モニターの行描画が毎ティック積み上がる症状を引き起こす。
112
+ * type: 'shell' なら VSCode が PTY を張って xterm.js ベースの疑似端末を与え、
113
+ * isTTY=true で真の幅が取れ、resize イベントも発火する。
112
114
  *
113
- * options.env.COLUMNS=200 を渡す理由:
114
- * type: 'process' では VSCode PTY を張らず stdout をパイプするため、
115
- * 子プロセスの `process.stdout.columns` undefined か極端に小さい値になり、
116
- * モニターの幅計算が破綻する。COLUMNS env を明示しておけば token-monitor の
117
- * resolveColumns() が 200 を採用して行が「openclaw」で切れる不具合を避けられる。
115
+ * Windows .cmd shim リスクは「command / args を shell の実行ファイル
116
+ * (cmd.exe / bash) に絶対パスで渡す」ので消えている。command node.exe
117
+ * 絶対パス、args に throughline.mjs の絶対パスと 'monitor' を入れ、shell
118
+ * (cmd.exe pwsh) がそのまま起動するだけ。
118
119
  */
119
120
  export function buildMonitorTask(throughlineBin) {
120
121
  return {
121
122
  label: MONITOR_LABEL,
122
123
  detail: 'Auto-generated by Throughline. Opens token-monitor in a dedicated terminal when the folder is opened.',
123
- type: 'process',
124
+ type: 'shell',
124
125
  command: process.execPath,
125
126
  args: [throughlineBin, 'monitor'],
126
- options: {
127
- env: { COLUMNS: '200' },
128
- },
129
127
  isBackground: true,
130
128
  presentation: {
131
129
  reveal: 'always',
@@ -138,23 +138,16 @@ test('hasMonitorTask: handles missing tasks array', () => {
138
138
 
139
139
  // --- buildMonitorTask ---
140
140
 
141
- test('buildMonitorTask: uses type=process with provided bin as args[0]', () => {
141
+ test('buildMonitorTask: uses type=shell with provided bin as args[0] for PTY allocation', () => {
142
142
  const task = buildMonitorTask('/abs/bin/throughline.mjs');
143
143
  assert.equal(task.label, 'Throughline Monitor');
144
- assert.equal(task.type, 'process');
144
+ assert.equal(task.type, 'shell');
145
145
  assert.equal(task.args[0], '/abs/bin/throughline.mjs');
146
146
  assert.deepEqual(task.args.slice(1), ['monitor']);
147
147
  assert.equal(task.runOptions.runOn, 'folderOpen');
148
148
  assert.equal(task.isBackground, true);
149
149
  });
150
150
 
151
- test('buildMonitorTask: sets COLUMNS=200 env to work around type:process non-TTY stdout', () => {
152
- const task = buildMonitorTask('/abs/bin/throughline.mjs');
153
- assert.ok(task.options, 'task should carry options');
154
- assert.ok(task.options.env, 'options should carry env');
155
- assert.equal(task.options.env.COLUMNS, '200');
156
- });
157
-
158
151
  // --- ensureMonitorTaskFile: skip conditions ---
159
152
 
160
153
  test('ensureMonitorTaskFile: opt_out via THROUGHLINE_NO_VSCODE=1', () => {
@@ -239,7 +232,7 @@ test('ensureMonitorTaskFile: created when .vscode/ missing', () => {
239
232
  assert.equal(obj.version, '2.0.0');
240
233
  assert.equal(obj.tasks.length, 1);
241
234
  assert.equal(obj.tasks[0].label, 'Throughline Monitor');
242
- assert.equal(obj.tasks[0].type, 'process');
235
+ assert.equal(obj.tasks[0].type, 'shell');
243
236
  assert.equal(obj.tasks[0].args[0], FAKE_BIN);
244
237
  } finally {
245
238
  cleanup();