throughline 0.3.24 → 0.3.25

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.
Files changed (111) hide show
  1. package/.claude/commands/tl-trim.md +42 -0
  2. package/.codex-sidecar.yml +62 -0
  3. package/CHANGELOG.md +583 -0
  4. package/README.ja.md +42 -5
  5. package/README.md +383 -23
  6. package/bin/throughline.mjs +168 -4
  7. package/codex/skills/throughline/SKILL.md +157 -0
  8. package/codex/skills/throughline/agents/openai.yaml +7 -0
  9. package/docs/INHERITANCE_ON_CLEAR_ONLY.md +146 -0
  10. package/docs/L1_L2_L3_REDESIGN.md +415 -0
  11. package/docs/PUBLIC_RELEASE_PLAN.md +184 -0
  12. package/docs/THROUGHLINE_CODEX_DUAL_SUPPORT.md +249 -0
  13. package/docs/THROUGHLINE_CODEX_FIRST_ROADMAP.md +555 -0
  14. package/docs/THROUGHLINE_CODEX_MONITOR_IMPLEMENTATION_PLAN.md +220 -0
  15. package/docs/THROUGHLINE_CODEX_TRIM_IMPLEMENTATION_PLAN.md +528 -0
  16. package/docs/THROUGHLINE_CODEX_TRIM_ROLLBACK_FIX_PLAN.md +672 -0
  17. package/docs/archive/CONCEPT.md +476 -0
  18. package/docs/archive/EXPERIMENT.md +371 -0
  19. package/docs/archive/README.md +22 -0
  20. package/docs/archive/SESSION_LINKING_DESIGN.md +231 -0
  21. package/docs/archive/THROUGHLINE_NEXT_STEPS.md +134 -0
  22. package/docs/throughline-codex-trim-rollback-incident-report.md +306 -0
  23. package/docs/throughline-handoff-context.example.json +57 -0
  24. package/docs/throughline-rollback-context-trim-insight.md +455 -0
  25. package/package.json +6 -2
  26. package/src/cli/codex-capture.mjs +95 -0
  27. package/src/cli/codex-handoff-model-smoke.mjs +292 -0
  28. package/src/cli/codex-handoff-model-smoke.test.mjs +262 -0
  29. package/src/cli/codex-handoff-smoke.mjs +163 -0
  30. package/src/cli/codex-handoff-smoke.test.mjs +149 -0
  31. package/src/cli/codex-handoff-start.mjs +291 -0
  32. package/src/cli/codex-handoff-start.test.mjs +194 -0
  33. package/src/cli/codex-hook.mjs +276 -0
  34. package/src/cli/codex-hook.test.mjs +293 -0
  35. package/src/cli/codex-host-primitive-audit.mjs +110 -0
  36. package/src/cli/codex-host-primitive-audit.test.mjs +75 -0
  37. package/src/cli/codex-restore-smoke.mjs +357 -0
  38. package/src/cli/codex-restore-source-audit.mjs +304 -0
  39. package/src/cli/codex-resume.mjs +138 -0
  40. package/src/cli/codex-rollback-model-visible-smoke.mjs +373 -0
  41. package/src/cli/codex-rollback-model-visible-smoke.test.mjs +255 -0
  42. package/src/cli/codex-sidecar-diagnostics.mjs +48 -0
  43. package/src/cli/codex-sidecar-dry-run.mjs +85 -0
  44. package/src/cli/codex-summarize.mjs +224 -0
  45. package/src/cli/codex-threads.mjs +89 -0
  46. package/src/cli/codex-visibility-smoke.mjs +196 -0
  47. package/src/cli/codex-vscode-restore-smoke.mjs +226 -0
  48. package/src/cli/codex-vscode-rollback-smoke.mjs +114 -0
  49. package/src/cli/doctor.mjs +503 -1
  50. package/src/cli/doctor.test.mjs +542 -3
  51. package/src/cli/handoff-preview.mjs +78 -0
  52. package/src/cli/help.test.mjs +64 -0
  53. package/src/cli/install.mjs +227 -4
  54. package/src/cli/install.test.mjs +207 -4
  55. package/src/cli/trim.mjs +564 -0
  56. package/src/codex-app-server.mjs +1816 -0
  57. package/src/codex-app-server.test.mjs +512 -0
  58. package/src/codex-auto-refresh.mjs +194 -0
  59. package/src/codex-auto-refresh.test.mjs +182 -0
  60. package/src/codex-capture.mjs +235 -0
  61. package/src/codex-capture.test.mjs +393 -0
  62. package/src/codex-handoff-model-smoke.mjs +114 -0
  63. package/src/codex-handoff-model-smoke.test.mjs +89 -0
  64. package/src/codex-handoff-smoke.mjs +124 -0
  65. package/src/codex-handoff-smoke.test.mjs +103 -0
  66. package/src/codex-handoff.mjs +331 -0
  67. package/src/codex-handoff.test.mjs +220 -0
  68. package/src/codex-host-primitive-audit.mjs +374 -0
  69. package/src/codex-host-primitive-audit.test.mjs +208 -0
  70. package/src/codex-restore-smoke.test.mjs +639 -0
  71. package/src/codex-restore-source-audit.mjs +1348 -0
  72. package/src/codex-restore-source-audit.test.mjs +623 -0
  73. package/src/codex-resume.test.mjs +242 -0
  74. package/src/codex-rollout-memory.mjs +711 -0
  75. package/src/codex-rollout-memory.test.mjs +610 -0
  76. package/src/codex-sidecar-cli.test.mjs +75 -0
  77. package/src/codex-sidecar.mjs +246 -0
  78. package/src/codex-sidecar.test.mjs +172 -0
  79. package/src/codex-summarize.test.mjs +143 -0
  80. package/src/codex-thread-identity.mjs +23 -0
  81. package/src/codex-thread-index.mjs +173 -0
  82. package/src/codex-thread-index.test.mjs +164 -0
  83. package/src/codex-usage.mjs +110 -0
  84. package/src/codex-usage.test.mjs +140 -0
  85. package/src/codex-visibility-smoke.test.mjs +222 -0
  86. package/src/codex-vscode-restore-smoke.mjs +206 -0
  87. package/src/codex-vscode-restore-smoke.test.mjs +325 -0
  88. package/src/codex-vscode-rollback-smoke.mjs +90 -0
  89. package/src/codex-vscode-rollback-smoke.test.mjs +290 -0
  90. package/src/db-schema.test.mjs +97 -0
  91. package/src/haiku-summarizer.mjs +267 -26
  92. package/src/haiku-summarizer.test.mjs +282 -0
  93. package/src/handoff-preview.test.mjs +108 -0
  94. package/src/handoff-record.mjs +294 -0
  95. package/src/handoff-record.test.mjs +226 -0
  96. package/src/hook-entrypoints.test.mjs +326 -0
  97. package/src/package-files.test.mjs +19 -0
  98. package/src/prompt-submit.mjs +9 -6
  99. package/src/resume-context.mjs +44 -140
  100. package/src/resume-context.test.mjs +172 -0
  101. package/src/session-start.mjs +8 -5
  102. package/src/state-file.mjs +50 -6
  103. package/src/state-file.test.mjs +50 -0
  104. package/src/token-monitor.mjs +14 -10
  105. package/src/token-monitor.test.mjs +27 -0
  106. package/src/trim-cli.test.mjs +1584 -0
  107. package/src/trim-model.mjs +584 -0
  108. package/src/trim-model.test.mjs +568 -0
  109. package/src/turn-processor.mjs +17 -10
  110. package/src/vscode-task.mjs +33 -10
  111. package/src/vscode-task.test.mjs +19 -9
