@towles/tool 0.0.107 → 0.0.108

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 (76) hide show
  1. package/README.md +7 -1
  2. package/package.json +2 -1
  3. package/plugins/tt-agentboard/README.md +160 -0
  4. package/plugins/tt-agentboard/apps/server/package.json +20 -0
  5. package/plugins/tt-agentboard/apps/server/src/main.ts +60 -0
  6. package/plugins/tt-agentboard/apps/tui/build.ts +11 -0
  7. package/plugins/tt-agentboard/apps/tui/bunfig.toml +1 -0
  8. package/plugins/tt-agentboard/apps/tui/package.json +23 -0
  9. package/plugins/tt-agentboard/apps/tui/scripts/sessionizer.sh +36 -0
  10. package/plugins/tt-agentboard/apps/tui/src/components/DetailPanel.tsx +350 -0
  11. package/plugins/tt-agentboard/apps/tui/src/components/DiffStats.tsx +33 -0
  12. package/plugins/tt-agentboard/apps/tui/src/components/SessionCard.tsx +177 -0
  13. package/plugins/tt-agentboard/apps/tui/src/components/StatusBar.tsx +49 -0
  14. package/plugins/tt-agentboard/apps/tui/src/constants.ts +46 -0
  15. package/plugins/tt-agentboard/apps/tui/src/detail-panel-height.ts +21 -0
  16. package/plugins/tt-agentboard/apps/tui/src/index.tsx +880 -0
  17. package/plugins/tt-agentboard/apps/tui/src/mux-context.ts +61 -0
  18. package/plugins/tt-agentboard/apps/tui/tsconfig.json +15 -0
  19. package/plugins/tt-agentboard/bun.lock +444 -0
  20. package/plugins/tt-agentboard/package.json +26 -0
  21. package/plugins/tt-agentboard/packages/mux-tmux/package.json +14 -0
  22. package/plugins/tt-agentboard/packages/mux-tmux/src/client.ts +550 -0
  23. package/plugins/tt-agentboard/packages/mux-tmux/src/index.ts +18 -0
  24. package/plugins/tt-agentboard/packages/mux-tmux/src/provider.ts +259 -0
  25. package/plugins/tt-agentboard/packages/mux-tmux/tsconfig.json +13 -0
  26. package/plugins/tt-agentboard/packages/runtime/package.json +14 -0
  27. package/plugins/tt-agentboard/packages/runtime/src/agents/tracker.ts +233 -0
  28. package/plugins/tt-agentboard/packages/runtime/src/agents/watchers/amp.ts +316 -0
  29. package/plugins/tt-agentboard/packages/runtime/src/agents/watchers/claude-code.ts +374 -0
  30. package/plugins/tt-agentboard/packages/runtime/src/agents/watchers/codex.ts +364 -0
  31. package/plugins/tt-agentboard/packages/runtime/src/agents/watchers/opencode.ts +249 -0
  32. package/plugins/tt-agentboard/packages/runtime/src/config.ts +70 -0
  33. package/plugins/tt-agentboard/packages/runtime/src/contracts/agent-watcher.ts +38 -0
  34. package/plugins/tt-agentboard/packages/runtime/src/contracts/agent.ts +16 -0
  35. package/plugins/tt-agentboard/packages/runtime/src/contracts/index.ts +3 -0
  36. package/plugins/tt-agentboard/packages/runtime/src/contracts/mux.ts +148 -0
  37. package/plugins/tt-agentboard/packages/runtime/src/debug.ts +19 -0
  38. package/plugins/tt-agentboard/packages/runtime/src/index.ts +69 -0
  39. package/plugins/tt-agentboard/packages/runtime/src/mux/detect.ts +20 -0
  40. package/plugins/tt-agentboard/packages/runtime/src/mux/registry.ts +45 -0
  41. package/plugins/tt-agentboard/packages/runtime/src/plugins/loader.ts +152 -0
  42. package/plugins/tt-agentboard/packages/runtime/src/server/context.ts +112 -0
  43. package/plugins/tt-agentboard/packages/runtime/src/server/git-info.ts +164 -0
  44. package/plugins/tt-agentboard/packages/runtime/src/server/index.ts +1753 -0
  45. package/plugins/tt-agentboard/packages/runtime/src/server/launcher.ts +71 -0
  46. package/plugins/tt-agentboard/packages/runtime/src/server/metadata-store.ts +86 -0
  47. package/plugins/tt-agentboard/packages/runtime/src/server/pane-scanner.ts +327 -0
  48. package/plugins/tt-agentboard/packages/runtime/src/server/port-scanner.ts +155 -0
  49. package/plugins/tt-agentboard/packages/runtime/src/server/session-order.ts +127 -0
  50. package/plugins/tt-agentboard/packages/runtime/src/server/sidebar-manager.ts +232 -0
  51. package/plugins/tt-agentboard/packages/runtime/src/server/sidebar-width-sync.ts +66 -0
  52. package/plugins/tt-agentboard/packages/runtime/src/shared.ts +179 -0
  53. package/plugins/tt-agentboard/packages/runtime/src/themes.ts +750 -0
  54. package/plugins/tt-agentboard/packages/runtime/test/config.test.ts +83 -0
  55. package/plugins/tt-agentboard/packages/runtime/test/tracker.test.ts +172 -0
  56. package/plugins/tt-agentboard/packages/runtime/tsconfig.json +13 -0
  57. package/plugins/tt-agentboard/tsconfig.json +19 -0
  58. package/plugins/tt-auto-claude/.claude-plugin/plugin.json +8 -0
  59. package/plugins/tt-auto-claude/commands/create-issue.md +20 -0
  60. package/plugins/tt-auto-claude/commands/list.md +21 -0
  61. package/plugins/tt-auto-claude/skills/auto-claude/SKILL.md +71 -0
  62. package/plugins/tt-core/.claude-plugin/plugin.json +8 -0
  63. package/plugins/tt-core/README.md +18 -0
  64. package/plugins/tt-core/commands/improve-architecture.md +66 -0
  65. package/plugins/tt-core/commands/interview-me.md +38 -0
  66. package/plugins/tt-core/commands/prd-to-issues.md +49 -0
  67. package/plugins/tt-core/commands/refine-text.md +30 -0
  68. package/plugins/tt-core/commands/task.md +37 -0
  69. package/plugins/tt-core/commands/tdd.md +69 -0
  70. package/plugins/tt-core/commands/write-prd.md +69 -0
  71. package/plugins/tt-core/promptfooconfig.interview-me.yaml +155 -0
  72. package/plugins/tt-core/promptfooconfig.refine-text.yaml +242 -0
  73. package/plugins/tt-core/promptfooconfig.tdd.yaml +144 -0
  74. package/plugins/tt-core/promptfooconfig.write-prd.yaml +145 -0
  75. package/plugins/tt-core/skills/towles-tool/SKILL.md +35 -0
  76. package/src/commands/agentboard.ts +19 -2
