@ramarivera/coding-buddy 0.8.0 → 0.9.1

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 (56) hide show
  1. package/README.md +23 -4
  2. package/adapters/omp/context.ts +1 -1
  3. package/adapters/omp/events.ts +286 -81
  4. package/adapters/omp/index.ts +3 -1
  5. package/adapters/omp/renderers.ts +4 -54
  6. package/adapters/omp/storage.ts +6 -1
  7. package/adapters/omp/ui.ts +17 -6
  8. package/adapters/pi/events.ts +280 -83
  9. package/adapters/pi/index.ts +11 -2
  10. package/adapters/pi/renderers.ts +3 -47
  11. package/adapters/pi/storage.ts +6 -1
  12. package/adapters/pi/ui.ts +17 -6
  13. package/adapters/shared/file-storage.ts +22 -0
  14. package/adapters/shared/widget-layout.ts +248 -2
  15. package/cli/settings.ts +1 -1
  16. package/cli/tui.tsx +1 -1
  17. package/core/command-service.ts +13 -0
  18. package/core/engine.ts +11 -2
  19. package/core/identity.ts +15 -0
  20. package/core/model.ts +3 -0
  21. package/core/ports.ts +4 -0
  22. package/core/reactions.ts +29 -2
  23. package/core/render-model.ts +4 -3
  24. package/package.json +6 -3
  25. package/scripts/ci/Dockerfile.vhs +125 -0
  26. package/scripts/ci/check-statusline.sh +441 -14
  27. package/scripts/ci/check-vhs-goldens.sh +97 -0
  28. package/scripts/ci/fonts.conf +37 -0
  29. package/scripts/ci/goldens/baseline-40.png +0 -0
  30. package/scripts/ci/goldens/baseline-80.png +0 -0
  31. package/scripts/ci/goldens/cjk-80.png +0 -0
  32. package/scripts/ci/goldens/emoji-80.png +0 -0
  33. package/scripts/ci/render-statusline-pty.py +107 -0
  34. package/scripts/ci/render-vhs-goldens.sh +226 -0
  35. package/scripts/ci/statusline.tape +28 -2
  36. package/scripts/ci/vhs-density-fixtures.sh +27 -0
  37. package/scripts/ci/vhs-run-statusline.sh +28 -0
  38. package/scripts/ci/write-density-status.ts +86 -0
  39. package/scripts/gen-emoji-widths.ts +41 -17
  40. package/scripts/paths.sh +3 -1
  41. package/server/art.ts +70 -17
  42. package/server/hooks/buddy-comment.ts +166 -17
  43. package/server/hooks/file-type-react.ts +1 -1
  44. package/server/hooks/mood-react.ts +1 -1
  45. package/server/hooks/name-react.ts +1 -1
  46. package/server/hooks/react.ts +1 -1
  47. package/server/hooks/reaction-data.ts +10 -3
  48. package/server/index.ts +67 -27
  49. package/server/path.ts +3 -0
  50. package/server/state.ts +147 -41
  51. package/skills/buddy/SKILL.md +1 -1
  52. package/statusline/buddy-status.sh +488 -76
  53. package/statusline/emoji-text.data +3 -0
  54. package/statusline/emoji-widths.data +2 -3
  55. package/statusline/substatus.sh +52 -10
  56. package/scripts/postinstall.cjs +0 -42
@@ -0,0 +1,3 @@
1
+ # Auto-generated by scripts/gen-emoji-widths.ts — do not edit by hand.
2
+ # Decimal codepoint ranges with Unicode Emoji=Yes and Emoji_Presentation=No.
3
+ 35,42,48-57,169,174,8252,8265,8482,8505,8596-8601,8617-8618,9000,9167,9197-9199,9201-9202,9208-9210,9410,9642-9643,9654,9664,9723-9724,9728-9732,9742,9745,9752,9757,9760,9762-9763,9766,9770,9774-9775,9784-9786,9792,9794,9823-9824,9827,9829-9830,9832,9851,9854,9874,9876-9879,9881,9883-9884,9888,9895,9904-9905,9928,9935,9937,9939,9961,9968-9969,9972,9975-9977,9986,9992-9993,9996-9997,9999,10002,10004,10006,10013,10017,10035-10036,10052,10055,10083-10084,10145,10548-10549,11013-11015,12336,12349,12951,12953,127344-127345,127358-127359,127490,127543,127777,127780-127788,127798,127869,127894-127895,127897-127899,127902-127903,127947-127950,127956-127967,127987,127989,127991,128063,128065,128253,128329-128330,128367-128368,128371-128377,128391,128394-128397,128400,128421,128424,128433-128434,128444,128450-128452,128465-128467,128476-128478,128481,128483,128488,128495,128499,128506,128715,128717-128719,128736-128741,128745,128752,128755
@@ -1,4 +1,3 @@
1
1
  # Auto-generated by scripts/gen-emoji-widths.ts — do not edit by hand.