@@ -239,7 +239,12 @@ export function buildSetupNotice(action) {
239
239
  return null;
240
240
  }
241
241
 
242
- function emitSetupNotice(action) {
242
+ function shouldEmitNotices(env) {
243
+ return env.THROUGHLINE_SUPPRESS_VSCODE_NOTICES !== '1';
244
+ }
245
+
246
+ function emitSetupNotice(action, env) {
247
+ if (!shouldEmitNotices(env)) return;
243
248
  const text = buildSetupNotice(action);
244
249
  if (text) process.stdout.write(text);
245
250
  }
@@ -279,9 +284,18 @@ export function shouldRecommendGitignore(cwd) {
279
284
  return true;
280
285
  }
281
286
 
282
- function emitGitignoreRecommendationOnce(vscodeDir) {
287
+ function emitGitignoreRecommendationOnce(vscodeDir, env) {
283
288
  const markerPath = join(vscodeDir, GITIGNORE_MARKER_FILENAME);
284
289
  if (existsSync(markerPath)) return;
290
+ if (!shouldEmitNotices(env)) {
291
+ try {
292
+ writeFileSync(markerPath, `${new Date().toISOString()}\n`);
293
+ } catch (err) {
294
+ const msg = err instanceof Error ? err.message : 'unknown';
295
+ process.stderr.write(`[throughline] failed to write gitignore marker: ${msg}\n`);
296
+ }
297
+ return;
298
+ }
285
299
  process.stdout.write(
286
300
  '<system-reminder>\n' +
287
301
  'Throughline ヒント: .vscode/tasks.json には現環境の絶対パス (node 実行ファイル / throughline.mjs)\n' +
@@ -305,9 +319,18 @@ function emitGitignoreRecommendationOnce(vscodeDir) {
305
319
  }
306
320
  }
307
321
 
308
- function emitJsoncGuidanceOnce(vscodeDir) {
322
+ function emitJsoncGuidanceOnce(vscodeDir, env) {
309
323
  const markerPath = join(vscodeDir, JSONC_MARKER_FILENAME);
310
324
  if (existsSync(markerPath)) return;
325
+ if (!shouldEmitNotices(env)) {
326
+ try {
327
+ writeFileSync(markerPath, `${new Date().toISOString()}\n`);
328
+ } catch (err) {
329
+ const msg = err instanceof Error ? err.message : 'unknown';
330
+ process.stderr.write(`[throughline] failed to write JSONC marker: ${msg}\n`);
331
+ }
332
+ return;
333
+ }
311
334
  process.stderr.write(
312
335
  `[throughline] .vscode/tasks.json contains JSONC features (comments or trailing commas). ` +
313
336
  `Auto-edit is unsafe on this file — add the Throughline Monitor task manually. ` +
@@ -363,15 +386,15 @@ export function ensureMonitorTaskFile(opts = {}) {
363
386
  if (!existsSync(vscodeDir)) mkdirSync(vscodeDir, { recursive: true });
364
387
  const obj = { version: '2.0.0', tasks: [buildMonitorTask(bin)] };
365
388
  atomicWrite(tasksPath, JSON.stringify(obj, null, 2) + '\n');
366
- emitSetupNotice('created');
367
- if (shouldRecommendGitignore(cwd)) emitGitignoreRecommendationOnce(vscodeDir);
389
+ emitSetupNotice('created', env);
390
+ if (shouldRecommendGitignore(cwd)) emitGitignoreRecommendationOnce(vscodeDir, env);
368
391
  return { action: 'created', path: tasksPath };
369
392
  }
370
393
 
371
394
  const text = readFileSync(tasksPath, 'utf8');
372
395
 
373
396
  if (detectJsoncFeatures(text)) {
374
- emitJsoncGuidanceOnce(vscodeDir);
397
+ emitJsoncGuidanceOnce(vscodeDir, env);
375
398
  return { action: 'skipped', reason: 'jsonc_unsupported', path: tasksPath };
376
399
  }
377
400
 
@@ -398,8 +421,8 @@ export function ensureMonitorTaskFile(opts = {}) {
398
421
  nextTasks[existingIdx] = repaired;
399
422
  const nextObj = { ...obj, version: obj.version ?? '2.0.0', tasks: nextTasks };
400
423
  atomicWrite(tasksPath, JSON.stringify(nextObj, null, indent) + '\n');
401
- emitSetupNotice('repaired');
402
- if (shouldRecommendGitignore(cwd)) emitGitignoreRecommendationOnce(vscodeDir);
424
+ emitSetupNotice('repaired', env);
425
+ if (shouldRecommendGitignore(cwd)) emitGitignoreRecommendationOnce(vscodeDir, env);
403
426
  return { action: 'repaired', path: tasksPath };
404
427
  }
405
428
  return { action: 'already_present', path: tasksPath };
@@ -412,7 +435,7 @@ export function ensureMonitorTaskFile(opts = {}) {
412
435
  tasks: [...(Array.isArray(obj.tasks) ? obj.tasks : []), buildMonitorTask(bin)],
413
436
  };
414
437
  atomicWrite(tasksPath, JSON.stringify(nextObj, null, indent) + '\n');
415
- emitSetupNotice('merged');
416
- if (shouldRecommendGitignore(cwd)) emitGitignoreRecommendationOnce(vscodeDir);
438
+ emitSetupNotice('merged', env);
439
+ if (shouldRecommendGitignore(cwd)) emitGitignoreRecommendationOnce(vscodeDir, env);
417
440
  return { action: 'merged', path: tasksPath };
418
441
  }
@@ -16,7 +16,13 @@ import {
16
16
  shouldRecommendGitignore,
17
17
  } from './vscode-task.mjs';
18
18
 
19
- const VSCODE_ENV = { TERM_PROGRAM: 'vscode' };
19
+ const VSCODE_ENV = {
20
+ TERM_PROGRAM: 'vscode',
21
+ THROUGHLINE_SUPPRESS_VSCODE_NOTICES: '1',
22
+ };
23
+ // Production notices are Claude-facing additional context. Tests keep them
24
+ // silent by default and opt in only when asserting notice text.
25
+ const VSCODE_NOTICE_ENV = { TERM_PROGRAM: 'vscode' };
20
26
  // 実在する絶対パスを使う。`isMonitorTaskBroken` が「絶対パス + 非存在」で broken 判定するので、
21
27
  // 架空パスを使うと意図せず repaired ブランチに落ちてしまう。
22
28
  const FAKE_BIN = process.execPath;
@@ -436,7 +442,11 @@ test('ensureMonitorTaskFile: already_present when command references throughline
436
442
  {
437
443
  label: 'My Custom Monitor',
438
444
  type: 'process',
439
- command: '/usr/bin/node',
445
+ // 実在する絶対パスを使う。`/usr/bin/node` は WSL2 では実在するが
446
+ // CI runner (Linux/macOS は /opt/hostedtoolcache, Windows は別) では
447
+ // 存在しないので isMonitorTaskBroken が true になり repaired ブランチに落ちる。
448
+ // process.execPath なら「いま走らせている node 自身の絶対パス」なので必ず実在する。
449
+ command: process.execPath,
440
450
  // 相対パスにして broken 判定を避ける(このテストは「label renamed でも検出できるか」だけが論点)
441
451
  args: ['./throughline.mjs', 'monitor'],
442
452
  },
@@ -573,7 +583,7 @@ test('ensureMonitorTaskFile: created emits gitignore recommendation when .git ex
573
583
  mkdirSync(join(dir, '.git'));
574
584
  const result = ensureMonitorTaskFile({
575
585
  cwd: dir,
576
- env: VSCODE_ENV,
586
+ env: VSCODE_NOTICE_ENV,
577
587
  throughlineBin: FAKE_BIN,
578
588
  });
579
589
  assert.equal(result.action, 'created');
@@ -597,7 +607,7 @@ test('ensureMonitorTaskFile: created does NOT emit gitignore recommendation when
597
607
  try {
598
608
  const result = ensureMonitorTaskFile({
599
609
  cwd: dir,
600
- env: VSCODE_ENV,
610
+ env: VSCODE_NOTICE_ENV,
601
611
  throughlineBin: FAKE_BIN,
602
612
  });
603
613
  assert.equal(result.action, 'created');
@@ -624,7 +634,7 @@ test('ensureMonitorTaskFile: gitignore recommendation is emitted only once per p
624
634
  // 1 回目: created → gitignore 推奨が出る
625
635
  const r1 = ensureMonitorTaskFile({
626
636
  cwd: dir,
627
- env: VSCODE_ENV,
637
+ env: VSCODE_NOTICE_ENV,
628
638
  throughlineBin: FAKE_BIN,
629
639
  });
630
640
  assert.equal(r1.action, 'created');
@@ -791,7 +801,7 @@ test('ensureMonitorTaskFile: repaired emits notice on stdout', () => {
791
801
 
792
802
  const result = ensureMonitorTaskFile({
793
803
  cwd: dir,
794
- env: VSCODE_ENV,
804
+ env: VSCODE_NOTICE_ENV,
795
805
  throughlineBin: FAKE_BIN,
796
806
  });
797
807
  assert.equal(result.action, 'repaired');
@@ -867,7 +877,7 @@ test('ensureMonitorTaskFile: jsonc_unsupported marker suppresses stderr on 2nd c
867
877
  try {
868
878
  const r1 = ensureMonitorTaskFile({
869
879
  cwd: dir,
870
- env: VSCODE_ENV,
880
+ env: VSCODE_NOTICE_ENV,
871
881
  throughlineBin: FAKE_BIN,
872
882
  });
873
883
  assert.equal(r1.action, 'skipped');
@@ -956,13 +966,13 @@ test('buildSetupNotice: ensureMonitorTaskFile writes notice to stdout on first c
956
966
  try {
957
967
  const r1 = ensureMonitorTaskFile({
958
968
  cwd: dir,
959
- env: VSCODE_ENV,
969
+ env: VSCODE_NOTICE_ENV,
960
970
  throughlineBin: FAKE_BIN,
961
971
  });
962
972
  assert.equal(r1.action, 'created');
963
973
  const r2 = ensureMonitorTaskFile({
964
974
  cwd: dir,
965
- env: VSCODE_ENV,
975
+ env: VSCODE_NOTICE_ENV,
966
976
  throughlineBin: FAKE_BIN,
967
977
  });
968
978
  assert.equal(r2.action, 'already_present');