aimux-cli 0.1.0

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 (207) hide show
  1. package/README.md +743 -0
  2. package/bin/aimux +2 -0
  3. package/dist/agent-events.d.ts +20 -0
  4. package/dist/agent-events.js +2 -0
  5. package/dist/agent-events.js.map +1 -0
  6. package/dist/agent-message-parts.d.ts +17 -0
  7. package/dist/agent-message-parts.js +31 -0
  8. package/dist/agent-message-parts.js.map +1 -0
  9. package/dist/agent-output-parser.d.ts +16 -0
  10. package/dist/agent-output-parser.js +229 -0
  11. package/dist/agent-output-parser.js.map +1 -0
  12. package/dist/agent-tracker.d.ts +9 -0
  13. package/dist/agent-tracker.js +144 -0
  14. package/dist/agent-tracker.js.map +1 -0
  15. package/dist/agent-watcher.d.ts +15 -0
  16. package/dist/agent-watcher.js +2 -0
  17. package/dist/agent-watcher.js.map +1 -0
  18. package/dist/attachment-store.d.ts +35 -0
  19. package/dist/attachment-store.js +129 -0
  20. package/dist/attachment-store.js.map +1 -0
  21. package/dist/builtin-metadata-watchers.d.ts +2 -0
  22. package/dist/builtin-metadata-watchers.js +275 -0
  23. package/dist/builtin-metadata-watchers.js.map +1 -0
  24. package/dist/claude-hooks.d.ts +29 -0
  25. package/dist/claude-hooks.js +106 -0
  26. package/dist/claude-hooks.js.map +1 -0
  27. package/dist/config.d.ts +78 -0
  28. package/dist/config.js +172 -0
  29. package/dist/config.js.map +1 -0
  30. package/dist/context/compactor.d.ts +20 -0
  31. package/dist/context/compactor.js +212 -0
  32. package/dist/context/compactor.js.map +1 -0
  33. package/dist/context/context-bridge.d.ts +67 -0
  34. package/dist/context/context-bridge.js +471 -0
  35. package/dist/context/context-bridge.js.map +1 -0
  36. package/dist/context/context-file.d.ts +11 -0
  37. package/dist/context/context-file.js +93 -0
  38. package/dist/context/context-file.js.map +1 -0
  39. package/dist/context/history.d.ts +40 -0
  40. package/dist/context/history.js +108 -0
  41. package/dist/context/history.js.map +1 -0
  42. package/dist/daemon.d.ts +39 -0
  43. package/dist/daemon.js +344 -0
  44. package/dist/daemon.js.map +1 -0
  45. package/dist/dashboard-session-registry.d.ts +47 -0
  46. package/dist/dashboard-session-registry.js +161 -0
  47. package/dist/dashboard-session-registry.js.map +1 -0
  48. package/dist/dashboard-state.d.ts +18 -0
  49. package/dist/dashboard-state.js +26 -0
  50. package/dist/dashboard-state.js.map +1 -0
  51. package/dist/dashboard.d.ts +118 -0
  52. package/dist/dashboard.js +91 -0
  53. package/dist/dashboard.js.map +1 -0
  54. package/dist/debug.d.ts +7 -0
  55. package/dist/debug.js +41 -0
  56. package/dist/debug.js.map +1 -0
  57. package/dist/fast-control.d.ts +45 -0
  58. package/dist/fast-control.js +174 -0
  59. package/dist/fast-control.js.map +1 -0
  60. package/dist/hotkeys.d.ts +44 -0
  61. package/dist/hotkeys.js +118 -0
  62. package/dist/hotkeys.js.map +1 -0
  63. package/dist/http-client.d.ts +10 -0
  64. package/dist/http-client.js +54 -0
  65. package/dist/http-client.js.map +1 -0
  66. package/dist/instance-directory.d.ts +32 -0
  67. package/dist/instance-directory.js +82 -0
  68. package/dist/instance-directory.js.map +1 -0
  69. package/dist/instance-registry.d.ts +38 -0
  70. package/dist/instance-registry.js +208 -0
  71. package/dist/instance-registry.js.map +1 -0
  72. package/dist/key-parser.d.ts +30 -0
  73. package/dist/key-parser.js +272 -0
  74. package/dist/key-parser.js.map +1 -0
  75. package/dist/last-used.d.ts +31 -0
  76. package/dist/last-used.js +93 -0
  77. package/dist/last-used.js.map +1 -0
  78. package/dist/main.d.ts +1 -0
  79. package/dist/main.js +2483 -0
  80. package/dist/main.js.map +1 -0
  81. package/dist/metadata-server.d.ts +268 -0
  82. package/dist/metadata-server.js +1379 -0
  83. package/dist/metadata-server.js.map +1 -0
  84. package/dist/metadata-store.d.ts +80 -0
  85. package/dist/metadata-store.js +87 -0
  86. package/dist/metadata-store.js.map +1 -0
  87. package/dist/multiplexer.d.ts +471 -0
  88. package/dist/multiplexer.js +5714 -0
  89. package/dist/multiplexer.js.map +1 -0
  90. package/dist/notification-context.d.ts +18 -0
  91. package/dist/notification-context.js +68 -0
  92. package/dist/notification-context.js.map +1 -0
  93. package/dist/notifications.d.ts +38 -0
  94. package/dist/notifications.js +111 -0
  95. package/dist/notifications.js.map +1 -0
  96. package/dist/notify.d.ts +10 -0
  97. package/dist/notify.js +62 -0
  98. package/dist/notify.js.map +1 -0
  99. package/dist/orchestration-actions.d.ts +76 -0
  100. package/dist/orchestration-actions.js +310 -0
  101. package/dist/orchestration-actions.js.map +1 -0
  102. package/dist/orchestration-dispatcher.d.ts +22 -0
  103. package/dist/orchestration-dispatcher.js +49 -0
  104. package/dist/orchestration-dispatcher.js.map +1 -0
  105. package/dist/orchestration-routing.d.ts +20 -0
  106. package/dist/orchestration-routing.js +78 -0
  107. package/dist/orchestration-routing.js.map +1 -0
  108. package/dist/orchestration.d.ts +26 -0
  109. package/dist/orchestration.js +110 -0
  110. package/dist/orchestration.js.map +1 -0
  111. package/dist/osc-notifications.d.ts +15 -0
  112. package/dist/osc-notifications.js +180 -0
  113. package/dist/osc-notifications.js.map +1 -0
  114. package/dist/paths.d.ts +55 -0
  115. package/dist/paths.js +259 -0
  116. package/dist/paths.js.map +1 -0
  117. package/dist/plugin-runtime.d.ts +46 -0
  118. package/dist/plugin-runtime.js +180 -0
  119. package/dist/plugin-runtime.js.map +1 -0
  120. package/dist/project-events.d.ts +36 -0
  121. package/dist/project-events.js +63 -0
  122. package/dist/project-events.js.map +1 -0
  123. package/dist/project-scanner.d.ts +38 -0
  124. package/dist/project-scanner.js +243 -0
  125. package/dist/project-scanner.js.map +1 -0
  126. package/dist/project-service-manifest.d.ts +18 -0
  127. package/dist/project-service-manifest.js +56 -0
  128. package/dist/project-service-manifest.js.map +1 -0
  129. package/dist/recency.d.ts +2 -0
  130. package/dist/recency.js +34 -0
  131. package/dist/recency.js.map +1 -0
  132. package/dist/recorder.d.ts +14 -0
  133. package/dist/recorder.js +130 -0
  134. package/dist/recorder.js.map +1 -0
  135. package/dist/session-bootstrap.d.ts +45 -0
  136. package/dist/session-bootstrap.js +436 -0
  137. package/dist/session-bootstrap.js.map +1 -0
  138. package/dist/session-message-history.d.ts +27 -0
  139. package/dist/session-message-history.js +105 -0
  140. package/dist/session-message-history.js.map +1 -0
  141. package/dist/session-runtime.d.ts +44 -0
  142. package/dist/session-runtime.js +56 -0
  143. package/dist/session-runtime.js.map +1 -0
  144. package/dist/session-semantics.d.ts +35 -0
  145. package/dist/session-semantics.js +110 -0
  146. package/dist/session-semantics.js.map +1 -0
  147. package/dist/status-detector.d.ts +17 -0
  148. package/dist/status-detector.js +67 -0
  149. package/dist/status-detector.js.map +1 -0
  150. package/dist/statusline-model.d.ts +103 -0
  151. package/dist/statusline-model.js +177 -0
  152. package/dist/statusline-model.js.map +1 -0
  153. package/dist/task-dispatcher.d.ts +63 -0
  154. package/dist/task-dispatcher.js +210 -0
  155. package/dist/task-dispatcher.js.map +1 -0
  156. package/dist/task-workflow.d.ts +13 -0
  157. package/dist/task-workflow.js +153 -0
  158. package/dist/task-workflow.js.map +1 -0
  159. package/dist/tasks.d.ts +60 -0
  160. package/dist/tasks.js +120 -0
  161. package/dist/tasks.js.map +1 -0
  162. package/dist/team.d.ts +28 -0
  163. package/dist/team.js +91 -0
  164. package/dist/team.js.map +1 -0
  165. package/dist/terminal-host.d.ts +10 -0
  166. package/dist/terminal-host.js +52 -0
  167. package/dist/terminal-host.js.map +1 -0
  168. package/dist/threads.d.ts +61 -0
  169. package/dist/threads.js +200 -0
  170. package/dist/threads.js.map +1 -0
  171. package/dist/tmux-doctor.d.ts +47 -0
  172. package/dist/tmux-doctor.js +112 -0
  173. package/dist/tmux-doctor.js.map +1 -0
  174. package/dist/tmux-runtime-manager.d.ts +164 -0
  175. package/dist/tmux-runtime-manager.js +794 -0
  176. package/dist/tmux-runtime-manager.js.map +1 -0
  177. package/dist/tmux-session-transport.d.ts +31 -0
  178. package/dist/tmux-session-transport.js +115 -0
  179. package/dist/tmux-session-transport.js.map +1 -0
  180. package/dist/tmux-statusline.d.ts +17 -0
  181. package/dist/tmux-statusline.js +166 -0
  182. package/dist/tmux-statusline.js.map +1 -0
  183. package/dist/tool-output-watchers.d.ts +10 -0
  184. package/dist/tool-output-watchers.js +190 -0
  185. package/dist/tool-output-watchers.js.map +1 -0
  186. package/dist/tui/render/box.d.ts +1 -0
  187. package/dist/tui/render/box.js +20 -0
  188. package/dist/tui/render/box.js.map +1 -0
  189. package/dist/tui/render/text.d.ts +8 -0
  190. package/dist/tui/render/text.js +92 -0
  191. package/dist/tui/render/text.js.map +1 -0
  192. package/dist/tui/screens/dashboard-renderers.d.ts +23 -0
  193. package/dist/tui/screens/dashboard-renderers.js +411 -0
  194. package/dist/tui/screens/dashboard-renderers.js.map +1 -0
  195. package/dist/tui/screens/overlay-renderers.d.ts +10 -0
  196. package/dist/tui/screens/overlay-renderers.js +274 -0
  197. package/dist/tui/screens/overlay-renderers.js.map +1 -0
  198. package/dist/tui/screens/subscreen-renderers.d.ts +9 -0
  199. package/dist/tui/screens/subscreen-renderers.js +327 -0
  200. package/dist/tui/screens/subscreen-renderers.js.map +1 -0
  201. package/dist/workflow.d.ts +19 -0
  202. package/dist/workflow.js +111 -0
  203. package/dist/workflow.js.map +1 -0
  204. package/dist/worktree.d.ts +23 -0
  205. package/dist/worktree.js +101 -0
  206. package/dist/worktree.js.map +1 -0
  207. package/package.json +70 -0