@@ -0,0 +1,164 @@
1
+ import { existsSync, watch } from "node:fs";
2
+ import type { FSWatcher } from "node:fs";
3
+ import { join } from "node:path";
4
+ import type { SessionData } from "../shared";
5
+
6
+ // --- Shell helper (for git commands only) ---
7
+
8
+ export function shell(cmd: string[]): string {
9
+ try {
10
+ const result = Bun.spawnSync(cmd, { stdout: "pipe", stderr: "pipe" });
11
+ return result.stdout.toString().trim();
12
+ } catch {
13
+ return "";
14
+ }
15
+ }
16
+
17
+ // --- Git helpers ---
18
+
19
+ export interface GitInfo {
20
+ branch: string;
21
+ dirty: boolean;
22
+ isWorktree: boolean;
23
+ filesChanged: number;
24
+ linesAdded: number;
25
+ linesRemoved: number;
26
+ /** Positive = ahead of origin/main, negative = behind */
27
+ commitsDelta: number;
28
+ }
29
+
30
+ const gitInfoCache = new Map<string, { info: GitInfo; ts: number }>();
31
+ const GIT_CACHE_TTL_MS = 5000;
32
+
33
+ export function getGitInfo(dir: string): GitInfo {
34
+ const empty: GitInfo = {
35
+ branch: "",
36
+ dirty: false,
37
+ isWorktree: false,
38
+ filesChanged: 0,
39
+ linesAdded: 0,
40
+ linesRemoved: 0,
41
+ commitsDelta: 0,
42
+ };
43
+ if (!dir) return empty;
44
+
45
+ const cached = gitInfoCache.get(dir);
46
+ if (cached && Date.now() - cached.ts < GIT_CACHE_TTL_MS) return cached.info;
47
+
48
+ const branch = shell(["git", "-C", dir, "rev-parse", "--abbrev-ref", "HEAD"]);
49
+ if (!branch) return empty;
50
+ const gitDir = shell(["git", "-C", dir, "rev-parse", "--git-dir"]);
51
+ const statusOut = shell(["git", "-C", dir, "status", "--porcelain"]);
52
+
53
+ // Uncommitted diff stats (unstaged + staged)
54
+ let linesAdded = 0;
55
+ let linesRemoved = 0;
56
+ for (const cmd of [
57
+ ["git", "-C", dir, "diff", "--numstat"],
58
+ ["git", "-C", dir, "diff", "--cached", "--numstat"],
59
+ ]) {
60
+ const out = shell(cmd);
61
+ if (!out) continue;
62
+ for (const line of out.split("\n")) {
63
+ const [added, removed] = line.split("\t");
64
+ if (added === "-" || removed === "-") continue; // binary
65
+ linesAdded += Number(added) || 0;
66
+ linesRemoved += Number(removed) || 0;
67
+ }
68
+ }
69
+
70
+ // Commits ahead/behind origin/main
71
+ // Commits ahead(+) or behind(-) origin/main
72
+ let commitsDelta = 0;
73
+ const originMain = shell(["git", "-C", dir, "rev-parse", "--verify", "origin/main"])
74
+ ? "origin/main"
75
+ : "origin/master";
76
+ const aheadBehind = shell([
77
+ "git",
78
+ "-C",
79
+ dir,
80
+ "rev-list",
81
+ "--left-right",
82
+ "--count",
83
+ `${originMain}...HEAD`,
84
+ ]);
85
+ if (aheadBehind) {
86
+ const [behind, ahead] = aheadBehind.split("\t");
87
+ commitsDelta = (Number(ahead) || 0) - (Number(behind) || 0);
88
+ }
89
+
90
+ const filesChanged = statusOut ? statusOut.split("\n").filter(Boolean).length : 0;
91
+
92
+ const info: GitInfo = {
93
+ branch,
94
+ dirty: statusOut.length > 0,
95
+ isWorktree: gitDir.includes("/worktrees/"),
96
+ filesChanged,
97
+ linesAdded,
98
+ linesRemoved,
99
+ commitsDelta,
100
+ };
101
+ gitInfoCache.set(dir, { info, ts: Date.now() });
102
+ return info;
103
+ }
104
+
105
+ export function invalidateGitCache(dir?: string): void {
106
+ if (dir) gitInfoCache.delete(dir);
107
+ else gitInfoCache.clear();
108
+ }
109
+
110
+ // --- Git HEAD file watchers ---
111
+
112
+ const gitHeadWatchers = new Map<string, FSWatcher>();
113
+
114
+ function resolveGitHeadPath(dir: string): string | null {
115
+ if (!dir) return null;
116
+ const gitDir = shell(["git", "-C", dir, "rev-parse", "--git-dir"]);
117
+ if (!gitDir) return null;
118
+ const absGitDir = gitDir.startsWith("/") ? gitDir : join(dir, gitDir);
119
+ const headPath = join(absGitDir, "HEAD");
120
+ return existsSync(headPath) ? headPath : null;
121
+ }
122
+
123
+ let debounceTimer: ReturnType<typeof setTimeout> | null = null;
124
+
125
+ function onGitHeadChange(broadcastFn: () => void): void {
126
+ if (debounceTimer) return;
127
+ debounceTimer = setTimeout(() => {
128
+ debounceTimer = null;
129
+ invalidateGitCache();
130
+ broadcastFn();
131
+ }, 200);
132
+ }
133
+
134
+ export function syncGitWatchers(sessions: SessionData[], broadcastFn: () => void): void {
135
+ const currentDirs = new Set<string>();
136
+ for (const s of sessions) {
137
+ if (s.dir) currentDirs.add(s.dir);
138
+ }
139
+
140
+ for (const [dir, watcher] of gitHeadWatchers) {
141
+ if (!currentDirs.has(dir)) {
142
+ watcher.close();
143
+ gitHeadWatchers.delete(dir);
144
+ }
145
+ }
146
+
147
+ for (const dir of currentDirs) {
148
+ if (gitHeadWatchers.has(dir)) continue;
149
+ const headPath = resolveGitHeadPath(dir);
150
+ if (!headPath) continue;
151
+ try {
152
+ const watcher = watch(headPath, () => onGitHeadChange(broadcastFn));
153
+ gitHeadWatchers.set(dir, watcher);
154
+ } catch {
155
+ /* ignore */
156
+ }
157
+ }
158
+ }
159
+
160
+ export function teardownGitWatchers(): void {
161
+ if (debounceTimer) clearTimeout(debounceTimer);
162
+ for (const watcher of gitHeadWatchers.values()) watcher.close();
163
+ gitHeadWatchers.clear();
164
+ }