2
- # Decimal codepoints in U+2600-U+27BF with Unicode Emoji_Presentation=Yes.
3
- # Regenerate with: bun run gen:emoji-widths
4
- 9748 9749 9800 9801 9802 9803 9804 9805 9806 9807 9808 9809 9810 9811 9855 9875 9889 9898 9899 9917 9918 9924 9925 9934 9940 9962 9970 9971 9973 9978 9981 9989 9994 9995 10024 10060 10062 10067 10068 10069 10071 10133 10134 10135 10160 10175
2
+ # Decimal codepoint ranges with Unicode Emoji_Presentation=Yes.
3
+ 8986-8987,9193-9196,9200,9203,9725-9726,9748-9749,9800-9811,9855,9875,9889,9898-9899,9917-9918,9924-9925,9934,9940,9962,9970-9971,9973,9978,9981,9989,9994-9995,10024,10060,10062,10067-10069,10071,10133-10135,10160,10175,11035-11036,11088,11093,126980,127183,127374,127377-127386,127462-127487,127489,127514,127535,127538-127542,127544-127546,127568-127569,127744-127776,127789-127797,127799-127868,127870-127891,127904-127946,127951-127955,127968-127984,127988,127992-128062,128064,128066-128252,128255-128317,128331-128334,128336-128359,128378,128405-128406,128420,128507-128591,128640-128709,128716,128720-128722,128725-128728,128732-128735,128747-128748,128756-128764,128992-129003,129008,129292-129338,129340-129349,129351-129535,129648-129660,129664-129674,129678-129734,129736,129741-129756,129759-129770,129775-129784
@@ -25,12 +25,24 @@ append_substatus() {
25
25
  local cache_file="$state_dir/.substatus.$sid"
26
26
  local lock_dir="$state_dir/.substatus.$sid.lock"
27
27
  local command=""
28
- local now cache_age lock_age refresh_seconds configured_refresh_seconds
28
+ local now cache_age lock_age refresh_seconds configured_refresh_seconds line sweep_lock sweep_lock_age
29
29
 
30
- # Remove abandoned refresh output without touching the complete cache or
31
- # the lock directory. The refresh path below uses the same deterministic
32
- # temp filename, so this also cleans up files from older implementations.
33
- find "$state_dir" -type f -name ".substatus.$sid.*" -mmin +60 -exec rm -f {} \; 2>/dev/null
30
+ # Cleanup is intentionally detached: stale temp files are housekeeping and
31
+ # must not make the statusline wait on a filesystem walk. The lock keeps
32
+ # concurrent statusline ticks from launching duplicate sweeps.
33
+ sweep_lock="$state_dir/.substatus-sweep.$sid.lock"
34
+ if [ -d "$sweep_lock" ]; then
35
+ sweep_lock_age=$(( $(date +%s) - $(_substatus_mtime "$sweep_lock") ))
36
+ if [ "$sweep_lock_age" -gt 300 ]; then
37
+ rmdir "$sweep_lock" 2>/dev/null || rm -rf "$sweep_lock" 2>/dev/null
38
+ fi
39
+ fi
40
+ if mkdir "$sweep_lock" 2>/dev/null; then
41
+ (
42
+ trap 'rmdir "$sweep_lock" 2>/dev/null' EXIT
43
+ find "$state_dir" -type f -name ".substatus.$sid.*" -mmin +60 -exec rm -f {} + 2>/dev/null
44
+ ) >/dev/null 2>&1 &
45
+ fi
34
46
 
35
47
  [ -f "$config_file" ] || return 0
36
48
  command=$(jq -r '.subStatusCommand // ""' "$config_file" 2>/dev/null)
@@ -43,10 +55,21 @@ append_substatus() {
43
55
  *) [ "$configured_refresh_seconds" -gt 0 ] && refresh_seconds="$configured_refresh_seconds" ;;
44
56
  esac
45
57
 
46
- # Always show the last complete result first. A missing or stale cache is
47
- # allowed to be blank; the refresh below will populate the next tick.
48
- [ -f "$cache_file" ] && cat "$cache_file"
49
-
58
+ # The main statusline supplies ANSI-aware output when it has a width
59
+ # budget. Keep this helper standalone for callers that don't.
60
+ _substatus_print_line() {
61
+ local line="$1"
62
+ if [ "$(type -t statusline_output_line 2>/dev/null)" = "function" ]; then
63
+ statusline_output_line "$line"
64
+ else
65
+ printf '%s\n' "$line"
66
+ fi
67
+ }
68
+ if [ -f "$cache_file" ]; then
69
+ while IFS= read -r line || [ -n "$line" ]; do
70
+ _substatus_print_line "$line"
71
+ done < "$cache_file"
72
+ fi
50
73
  now=$(date +%s)
51
74
  cache_age=999999
52
75
  if [ -f "$cache_file" ]; then
@@ -59,7 +82,11 @@ append_substatus() {
59
82
  # over a minute old, so a slow but healthy command is never duplicated.
60
83
  if [ -d "$lock_dir" ]; then
61
84
  lock_age=$(( now - $(_substatus_mtime "$lock_dir") ))
62
- if [ "$lock_age" -gt 60 ]; then
85
+ # A refresh killed alongside its parent leaves this lock behind. The
86
+ # window must be short enough that a fresh session recovers within a
87
+ # few ticks instead of rendering no sub-status at all, but longer than
88
+ # a healthy slow command's runtime so it is never duplicated.
89
+ if [ "$lock_age" -gt 20 ]; then
63
90
  rmdir "$lock_dir" 2>/dev/null || rm -rf "$lock_dir" 2>/dev/null
64
91
  fi
65
92
  fi
@@ -85,3 +112,18 @@ append_substatus() {
85
112
  fi
86
113
  ) </dev/null > /dev/null 2>/dev/null &
87
114
  }
115
+
116
+ # Claude Code kills the statusline process when the next render starts, and a
117
+ # plain `&` child stays in that process group — so the refresh was being killed
118
+ # mid-write, leaving a held lock and a 0-byte temp file behind. A session that
119
+ # lost the race that way never rendered a sub-status at all.
120
+ #
121
+ # setsid detaches into a new session so the refresh survives; it is Linux-only,
122
+ # so fall back to nohup (which at least survives SIGHUP) on macOS.
123
+ _substatus_detach() {
124
+ if command -v setsid >/dev/null 2>&1; then
125
+ setsid "$@" </dev/null >/dev/null 2>&1 &
126
+ else
127
+ nohup "$@" </dev/null >/dev/null 2>&1 &
128
+ fi
129
+ }
@@ -1,42 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Post-install check: warn if bun is unavailable.
4
- * Installation must succeed for Node-only Pi/OMP consumers; Claude-only commands
5
- * will diagnose bun at runtime.
6
- */
7
-
8
- const { spawn } = require("child_process");
9
-
10
- function checkBun() {
11
- return new Promise((resolve) => {
12
- const proc = spawn("bun", ["--version"], { stdio: "pipe" });
13
- let output = "";
14
- proc.stdout.on("data", (data) => {
15
- output += data.toString();
16
- });
17
- proc.on("close", (code) => {
18
- if (code === 0) {
19
- console.log(`✓ bun ${output.trim()} detected`);
20
- resolve(true);
21
- } else {
22
- console.warn(
23
- "Bun is required only for Claude-only commands; install it from https://bun.sh or run `npm install -g bun`."
24
- );
25
- resolve(false);
26
- }
27
- });
28
- proc.on("error", () => {
29
- console.warn(
30
- "Bun is required only for Claude-only commands; install it from https://bun.sh or run `npm install -g bun`."
31
- );
32
- resolve(false);
33
- });
34
- });
35
- }
36
-
37
- checkBun().then((ok) => {
38
- if (!ok) {
39
- console.warn("Install completed, but bun is required to run Claude-only commands.");
40
- }
41
- process.exit(0);
42
- });