@@ -0,0 +1,56 @@
1
+ export class SessionRuntime {
2
+ transport;
3
+ hooks;
4
+ startedAt;
5
+ constructor(transport, startTime, hooks = {}) {
6
+ this.transport = transport;
7
+ this.hooks = hooks;
8
+ this.startedAt = startTime;
9
+ transport.onData((data) => {
10
+ hooks.onEvent?.({ type: "output", data });
11
+ });
12
+ transport.onExit((code) => {
13
+ hooks.onEvent?.({ type: "exit", code });
14
+ });
15
+ }
16
+ get id() {
17
+ return this.transport.id;
18
+ }
19
+ get command() {
20
+ return this.transport.command;
21
+ }
22
+ get backendSessionId() {
23
+ return this.transport.backendSessionId;
24
+ }
25
+ set backendSessionId(value) {
26
+ this.transport.backendSessionId = value;
27
+ }
28
+ get exited() {
29
+ return this.transport.exited;
30
+ }
31
+ get exitCode() {
32
+ return this.transport.exitCode;
33
+ }
34
+ get status() {
35
+ return this.transport.status;
36
+ }
37
+ get startTime() {
38
+ return this.startedAt;
39
+ }
40
+ write(data) {
41
+ this.transport.write(data);
42
+ }
43
+ resize(cols, rows) {
44
+ this.transport.resize(cols, rows);
45
+ }
46
+ onExit(cb) {
47
+ this.transport.onExit(cb);
48
+ }
49
+ kill() {
50
+ this.transport.kill();
51
+ }
52
+ destroy() {
53
+ this.transport.destroy();
54
+ }
55
+ }
56
+ //# sourceMappingURL=session-runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-runtime.js","sourceRoot":"","sources":["../src/session-runtime.ts"],"names":[],"mappings":"AAuBA,MAAM,OAAO,cAAc;IAId;IAED;IALO,SAAS,CAAU;IAEpC,YACW,SAA2B,EACpC,SAA6B,EACrB,QAA6B,EAAE;QAF9B,cAAS,GAAT,SAAS,CAAkB;QAE5B,UAAK,GAAL,KAAK,CAA0B;QAEvC,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAE3B,SAAS,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;YACxB,KAAK,CAAC,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5C,CAAC,CAAC,CAAC;QAEH,SAAS,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;YACxB,KAAK,CAAC,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1C,CAAC,CAAC,CAAC;IACL,CAAC;IAED,IAAI,EAAE;QACJ,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;IAC3B,CAAC;IAED,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;IAChC,CAAC;IAED,IAAI,gBAAgB;QAClB,OAAO,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAC;IACzC,CAAC;IAED,IAAI,gBAAgB,CAAC,KAAyB;QAC5C,IAAI,CAAC,SAAS,CAAC,gBAAgB,GAAG,KAAK,CAAC;IAC1C,CAAC;IAED,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;IAC/B,CAAC;IAED,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;IACjC,CAAC;IAED,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;IAC/B,CAAC;IAED,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED,KAAK,CAAC,IAAY;QAChB,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;IAED,MAAM,CAAC,IAAY,EAAE,IAAY;QAC/B,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACpC,CAAC;IAED,MAAM,CAAC,EAA0B;QAC/B,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC5B,CAAC;IAED,IAAI;QACF,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;IACxB,CAAC;IAED,OAAO;QACL,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC;CACF"}
@@ -0,0 +1,35 @@
1
+ import type { AgentActivityState, AgentAttentionState } from "./agent-events.js";
2
+ import type { DashboardSessionStatus } from "./dashboard.js";
3
+ export type SessionAvailability = "available" | "busy" | "needs_input" | "blocked" | "offline";
4
+ export type SessionWorkflowState = "none" | "waiting_on_me" | "waiting_on_them" | "blocked";
5
+ export interface SessionSemanticState {
6
+ activity?: AgentActivityState;
7
+ attention: AgentAttentionState;
8
+ availability: SessionAvailability;
9
+ workflowState: SessionWorkflowState;
10
+ unreadCount: number;
11
+ pendingDeliveryCount: number;
12
+ waitingOnMeCount: number;
13
+ waitingOnThemCount: number;
14
+ blockedCount: number;
15
+ familyCount: number;
16
+ hasActiveTask: boolean;
17
+ }
18
+ export interface DeriveSessionSemanticsInput {
19
+ status: DashboardSessionStatus;
20
+ activity?: AgentActivityState;
21
+ attention?: AgentAttentionState;
22
+ unseenCount?: number;
23
+ threadUnreadCount?: number;
24
+ threadPendingCount?: number;
25
+ threadWaitingOnMeCount?: number;
26
+ threadWaitingOnThemCount?: number;
27
+ workflowOnMeCount?: number;
28
+ workflowBlockedCount?: number;
29
+ workflowFamilyCount?: number;
30
+ hasActiveTask?: boolean;
31
+ }
32
+ export declare function deriveSessionSemantics(input: DeriveSessionSemanticsInput): SessionSemanticState;
33
+ export declare function sessionSemanticStatusLabel(semantic: SessionSemanticState, fallbackStatus: DashboardSessionStatus): string;
34
+ export declare function sessionSemanticAttentionScore(semantic: SessionSemanticState): number;
35
+ export declare function sessionSemanticCompactHint(semantic: SessionSemanticState): string | null;
@@ -0,0 +1,110 @@
1
+ export function deriveSessionSemantics(input) {
2
+ const attention = input.attention ?? "normal";
3
+ const unreadCount = Math.max(0, input.unseenCount ?? 0, input.threadUnreadCount ?? 0);
4
+ const pendingDeliveryCount = Math.max(0, input.threadPendingCount ?? 0);
5
+ const waitingOnMeCount = Math.max(0, input.threadWaitingOnMeCount ?? 0, input.workflowOnMeCount ?? 0);
6
+ const waitingOnThemCount = Math.max(0, input.threadWaitingOnThemCount ?? 0);
7
+ const blockedCount = Math.max(0, input.workflowBlockedCount ?? 0);
8
+ const familyCount = Math.max(0, input.workflowFamilyCount ?? 0);
9
+ const hasActiveTask = Boolean(input.hasActiveTask);
10
+ let workflowState = "none";
11
+ if (blockedCount > 0 || attention === "blocked") {
12
+ workflowState = "blocked";
13
+ }
14
+ else if (waitingOnMeCount > 0) {
15
+ workflowState = "waiting_on_me";
16
+ }
17
+ else if (waitingOnThemCount > 0) {
18
+ workflowState = "waiting_on_them";
19
+ }
20
+ let availability;
21
+ if (input.status === "offline" || input.status === "exited") {
22
+ availability = "offline";
23
+ }
24
+ else if (attention === "error" || attention === "blocked" || workflowState === "blocked") {
25
+ availability = "blocked";
26
+ }
27
+ else if (attention === "needs_input" || workflowState === "waiting_on_me") {
28
+ availability = "needs_input";
29
+ }
30
+ else if (input.status === "running" ||
31
+ input.status === "waiting" ||
32
+ input.activity === "running" ||
33
+ input.activity === "waiting" ||
34
+ hasActiveTask ||
35
+ waitingOnThemCount > 0) {
36
+ availability = "busy";
37
+ }
38
+ else {
39
+ availability = "available";
40
+ }
41
+ return {
42
+ activity: input.activity,
43
+ attention,
44
+ availability,
45
+ workflowState,
46
+ unreadCount,
47
+ pendingDeliveryCount,
48
+ waitingOnMeCount,
49
+ waitingOnThemCount,
50
+ blockedCount,
51
+ familyCount,
52
+ hasActiveTask,
53
+ };
54
+ }
55
+ export function sessionSemanticStatusLabel(semantic, fallbackStatus) {
56
+ if (semantic.attention === "error")
57
+ return "error";
58
+ if (semantic.workflowState === "blocked" || semantic.attention === "blocked")
59
+ return "blocked";
60
+ if (semantic.availability === "needs_input")
61
+ return "needs input";
62
+ if (semantic.activity === "done")
63
+ return "done";
64
+ if (semantic.activity === "waiting")
65
+ return "waiting";
66
+ if (semantic.activity === "running")
67
+ return "working";
68
+ if (semantic.activity === "interrupted")
69
+ return "interrupted";
70
+ if (semantic.availability === "busy") {
71
+ if (fallbackStatus === "waiting")
72
+ return "thinking";
73
+ if (fallbackStatus === "running")
74
+ return "working";
75
+ }
76
+ if (fallbackStatus === "waiting")
77
+ return "thinking";
78
+ return fallbackStatus;
79
+ }
80
+ export function sessionSemanticAttentionScore(semantic) {
81
+ if (semantic.attention === "error")
82
+ return 5;
83
+ if (semantic.availability === "needs_input")
84
+ return 4;
85
+ if (semantic.workflowState === "blocked" || semantic.attention === "blocked")
86
+ return 3;
87
+ if (semantic.unreadCount > 0 || semantic.pendingDeliveryCount > 0)
88
+ return 2;
89
+ if (semantic.activity === "done")
90
+ return 1;
91
+ return 0;
92
+ }
93
+ export function sessionSemanticCompactHint(semantic) {
94
+ if (semantic.attention === "error")
95
+ return "error";
96
+ if (semantic.workflowState === "blocked" || semantic.attention === "blocked")
97
+ return "blocked";
98
+ if (semantic.workflowState === "waiting_on_me" || semantic.availability === "needs_input")
99
+ return "on you";
100
+ if (semantic.workflowState === "waiting_on_them")
101
+ return "on them";
102
+ if (semantic.unreadCount > 0)
103
+ return `${Math.min(semantic.unreadCount, 99)} unread`;
104
+ if (semantic.pendingDeliveryCount > 0)
105
+ return `${Math.min(semantic.pendingDeliveryCount, 99)} pending`;
106
+ if (semantic.hasActiveTask && semantic.availability === "available")
107
+ return "task";
108
+ return null;
109
+ }
110
+ //# sourceMappingURL=session-semantics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-semantics.js","sourceRoot":"","sources":["../src/session-semantics.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ export type SessionStatus = "running" | "idle" | "waiting" | "exited" | "offline";
2
+ export declare class StatusDetector {
3
+ private lastOutputTime;
4
+ private lastStrippedLine;
5
+ private patterns;
6
+ private _status;
7
+ private idleTimer;
8
+ constructor(promptPatterns?: RegExp[]);
9
+ get status(): SessionStatus;
10
+ /**
11
+ * Feed stripped (no ANSI) output for analysis.
12
+ */
13
+ feed(strippedText: string): void;
14
+ private checkIdle;
15
+ markExited(): void;
16
+ destroy(): void;
17
+ }
@@ -0,0 +1,67 @@
1
+ // Generic patterns that look like prompts
2
+ const GENERIC_PROMPT = /[>$#%] $/m;
3
+ export class StatusDetector {
4
+ lastOutputTime = 0;
5
+ lastStrippedLine = "";
6
+ patterns;
7
+ _status = "running";
8
+ idleTimer = null;
9
+ constructor(promptPatterns = []) {
10
+ this.patterns = promptPatterns;
11
+ }
12
+ get status() {
13
+ return this._status;
14
+ }
15
+ /**
16
+ * Feed stripped (no ANSI) output for analysis.
17
+ */
18
+ feed(strippedText) {
19
+ this.lastOutputTime = Date.now();
20
+ this._status = "running";
21
+ // Track the last non-empty line
22
+ const lines = strippedText.split("\n");
23
+ for (let i = lines.length - 1; i >= 0; i--) {
24
+ if (lines[i].trim().length > 0) {
25
+ this.lastStrippedLine = lines[i];
26
+ break;
27
+ }
28
+ }
29
+ // Reset idle timer
30
+ if (this.idleTimer)
31
+ clearTimeout(this.idleTimer);
32
+ this.idleTimer = setTimeout(() => this.checkIdle(), 2000);
33
+ }
34
+ checkIdle() {
35
+ const elapsed = Date.now() - this.lastOutputTime;
36
+ if (elapsed < 2000)
37
+ return;
38
+ // Check tool-specific prompts from config
39
+ for (const pattern of this.patterns) {
40
+ if (pattern.test(this.lastStrippedLine)) {
41
+ this._status = "idle";
42
+ return;
43
+ }
44
+ }
45
+ // Check generic prompt pattern
46
+ if (GENERIC_PROMPT.test(this.lastStrippedLine)) {
47
+ this._status = "idle";
48
+ return;
49
+ }
50
+ // No prompt detected but output stopped — "waiting" (thinking/processing)
51
+ this._status = "waiting";
52
+ }
53
+ markExited() {
54
+ this._status = "exited";
55
+ if (this.idleTimer) {
56
+ clearTimeout(this.idleTimer);
57
+ this.idleTimer = null;
58
+ }
59
+ }
60
+ destroy() {
61
+ if (this.idleTimer) {
62
+ clearTimeout(this.idleTimer);
63
+ this.idleTimer = null;
64
+ }
65
+ }
66
+ }
67
+ //# sourceMappingURL=status-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status-detector.js","sourceRoot":"","sources":["../src/status-detector.ts"],"names":[],"mappings":"AAEA,0CAA0C;AAC1C,MAAM,cAAc,GAAG,WAAW,CAAC;AAEnC,MAAM,OAAO,cAAc;IACjB,cAAc,GAAG,CAAC,CAAC;IACnB,gBAAgB,GAAG,EAAE,CAAC;IACtB,QAAQ,CAAW;IACnB,OAAO,GAAkB,SAAS,CAAC;IACnC,SAAS,GAAyC,IAAI,CAAC;IAE/D,YAAY,iBAA2B,EAAE;QACvC,IAAI,CAAC,QAAQ,GAAG,cAAc,CAAC;IACjC,CAAC;IAED,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAED;;OAEG;IACH,IAAI,CAAC,YAAoB;QACvB,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACjC,IAAI,CAAC,OAAO,GAAG,SAAS,CAAC;QAEzB,gCAAgC;QAChC,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACvC,KAAK,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3C,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC/B,IAAI,CAAC,gBAAgB,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;gBACjC,MAAM;YACR,CAAC;QACH,CAAC;QAED,mBAAmB;QACnB,IAAI,IAAI,CAAC,SAAS;YAAE,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACjD,IAAI,CAAC,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,IAAI,CAAC,CAAC;IAC5D,CAAC;IAEO,SAAS;QACf,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,cAAc,CAAC;QACjD,IAAI,OAAO,GAAG,IAAI;YAAE,OAAO;QAE3B,0CAA0C;QAC1C,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACpC,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,EAAE,CAAC;gBACxC,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;gBACtB,OAAO;YACT,CAAC;QACH,CAAC;QAED,+BAA+B;QAC/B,IAAI,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,EAAE,CAAC;YAC/C,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;YACtB,OAAO;QACT,CAAC;QAED,0EAA0E;QAC1E,IAAI,CAAC,OAAO,GAAG,SAAS,CAAC;IAC3B,CAAC;IAED,UAAU;QACR,IAAI,CAAC,OAAO,GAAG,QAAQ,CAAC;QACxB,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAC7B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACxB,CAAC;IACH,CAAC;IAED,OAAO;QACL,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAC7B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACxB,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,103 @@
1
+ import type { AgentActivityState, AgentAttentionState } from "./agent-events.js";
2
+ import type { SessionSemanticState } from "./session-semantics.js";
3
+ export interface StatuslineSession {
4
+ id: string;
5
+ kind?: "agent" | "service";
6
+ tool: string;
7
+ label?: string;
8
+ tmuxWindowId?: string;
9
+ tmuxWindowIndex?: number;
10
+ windowName?: string;
11
+ headline?: string;
12
+ status?: string;
13
+ role?: string;
14
+ active?: boolean;
15
+ worktreePath?: string;
16
+ semantic?: SessionSemanticState;
17
+ }
18
+ export declare function compactSessionTitle(session: Pick<StatuslineSession, "kind" | "tool" | "label" | "role" | "id">): string;
19
+ export interface StatuslineMetadataEntry {
20
+ status?: {
21
+ text: string;
22
+ tone?: string;
23
+ };
24
+ progress?: {
25
+ current: number;
26
+ total: number;
27
+ label?: string;
28
+ };
29
+ logs?: Array<{
30
+ message: string;
31
+ source?: string;
32
+ tone?: string;
33
+ ts: string;
34
+ }>;
35
+ context?: {
36
+ cwd?: string;
37
+ worktreePath?: string;
38
+ worktreeName?: string;
39
+ branch?: string;
40
+ pr?: {
41
+ number?: number;
42
+ title?: string;
43
+ url?: string;
44
+ headRef?: string;
45
+ baseRef?: string;
46
+ };
47
+ repo?: {
48
+ owner?: string;
49
+ name?: string;
50
+ remote?: string;
51
+ };
52
+ };
53
+ derived?: {
54
+ activity?: AgentActivityState;
55
+ attention?: AgentAttentionState;
56
+ unseenCount?: number;
57
+ services?: Array<{
58
+ label?: string;
59
+ url?: string;
60
+ port?: number;
61
+ }>;
62
+ };
63
+ updatedAt?: string;
64
+ }
65
+ export interface StatuslineData {
66
+ project?: string;
67
+ dashboardScreen?: "dashboard" | "plans" | "graveyard" | "activity" | "threads" | "workflow" | "help";
68
+ sessions?: StatuslineSession[];
69
+ metadata?: Record<string, StatuslineMetadataEntry>;
70
+ controlPlane?: {
71
+ daemonAlive?: boolean;
72
+ projectServiceAlive?: boolean;
73
+ };
74
+ tasks?: {
75
+ pending?: number;
76
+ assigned?: number;
77
+ };
78
+ flash?: string | null;
79
+ updatedAt?: string;
80
+ }
81
+ export interface ResolvedStatuslineSession extends StatuslineSession {
82
+ derived?: StatuslineMetadataEntry["derived"];
83
+ metadata?: StatuslineMetadataEntry;
84
+ isCurrent: boolean;
85
+ }
86
+ export declare function trim(text: string, max: number): string;
87
+ export declare function normalizePath(path: string | undefined, projectRoot: string): string;
88
+ export declare function sessionIdentity(session: Pick<StatuslineSession, "id" | "tool" | "label" | "role">): string;
89
+ export declare function renderDerivedBadge(derived: StatuslineMetadataEntry["derived"]): string | null;
90
+ export declare function renderSessionCompactHint(session: {
91
+ semantic?: SessionSemanticState;
92
+ derived?: StatuslineMetadataEntry["derived"];
93
+ }): string | null;
94
+ export declare function renderDashboardScreens(activeScreen: StatuslineData["dashboardScreen"]): string[];
95
+ export declare function currentPathContext(currentPath: string | undefined): {
96
+ worktreeName?: string;
97
+ branch?: string;
98
+ } | null;
99
+ export declare function resolveCurrentSessionId(data: StatuslineData, currentSession?: string, currentWindow?: string, currentWindowId?: string, currentPath?: string, projectRoot?: string): string | undefined;
100
+ export declare function resolveExactCurrentSessionId(data: StatuslineData, currentSession?: string, currentWindow?: string, currentWindowId?: string, currentPath?: string, projectRoot?: string): string | undefined;
101
+ export declare function resolveScopedSessions(data: StatuslineData, projectRoot: string, currentSession?: string, currentWindow?: string, currentWindowId?: string, currentPath?: string): ResolvedStatuslineSession[];
102
+ export declare function resolveSessionMetadata(data: StatuslineData, projectRoot: string, currentSession?: string, currentWindow?: string, currentWindowId?: string, currentPath?: string): StatuslineMetadataEntry | undefined;
103
+ export declare function resolveExactSessionMetadata(data: StatuslineData, projectRoot: string, currentSession?: string, currentWindow?: string, currentWindowId?: string, currentPath?: string): StatuslineMetadataEntry | undefined;
@@ -0,0 +1,177 @@
1
+ import { basename } from "node:path";
2
+ import { sessionSemanticCompactHint } from "./session-semantics.js";
3
+ function isAutogeneratedSessionLabel(session) {
4
+ const label = session.label?.trim().toLowerCase();
5
+ const tool = session.tool?.trim().toLowerCase();
6
+ if (!label || !tool)
7
+ return false;
8
+ return label === tool || label.startsWith(`${tool}-`);
9
+ }
10
+ export function compactSessionTitle(session) {
11
+ const base = session.kind === "service"
12
+ ? session.label?.trim() || session.tool || "service"
13
+ : !isAutogeneratedSessionLabel(session) && session.label?.trim()
14
+ ? session.label.trim()
15
+ : session.tool || session.id;
16
+ if (session.kind === "service") {
17
+ return `${base}[svc]`;
18
+ }
19
+ return session.role ? `${base}(${session.role})` : base;
20
+ }
21
+ export function trim(text, max) {
22
+ if (text.length <= max)
23
+ return text;
24
+ if (max <= 1)
25
+ return text.slice(0, max);
26
+ return `${text.slice(0, Math.max(0, max - 1))}…`;
27
+ }
28
+ export function normalizePath(path, projectRoot) {
29
+ return path?.trim() || projectRoot;
30
+ }
31
+ function isWithinPath(path, root) {
32
+ return path === root || path.startsWith(`${root}/`);
33
+ }
34
+ function resolveScopedWorktreePath(data, projectRoot, currentPath) {
35
+ const normalizedCurrentPath = normalizePath(currentPath, projectRoot);
36
+ const candidates = (data.sessions ?? [])
37
+ .map((session) => normalizePath(session.worktreePath, projectRoot))
38
+ .filter((worktreePath) => isWithinPath(normalizedCurrentPath, worktreePath))
39
+ .sort((left, right) => right.length - left.length);
40
+ return candidates[0] ?? normalizedCurrentPath;
41
+ }
42
+ export function sessionIdentity(session) {
43
+ return compactSessionTitle(session);
44
+ }
45
+ export function renderDerivedBadge(derived) {
46
+ if (!derived)
47
+ return null;
48
+ if (derived.attention === "error")
49
+ return "✗";
50
+ if (derived.attention === "needs_input")
51
+ return "?";
52
+ if (derived.attention === "blocked")
53
+ return "!";
54
+ if ((derived.unseenCount ?? 0) > 0)
55
+ return String(Math.min(derived.unseenCount ?? 0, 9));
56
+ if (derived.activity === "done")
57
+ return "✓";
58
+ if (derived.activity === "running")
59
+ return "↻";
60
+ if (derived.activity === "waiting")
61
+ return "…";
62
+ return null;
63
+ }
64
+ export function renderSessionCompactHint(session) {
65
+ if (session.semantic) {
66
+ return sessionSemanticCompactHint(session.semantic);
67
+ }
68
+ if (session.derived?.attention === "error")
69
+ return "error";
70
+ if (session.derived?.attention === "needs_input")
71
+ return "on you";
72
+ if (session.derived?.attention === "blocked")
73
+ return "blocked";
74
+ if ((session.derived?.unseenCount ?? 0) > 0) {
75
+ return `${Math.min(session.derived?.unseenCount ?? 0, 99)} unread`;
76
+ }
77
+ return null;
78
+ }
79
+ export function renderDashboardScreens(activeScreen) {
80
+ const active = activeScreen ?? "dashboard";
81
+ const screens = [
82
+ { key: "dashboard", label: "dashboard" },
83
+ { key: "activity", label: "activity" },
84
+ { key: "threads", label: "threads" },
85
+ { key: "workflow", label: "workflow" },
86
+ { key: "plans", label: "plans" },
87
+ { key: "graveyard", label: "graveyard" },
88
+ ];
89
+ return screens.map((screen) => screen.key === active ? `#[fg=black,bg=yellow] ${screen.label} #[default]` : screen.label);
90
+ }
91
+ export function currentPathContext(currentPath) {
92
+ if (!currentPath)
93
+ return null;
94
+ const worktreeName = basename(currentPath);
95
+ return {
96
+ worktreeName: worktreeName || undefined,
97
+ };
98
+ }
99
+ export function resolveCurrentSessionId(data, currentSession, currentWindow, currentWindowId, currentPath, projectRoot) {
100
+ const sessions = data.sessions ?? [];
101
+ if (currentWindowId) {
102
+ const byWindow = sessions.find((session) => session.tmuxWindowId === currentWindowId);
103
+ if (byWindow?.id)
104
+ return byWindow.id;
105
+ }
106
+ if (currentWindow && projectRoot) {
107
+ const scopedWorktreePath = resolveScopedWorktreePath(data, projectRoot, currentPath);
108
+ const byScopedWindow = sessions.find((session) => {
109
+ if (normalizePath(session.worktreePath, projectRoot) !== scopedWorktreePath)
110
+ return false;
111
+ return session.windowName === currentWindow || session.label === currentWindow || session.tool === currentWindow;
112
+ });
113
+ if (byScopedWindow?.id)
114
+ return byScopedWindow.id;
115
+ }
116
+ return data.sessions?.find((session) => session.active)?.id;
117
+ }
118
+ export function resolveExactCurrentSessionId(data, currentSession, currentWindow, currentWindowId, currentPath, projectRoot) {
119
+ const sessions = data.sessions ?? [];
120
+ if (currentWindowId) {
121
+ const byWindow = sessions.find((session) => session.tmuxWindowId === currentWindowId);
122
+ if (byWindow?.id)
123
+ return byWindow.id;
124
+ }
125
+ if (currentWindow && projectRoot) {
126
+ const scopedWorktreePath = resolveScopedWorktreePath(data, projectRoot, currentPath);
127
+ const matches = sessions.filter((session) => {
128
+ if (normalizePath(session.worktreePath, projectRoot) !== scopedWorktreePath)
129
+ return false;
130
+ return session.windowName === currentWindow || session.label === currentWindow || session.tool === currentWindow;
131
+ });
132
+ if (matches.length === 1) {
133
+ return matches[0]?.id;
134
+ }
135
+ }
136
+ return undefined;
137
+ }
138
+ export function resolveScopedSessions(data, projectRoot, currentSession, currentWindow, currentWindowId, currentPath) {
139
+ const scopedWorktreePath = resolveScopedWorktreePath(data, projectRoot, currentPath);
140
+ return (data.sessions ?? [])
141
+ .filter((session) => normalizePath(session.worktreePath, projectRoot) === scopedWorktreePath)
142
+ .sort((left, right) => {
143
+ const leftKind = left.kind === "service" ? 1 : 0;
144
+ const rightKind = right.kind === "service" ? 1 : 0;
145
+ if (leftKind !== rightKind)
146
+ return leftKind - rightKind;
147
+ const leftIndex = left.tmuxWindowIndex ?? Number.MAX_SAFE_INTEGER;
148
+ const rightIndex = right.tmuxWindowIndex ?? Number.MAX_SAFE_INTEGER;
149
+ if (leftIndex !== rightIndex)
150
+ return leftIndex - rightIndex;
151
+ return compactSessionTitle(left).localeCompare(compactSessionTitle(right));
152
+ })
153
+ .slice(0, 5)
154
+ .map((session) => {
155
+ const resolvedMetadata = data.metadata?.[session.id];
156
+ return {
157
+ ...session,
158
+ derived: resolvedMetadata?.derived,
159
+ semantic: session.semantic,
160
+ metadata: resolvedMetadata,
161
+ isCurrent: currentWindowId ? session.tmuxWindowId === currentWindowId : Boolean(session.active),
162
+ };
163
+ });
164
+ }
165
+ export function resolveSessionMetadata(data, projectRoot, currentSession, currentWindow, currentWindowId, currentPath) {
166
+ const activeSessionId = resolveCurrentSessionId(data, currentSession, currentWindow, currentWindowId, currentPath, projectRoot);
167
+ if (!activeSessionId)
168
+ return undefined;
169
+ return data.metadata?.[activeSessionId];
170
+ }
171
+ export function resolveExactSessionMetadata(data, projectRoot, currentSession, currentWindow, currentWindowId, currentPath) {
172
+ const activeSessionId = resolveExactCurrentSessionId(data, currentSession, currentWindow, currentWindowId, currentPath, projectRoot);
173
+ if (!activeSessionId)
174
+ return undefined;
175
+ return data.metadata?.[activeSessionId];
176
+ }
177
+ //# sourceMappingURL=statusline-model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"statusline-model.js","sourceRoot":"","sources":["../src/statusline-model.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ import { type Task } from "./tasks.js";
2
+ import type { SessionAvailability } from "./session-semantics.js";
3
+ interface DispatchSession {
4
+ id: string;
5
+ exited: boolean;
6
+ status: string;
7
+ write(data: string): void;
8
+ }
9
+ export interface TaskEvent {
10
+ type: "assigned" | "completed" | "failed" | "review_created" | "review_approved" | "changes_requested";
11
+ taskId: string;
12
+ sessionId: string;
13
+ description: string;
14
+ }
15
+ export declare class TaskDispatcher {
16
+ private getSession;
17
+ private getSessionTool;
18
+ private getSessionRole;
19
+ private getSessionAvailability;
20
+ private tickCount;
21
+ private lastCounts;
22
+ private workflow;
23
+ /** Per-session task info: sessionId → task description */
24
+ private sessionTasks;
25
+ /** Recent events for flash notifications, drained by caller */
26
+ private pendingEvents;
27
+ constructor(getSession: (id: string) => DispatchSession | undefined, getSessionTool: (id: string) => string | undefined, getSessionRole?: (id: string) => string | undefined, getSessionAvailability?: (id: string) => SessionAvailability | undefined);
28
+ /**
29
+ * Main dispatch loop, called every ~2s from the dashboard/status refresh loop.
30
+ */
31
+ tick(localSessionIds: string[]): void;
32
+ /**
33
+ * Find an idle local session matching the task's targeting criteria.
34
+ * Priority: assignedTo (specific session) > assignee (role) > tool > any idle.
35
+ */
36
+ private findIdleSession;
37
+ private inject;
38
+ /**
39
+ * Notify the assigning session that a task has completed.
40
+ */
41
+ private notifyAssigner;
42
+ /**
43
+ * Get cached counts from last tick.
44
+ */
45
+ getTaskCounts(): {
46
+ pending: number;
47
+ assigned: number;
48
+ };
49
+ /**
50
+ * Get the task description assigned to a session, if any.
51
+ */
52
+ getSessionTask(sessionId: string): string | undefined;
53
+ /**
54
+ * Drain pending events (for flash notifications). Returns and clears the queue.
55
+ */
56
+ drainEvents(): TaskEvent[];
57
+ }
58
+ /**
59
+ * Create a review task for the active session's recent work.
60
+ * Called from the [v] hotkey handler.
61
+ */
62
+ export declare function requestReview(agentSessionId: string, agentRole: string, diff: string | undefined, summary: string): Task | null;
63
+ export {};