aicodeman 0.2.8
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/LICENSE +21 -0
- package/README.md +403 -0
- package/dist/ai-checker-base.d.ts +175 -0
- package/dist/ai-checker-base.d.ts.map +1 -0
- package/dist/ai-checker-base.js +424 -0
- package/dist/ai-checker-base.js.map +1 -0
- package/dist/ai-idle-checker.d.ts +53 -0
- package/dist/ai-idle-checker.d.ts.map +1 -0
- package/dist/ai-idle-checker.js +141 -0
- package/dist/ai-idle-checker.js.map +1 -0
- package/dist/ai-plan-checker.d.ts +52 -0
- package/dist/ai-plan-checker.d.ts.map +1 -0
- package/dist/ai-plan-checker.js +103 -0
- package/dist/ai-plan-checker.js.map +1 -0
- package/dist/bash-tool-parser.d.ts +191 -0
- package/dist/bash-tool-parser.d.ts.map +1 -0
- package/dist/bash-tool-parser.js +598 -0
- package/dist/bash-tool-parser.js.map +1 -0
- package/dist/cli.d.ts +12 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +460 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/buffer-limits.d.ts +59 -0
- package/dist/config/buffer-limits.d.ts.map +1 -0
- package/dist/config/buffer-limits.js +74 -0
- package/dist/config/buffer-limits.js.map +1 -0
- package/dist/config/map-limits.d.ts +40 -0
- package/dist/config/map-limits.d.ts.map +1 -0
- package/dist/config/map-limits.js +52 -0
- package/dist/config/map-limits.js.map +1 -0
- package/dist/file-stream-manager.d.ts +148 -0
- package/dist/file-stream-manager.d.ts.map +1 -0
- package/dist/file-stream-manager.js +351 -0
- package/dist/file-stream-manager.js.map +1 -0
- package/dist/hooks-config.d.ts +31 -0
- package/dist/hooks-config.d.ts.map +1 -0
- package/dist/hooks-config.js +115 -0
- package/dist/hooks-config.js.map +1 -0
- package/dist/image-watcher.d.ts +86 -0
- package/dist/image-watcher.d.ts.map +1 -0
- package/dist/image-watcher.js +275 -0
- package/dist/image-watcher.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +54 -0
- package/dist/index.js.map +1 -0
- package/dist/mux-factory.d.ts +13 -0
- package/dist/mux-factory.d.ts.map +1 -0
- package/dist/mux-factory.js +19 -0
- package/dist/mux-factory.js.map +1 -0
- package/dist/mux-interface.d.ts +145 -0
- package/dist/mux-interface.d.ts.map +1 -0
- package/dist/mux-interface.js +9 -0
- package/dist/mux-interface.js.map +1 -0
- package/dist/plan-orchestrator.d.ts +123 -0
- package/dist/plan-orchestrator.d.ts.map +1 -0
- package/dist/plan-orchestrator.js +500 -0
- package/dist/plan-orchestrator.js.map +1 -0
- package/dist/prompts/index.d.ts +9 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +9 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/prompts/planner.d.ts +14 -0
- package/dist/prompts/planner.d.ts.map +1 -0
- package/dist/prompts/planner.js +83 -0
- package/dist/prompts/planner.js.map +1 -0
- package/dist/prompts/research-agent.d.ts +10 -0
- package/dist/prompts/research-agent.d.ts.map +1 -0
- package/dist/prompts/research-agent.js +143 -0
- package/dist/prompts/research-agent.js.map +1 -0
- package/dist/push-store.d.ts +41 -0
- package/dist/push-store.d.ts.map +1 -0
- package/dist/push-store.js +168 -0
- package/dist/push-store.js.map +1 -0
- package/dist/ralph-config.d.ts +67 -0
- package/dist/ralph-config.d.ts.map +1 -0
- package/dist/ralph-config.js +134 -0
- package/dist/ralph-config.js.map +1 -0
- package/dist/ralph-loop.d.ts +124 -0
- package/dist/ralph-loop.d.ts.map +1 -0
- package/dist/ralph-loop.js +418 -0
- package/dist/ralph-loop.js.map +1 -0
- package/dist/ralph-tracker.d.ts +1081 -0
- package/dist/ralph-tracker.d.ts.map +1 -0
- package/dist/ralph-tracker.js +3343 -0
- package/dist/ralph-tracker.js.map +1 -0
- package/dist/respawn-controller.d.ts +1182 -0
- package/dist/respawn-controller.d.ts.map +1 -0
- package/dist/respawn-controller.js +2754 -0
- package/dist/respawn-controller.js.map +1 -0
- package/dist/run-summary.d.ts +123 -0
- package/dist/run-summary.d.ts.map +1 -0
- package/dist/run-summary.js +325 -0
- package/dist/run-summary.js.map +1 -0
- package/dist/session-lifecycle-log.d.ts +36 -0
- package/dist/session-lifecycle-log.d.ts.map +1 -0
- package/dist/session-lifecycle-log.js +101 -0
- package/dist/session-lifecycle-log.js.map +1 -0
- package/dist/session-manager.d.ts +97 -0
- package/dist/session-manager.d.ts.map +1 -0
- package/dist/session-manager.js +224 -0
- package/dist/session-manager.js.map +1 -0
- package/dist/session.d.ts +686 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +2025 -0
- package/dist/session.js.map +1 -0
- package/dist/state-store.d.ts +189 -0
- package/dist/state-store.d.ts.map +1 -0
- package/dist/state-store.js +730 -0
- package/dist/state-store.js.map +1 -0
- package/dist/subagent-watcher.d.ts +345 -0
- package/dist/subagent-watcher.d.ts.map +1 -0
- package/dist/subagent-watcher.js +1469 -0
- package/dist/subagent-watcher.js.map +1 -0
- package/dist/task-queue.d.ts +108 -0
- package/dist/task-queue.d.ts.map +1 -0
- package/dist/task-queue.js +235 -0
- package/dist/task-queue.js.map +1 -0
- package/dist/task-tracker.d.ts +306 -0
- package/dist/task-tracker.d.ts.map +1 -0
- package/dist/task-tracker.js +488 -0
- package/dist/task-tracker.js.map +1 -0
- package/dist/task.d.ts +73 -0
- package/dist/task.d.ts.map +1 -0
- package/dist/task.js +177 -0
- package/dist/task.js.map +1 -0
- package/dist/team-watcher.d.ts +53 -0
- package/dist/team-watcher.d.ts.map +1 -0
- package/dist/team-watcher.js +313 -0
- package/dist/team-watcher.js.map +1 -0
- package/dist/templates/case-template.md +461 -0
- package/dist/templates/claude-md.d.ts +26 -0
- package/dist/templates/claude-md.d.ts.map +1 -0
- package/dist/templates/claude-md.js +74 -0
- package/dist/templates/claude-md.js.map +1 -0
- package/dist/tmux-manager.d.ts +181 -0
- package/dist/tmux-manager.d.ts.map +1 -0
- package/dist/tmux-manager.js +1405 -0
- package/dist/tmux-manager.js.map +1 -0
- package/dist/transcript-watcher.d.ts +110 -0
- package/dist/transcript-watcher.d.ts.map +1 -0
- package/dist/transcript-watcher.js +338 -0
- package/dist/transcript-watcher.js.map +1 -0
- package/dist/tunnel-manager.d.ts +54 -0
- package/dist/tunnel-manager.d.ts.map +1 -0
- package/dist/tunnel-manager.js +251 -0
- package/dist/tunnel-manager.js.map +1 -0
- package/dist/types.d.ts +1139 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +215 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/buffer-accumulator.d.ts +111 -0
- package/dist/utils/buffer-accumulator.d.ts.map +1 -0
- package/dist/utils/buffer-accumulator.js +172 -0
- package/dist/utils/buffer-accumulator.js.map +1 -0
- package/dist/utils/claude-cli-resolver.d.ts +26 -0
- package/dist/utils/claude-cli-resolver.d.ts.map +1 -0
- package/dist/utils/claude-cli-resolver.js +78 -0
- package/dist/utils/claude-cli-resolver.js.map +1 -0
- package/dist/utils/cleanup-manager.d.ts +165 -0
- package/dist/utils/cleanup-manager.d.ts.map +1 -0
- package/dist/utils/cleanup-manager.js +274 -0
- package/dist/utils/cleanup-manager.js.map +1 -0
- package/dist/utils/index.d.ts +19 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +19 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/lru-map.d.ts +140 -0
- package/dist/utils/lru-map.d.ts.map +1 -0
- package/dist/utils/lru-map.js +234 -0
- package/dist/utils/lru-map.js.map +1 -0
- package/dist/utils/nice-wrapper.d.ts +13 -0
- package/dist/utils/nice-wrapper.d.ts.map +1 -0
- package/dist/utils/nice-wrapper.js +17 -0
- package/dist/utils/nice-wrapper.js.map +1 -0
- package/dist/utils/opencode-cli-resolver.d.ts +21 -0
- package/dist/utils/opencode-cli-resolver.d.ts.map +1 -0
- package/dist/utils/opencode-cli-resolver.js +67 -0
- package/dist/utils/opencode-cli-resolver.js.map +1 -0
- package/dist/utils/regex-patterns.d.ts +64 -0
- package/dist/utils/regex-patterns.d.ts.map +1 -0
- package/dist/utils/regex-patterns.js +74 -0
- package/dist/utils/regex-patterns.js.map +1 -0
- package/dist/utils/stale-expiration-map.d.ts +159 -0
- package/dist/utils/stale-expiration-map.d.ts.map +1 -0
- package/dist/utils/stale-expiration-map.js +277 -0
- package/dist/utils/stale-expiration-map.js.map +1 -0
- package/dist/utils/string-similarity.d.ts +108 -0
- package/dist/utils/string-similarity.d.ts.map +1 -0
- package/dist/utils/string-similarity.js +189 -0
- package/dist/utils/string-similarity.js.map +1 -0
- package/dist/utils/token-validation.d.ts +39 -0
- package/dist/utils/token-validation.d.ts.map +1 -0
- package/dist/utils/token-validation.js +59 -0
- package/dist/utils/token-validation.js.map +1 -0
- package/dist/utils/type-safety.d.ts +33 -0
- package/dist/utils/type-safety.d.ts.map +1 -0
- package/dist/utils/type-safety.js +35 -0
- package/dist/utils/type-safety.js.map +1 -0
- package/dist/web/public/app.js +491 -0
- package/dist/web/public/app.js.br +0 -0
- package/dist/web/public/app.js.gz +0 -0
- package/dist/web/public/index.html +1675 -0
- package/dist/web/public/index.html.br +0 -0
- package/dist/web/public/index.html.gz +0 -0
- package/dist/web/public/manifest.json +8 -0
- package/dist/web/public/mobile.css +1 -0
- package/dist/web/public/mobile.css.br +0 -0
- package/dist/web/public/mobile.css.gz +0 -0
- package/dist/web/public/ralph-wizard.js +1037 -0
- package/dist/web/public/ralph-wizard.js.br +0 -0
- package/dist/web/public/ralph-wizard.js.gz +0 -0
- package/dist/web/public/styles.css +1 -0
- package/dist/web/public/styles.css.br +0 -0
- package/dist/web/public/styles.css.gz +0 -0
- package/dist/web/public/sw.js +67 -0
- package/dist/web/public/sw.js.br +0 -0
- package/dist/web/public/sw.js.gz +0 -0
- package/dist/web/public/upload.html +155 -0
- package/dist/web/public/upload.html.br +0 -0
- package/dist/web/public/upload.html.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-fit.min.js +1 -0
- package/dist/web/public/vendor/xterm-addon-fit.min.js.br +0 -0
- package/dist/web/public/vendor/xterm-addon-fit.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-unicode11.min.js +1 -0
- package/dist/web/public/vendor/xterm-addon-unicode11.min.js.br +0 -0
- package/dist/web/public/vendor/xterm-addon-unicode11.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-webgl.min.js +2 -0
- package/dist/web/public/vendor/xterm-addon-webgl.min.js.br +0 -0
- package/dist/web/public/vendor/xterm-addon-webgl.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm.css +209 -0
- package/dist/web/public/vendor/xterm.css.br +0 -0
- package/dist/web/public/vendor/xterm.css.gz +0 -0
- package/dist/web/public/vendor/xterm.min.js +9 -0
- package/dist/web/public/vendor/xterm.min.js.br +0 -0
- package/dist/web/public/vendor/xterm.min.js.gz +0 -0
- package/dist/web/schemas.d.ts +479 -0
- package/dist/web/schemas.d.ts.map +1 -0
- package/dist/web/schemas.js +448 -0
- package/dist/web/schemas.js.map +1 -0
- package/dist/web/server.d.ts +207 -0
- package/dist/web/server.d.ts.map +1 -0
- package/dist/web/server.js +5784 -0
- package/dist/web/server.js.map +1 -0
- package/package.json +110 -0
- package/scripts/postinstall.js +390 -0
package/dist/task.js
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Task model for Claude prompt execution
|
|
3
|
+
*
|
|
4
|
+
* Represents a single task (prompt) to be executed by a Claude session.
|
|
5
|
+
* Tasks support priority ordering, dependencies, and completion detection.
|
|
6
|
+
*
|
|
7
|
+
* @module task
|
|
8
|
+
*/
|
|
9
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
10
|
+
/** Pre-compiled pattern for generic promise tag detection */
|
|
11
|
+
const PROMISE_TAG_PATTERN = /<promise>[^<]+<\/promise>/;
|
|
12
|
+
/** Escapes special regex characters in a string for safe use in RegExp constructor */
|
|
13
|
+
function escapeRegex(str) {
|
|
14
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* A task representing a prompt to be executed by a Claude session.
|
|
18
|
+
*
|
|
19
|
+
* @description
|
|
20
|
+
* Tasks have a lifecycle: pending → running → completed/failed
|
|
21
|
+
* They support priority ordering and dependency chains.
|
|
22
|
+
*/
|
|
23
|
+
export class Task {
|
|
24
|
+
id;
|
|
25
|
+
prompt;
|
|
26
|
+
workingDir;
|
|
27
|
+
priority;
|
|
28
|
+
dependencies;
|
|
29
|
+
completionPhrase;
|
|
30
|
+
timeoutMs;
|
|
31
|
+
createdAt;
|
|
32
|
+
_status = 'pending';
|
|
33
|
+
_assignedSessionId = null;
|
|
34
|
+
_startedAt = null;
|
|
35
|
+
_completedAt = null;
|
|
36
|
+
_output = '';
|
|
37
|
+
_error = null;
|
|
38
|
+
/** Pre-compiled regex for completion phrase detection (avoids re-creation per check) */
|
|
39
|
+
_completionPattern;
|
|
40
|
+
constructor(options, id) {
|
|
41
|
+
this.id = id || uuidv4();
|
|
42
|
+
this.prompt = options.prompt;
|
|
43
|
+
this.workingDir = options.workingDir || process.cwd();
|
|
44
|
+
this.priority = options.priority ?? 0;
|
|
45
|
+
this.dependencies = options.dependencies || [];
|
|
46
|
+
this.completionPhrase = options.completionPhrase;
|
|
47
|
+
this.timeoutMs = options.timeoutMs;
|
|
48
|
+
this.createdAt = Date.now();
|
|
49
|
+
this._completionPattern = options.completionPhrase
|
|
50
|
+
? new RegExp(`<promise>${escapeRegex(options.completionPhrase)}</promise>`)
|
|
51
|
+
: null;
|
|
52
|
+
}
|
|
53
|
+
get status() {
|
|
54
|
+
return this._status;
|
|
55
|
+
}
|
|
56
|
+
get assignedSessionId() {
|
|
57
|
+
return this._assignedSessionId;
|
|
58
|
+
}
|
|
59
|
+
get startedAt() {
|
|
60
|
+
return this._startedAt;
|
|
61
|
+
}
|
|
62
|
+
get completedAt() {
|
|
63
|
+
return this._completedAt;
|
|
64
|
+
}
|
|
65
|
+
get output() {
|
|
66
|
+
return this._output;
|
|
67
|
+
}
|
|
68
|
+
get error() {
|
|
69
|
+
return this._error;
|
|
70
|
+
}
|
|
71
|
+
isPending() {
|
|
72
|
+
return this._status === 'pending';
|
|
73
|
+
}
|
|
74
|
+
isRunning() {
|
|
75
|
+
return this._status === 'running';
|
|
76
|
+
}
|
|
77
|
+
isCompleted() {
|
|
78
|
+
return this._status === 'completed';
|
|
79
|
+
}
|
|
80
|
+
isFailed() {
|
|
81
|
+
return this._status === 'failed';
|
|
82
|
+
}
|
|
83
|
+
isDone() {
|
|
84
|
+
return this._status === 'completed' || this._status === 'failed';
|
|
85
|
+
}
|
|
86
|
+
toDefinition() {
|
|
87
|
+
return {
|
|
88
|
+
id: this.id,
|
|
89
|
+
prompt: this.prompt,
|
|
90
|
+
workingDir: this.workingDir,
|
|
91
|
+
priority: this.priority,
|
|
92
|
+
dependencies: this.dependencies,
|
|
93
|
+
completionPhrase: this.completionPhrase,
|
|
94
|
+
timeoutMs: this.timeoutMs,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
toState() {
|
|
98
|
+
return {
|
|
99
|
+
...this.toDefinition(),
|
|
100
|
+
status: this._status,
|
|
101
|
+
assignedSessionId: this._assignedSessionId,
|
|
102
|
+
createdAt: this.createdAt,
|
|
103
|
+
startedAt: this._startedAt,
|
|
104
|
+
completedAt: this._completedAt,
|
|
105
|
+
output: this._output,
|
|
106
|
+
error: this._error,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
/** Reconstructs a Task from persisted state. */
|
|
110
|
+
static fromState(state) {
|
|
111
|
+
const task = new Task({
|
|
112
|
+
prompt: state.prompt,
|
|
113
|
+
workingDir: state.workingDir,
|
|
114
|
+
priority: state.priority,
|
|
115
|
+
dependencies: state.dependencies,
|
|
116
|
+
completionPhrase: state.completionPhrase,
|
|
117
|
+
timeoutMs: state.timeoutMs,
|
|
118
|
+
}, state.id);
|
|
119
|
+
task._status = state.status;
|
|
120
|
+
task._assignedSessionId = state.assignedSessionId;
|
|
121
|
+
task._startedAt = state.startedAt;
|
|
122
|
+
task._completedAt = state.completedAt;
|
|
123
|
+
task._output = state.output;
|
|
124
|
+
task._error = state.error;
|
|
125
|
+
return task;
|
|
126
|
+
}
|
|
127
|
+
/** Assigns this task to a session and marks it as running. */
|
|
128
|
+
assign(sessionId) {
|
|
129
|
+
if (this._status !== 'pending') {
|
|
130
|
+
throw new Error(`Cannot assign task ${this.id}: status is ${this._status}`);
|
|
131
|
+
}
|
|
132
|
+
this._status = 'running';
|
|
133
|
+
this._assignedSessionId = sessionId;
|
|
134
|
+
this._startedAt = Date.now();
|
|
135
|
+
}
|
|
136
|
+
appendOutput(output) {
|
|
137
|
+
this._output += output;
|
|
138
|
+
}
|
|
139
|
+
setError(error) {
|
|
140
|
+
this._error = error;
|
|
141
|
+
}
|
|
142
|
+
complete() {
|
|
143
|
+
this._status = 'completed';
|
|
144
|
+
this._completedAt = Date.now();
|
|
145
|
+
}
|
|
146
|
+
fail(error) {
|
|
147
|
+
this._status = 'failed';
|
|
148
|
+
this._completedAt = Date.now();
|
|
149
|
+
if (error) {
|
|
150
|
+
this._error = error;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
reset() {
|
|
154
|
+
this._status = 'pending';
|
|
155
|
+
this._assignedSessionId = null;
|
|
156
|
+
this._startedAt = null;
|
|
157
|
+
this._completedAt = null;
|
|
158
|
+
this._output = '';
|
|
159
|
+
this._error = null;
|
|
160
|
+
}
|
|
161
|
+
/** Checks if output contains the completion phrase. */
|
|
162
|
+
checkCompletion(output) {
|
|
163
|
+
if (this._completionPattern) {
|
|
164
|
+
return this._completionPattern.test(output);
|
|
165
|
+
}
|
|
166
|
+
// Default: check for any promise tag completion
|
|
167
|
+
return PROMISE_TAG_PATTERN.test(output);
|
|
168
|
+
}
|
|
169
|
+
/** Returns true if the task has exceeded its timeout. */
|
|
170
|
+
isTimedOut() {
|
|
171
|
+
if (!this.timeoutMs || !this._startedAt) {
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
return Date.now() - this._startedAt > this.timeoutMs;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
//# sourceMappingURL=task.js.map
|
package/dist/task.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task.js","sourceRoot":"","sources":["../src/task.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Agent Teams Watcher
|
|
3
|
+
*
|
|
4
|
+
* Polls ~/.claude/teams/ and ~/.claude/tasks/ for agent team activity.
|
|
5
|
+
* Matches teams to Codeman sessions via leadSessionId and emits
|
|
6
|
+
* events for UI updates and team-aware idle detection.
|
|
7
|
+
*
|
|
8
|
+
* @module team-watcher
|
|
9
|
+
*/
|
|
10
|
+
import { EventEmitter } from 'node:events';
|
|
11
|
+
import type { TeamConfig, TeamMember, TeamTask, InboxMessage } from './types.js';
|
|
12
|
+
export declare class TeamWatcher extends EventEmitter {
|
|
13
|
+
private teamsDir;
|
|
14
|
+
private tasksDir;
|
|
15
|
+
private pollTimer;
|
|
16
|
+
private teams;
|
|
17
|
+
private teamTasks;
|
|
18
|
+
private inboxCache;
|
|
19
|
+
private configMtimes;
|
|
20
|
+
private taskMtimes;
|
|
21
|
+
private inboxMtimes;
|
|
22
|
+
private sessionToTeam;
|
|
23
|
+
constructor(teamsDir?: string, tasksDir?: string);
|
|
24
|
+
start(): void;
|
|
25
|
+
stop(): void;
|
|
26
|
+
/** Get all discovered teams */
|
|
27
|
+
getTeams(): TeamConfig[];
|
|
28
|
+
/** Get team associated with a Codeman session (matched by leadSessionId) */
|
|
29
|
+
getTeamForSession(sessionId: string): TeamConfig | undefined;
|
|
30
|
+
/** Get tasks for a team (excluding internal tasks) */
|
|
31
|
+
getTeamTasks(teamName: string): TeamTask[];
|
|
32
|
+
/** Count active (non-completed) tasks for a team */
|
|
33
|
+
getActiveTaskCount(teamName: string): number;
|
|
34
|
+
/** Get inbox messages for a team member (or all members) */
|
|
35
|
+
getInboxMessages(teamName: string, member?: string): InboxMessage[];
|
|
36
|
+
/** Check if a session has active teammates (for idle detection) */
|
|
37
|
+
hasActiveTeammates(sessionId: string): boolean;
|
|
38
|
+
/** Get teammates that have real tmux panes (not in-process) */
|
|
39
|
+
getTmuxPaneTeammates(teamName: string): Array<TeamMember & {
|
|
40
|
+
tmuxPaneId: string;
|
|
41
|
+
}>;
|
|
42
|
+
/** Get count of active teammates for a session */
|
|
43
|
+
getActiveTeammateCount(sessionId: string): number;
|
|
44
|
+
private poll;
|
|
45
|
+
private pollAsync;
|
|
46
|
+
private pollTeams;
|
|
47
|
+
private pollTasks;
|
|
48
|
+
private pollInboxes;
|
|
49
|
+
/** Check for directory-based lock (mkdir atomic locking) */
|
|
50
|
+
private isLocked;
|
|
51
|
+
private readJson;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=team-watcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"team-watcher.d.ts","sourceRoot":"","sources":["../src/team-watcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAK3C,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAWjF,qBAAa,WAAY,SAAQ,YAAY;IAC3C,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,SAAS,CAA+B;IAChD,OAAO,CAAC,KAAK,CAAyE;IACtF,OAAO,CAAC,SAAS,CAAyE;IAC1F,OAAO,CAAC,UAAU,CAA6E;IAE/F,OAAO,CAAC,YAAY,CAAkC;IACtD,OAAO,CAAC,UAAU,CAAkC;IACpD,OAAO,CAAC,WAAW,CAAkC;IAErD,OAAO,CAAC,aAAa,CAAkC;gBAE3C,QAAQ,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM;IAOhD,KAAK,IAAI,IAAI;IAMb,IAAI,IAAI,IAAI;IAcZ,+BAA+B;IAC/B,QAAQ,IAAI,UAAU,EAAE;IAIxB,4EAA4E;IAC5E,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS;IAW5D,sDAAsD;IACtD,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,EAAE;IAM1C,oDAAoD;IACpD,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAK5C,4DAA4D;IAC5D,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,YAAY,EAAE;IAenE,mEAAmE;IACnE,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAa9C,+DAA+D;IAC/D,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,CAAC,UAAU,GAAG;QAAE,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IAUlF,kDAAkD;IAClD,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAQjD,OAAO,CAAC,IAAI;YAOE,SAAS;YAMT,SAAS;YAuET,SAAS;YA6CT,WAAW;IA8CzB,4DAA4D;YAC9C,QAAQ;YASR,QAAQ;CAQvB"}
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Agent Teams Watcher
|
|
3
|
+
*
|
|
4
|
+
* Polls ~/.claude/teams/ and ~/.claude/tasks/ for agent team activity.
|
|
5
|
+
* Matches teams to Codeman sessions via leadSessionId and emits
|
|
6
|
+
* events for UI updates and team-aware idle detection.
|
|
7
|
+
*
|
|
8
|
+
* @module team-watcher
|
|
9
|
+
*/
|
|
10
|
+
import { EventEmitter } from 'node:events';
|
|
11
|
+
import { readdir, readFile, stat } from 'node:fs/promises';
|
|
12
|
+
import { homedir } from 'node:os';
|
|
13
|
+
import { join } from 'node:path';
|
|
14
|
+
import { LRUMap } from './utils/lru-map.js';
|
|
15
|
+
// ========== Constants ==========
|
|
16
|
+
const POLL_INTERVAL_MS = 5000;
|
|
17
|
+
const MAX_CACHED_TEAMS = 50;
|
|
18
|
+
const MAX_CACHED_TASKS = 200;
|
|
19
|
+
// ========== TeamWatcher Class ==========
|
|
20
|
+
export class TeamWatcher extends EventEmitter {
|
|
21
|
+
teamsDir;
|
|
22
|
+
tasksDir;
|
|
23
|
+
pollTimer = null;
|
|
24
|
+
teams = new LRUMap({ maxSize: MAX_CACHED_TEAMS });
|
|
25
|
+
teamTasks = new LRUMap({ maxSize: MAX_CACHED_TASKS });
|
|
26
|
+
inboxCache = new LRUMap({ maxSize: MAX_CACHED_TASKS });
|
|
27
|
+
// Track config mtimes to avoid re-reading unchanged files
|
|
28
|
+
configMtimes = new Map();
|
|
29
|
+
taskMtimes = new Map();
|
|
30
|
+
inboxMtimes = new Map();
|
|
31
|
+
// Reverse index: sessionId → teamName for O(1) lookup
|
|
32
|
+
sessionToTeam = new Map();
|
|
33
|
+
constructor(teamsDir, tasksDir) {
|
|
34
|
+
super();
|
|
35
|
+
const claudeHome = join(homedir(), '.claude');
|
|
36
|
+
this.teamsDir = teamsDir || join(claudeHome, 'teams');
|
|
37
|
+
this.tasksDir = tasksDir || join(claudeHome, 'tasks');
|
|
38
|
+
}
|
|
39
|
+
start() {
|
|
40
|
+
if (this.pollTimer)
|
|
41
|
+
return;
|
|
42
|
+
this.poll();
|
|
43
|
+
this.pollTimer = setInterval(() => this.poll(), POLL_INTERVAL_MS);
|
|
44
|
+
}
|
|
45
|
+
stop() {
|
|
46
|
+
if (this.pollTimer) {
|
|
47
|
+
clearInterval(this.pollTimer);
|
|
48
|
+
this.pollTimer = null;
|
|
49
|
+
}
|
|
50
|
+
this.teams.clear();
|
|
51
|
+
this.teamTasks.clear();
|
|
52
|
+
this.inboxCache.clear();
|
|
53
|
+
this.configMtimes.clear();
|
|
54
|
+
this.taskMtimes.clear();
|
|
55
|
+
this.inboxMtimes.clear();
|
|
56
|
+
this.sessionToTeam.clear();
|
|
57
|
+
}
|
|
58
|
+
/** Get all discovered teams */
|
|
59
|
+
getTeams() {
|
|
60
|
+
return Array.from(this.teams.values());
|
|
61
|
+
}
|
|
62
|
+
/** Get team associated with a Codeman session (matched by leadSessionId) */
|
|
63
|
+
getTeamForSession(sessionId) {
|
|
64
|
+
const teamName = this.sessionToTeam.get(sessionId);
|
|
65
|
+
if (teamName) {
|
|
66
|
+
const team = this.teams.peek(teamName);
|
|
67
|
+
if (team)
|
|
68
|
+
return team;
|
|
69
|
+
// Stale reverse index entry — clean up
|
|
70
|
+
this.sessionToTeam.delete(sessionId);
|
|
71
|
+
}
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
/** Get tasks for a team (excluding internal tasks) */
|
|
75
|
+
getTeamTasks(teamName) {
|
|
76
|
+
const tasks = this.teamTasks.get(teamName);
|
|
77
|
+
if (!tasks)
|
|
78
|
+
return [];
|
|
79
|
+
return tasks.filter((t) => !t.metadata?._internal);
|
|
80
|
+
}
|
|
81
|
+
/** Count active (non-completed) tasks for a team */
|
|
82
|
+
getActiveTaskCount(teamName) {
|
|
83
|
+
const tasks = this.getTeamTasks(teamName);
|
|
84
|
+
return tasks.filter((t) => t.status !== 'completed').length;
|
|
85
|
+
}
|
|
86
|
+
/** Get inbox messages for a team member (or all members) */
|
|
87
|
+
getInboxMessages(teamName, member) {
|
|
88
|
+
if (member) {
|
|
89
|
+
const key = `${teamName}/${member}`;
|
|
90
|
+
return this.inboxCache.get(key) || [];
|
|
91
|
+
}
|
|
92
|
+
// Return all messages for team
|
|
93
|
+
const messages = [];
|
|
94
|
+
for (const [key, msgs] of this.inboxCache.entries()) {
|
|
95
|
+
if (key.startsWith(`${teamName}/`)) {
|
|
96
|
+
messages.push(...msgs);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return messages.sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());
|
|
100
|
+
}
|
|
101
|
+
/** Check if a session has active teammates (for idle detection) */
|
|
102
|
+
hasActiveTeammates(sessionId) {
|
|
103
|
+
const team = this.getTeamForSession(sessionId);
|
|
104
|
+
if (!team)
|
|
105
|
+
return false;
|
|
106
|
+
// Check if any non-lead members exist (they are active by definition while present)
|
|
107
|
+
const teammates = team.members.filter((m) => m.agentType !== 'team-lead');
|
|
108
|
+
if (teammates.length === 0)
|
|
109
|
+
return false;
|
|
110
|
+
// Check if team has active (non-completed) tasks
|
|
111
|
+
const activeTasks = this.getActiveTaskCount(team.name);
|
|
112
|
+
return activeTasks > 0;
|
|
113
|
+
}
|
|
114
|
+
/** Get teammates that have real tmux panes (not in-process) */
|
|
115
|
+
getTmuxPaneTeammates(teamName) {
|
|
116
|
+
const team = this.teams.get(teamName);
|
|
117
|
+
if (!team)
|
|
118
|
+
return [];
|
|
119
|
+
return team.members.filter((m) => m.agentType !== 'team-lead' && !!m.tmuxPaneId && m.tmuxPaneId !== 'in-process');
|
|
120
|
+
}
|
|
121
|
+
/** Get count of active teammates for a session */
|
|
122
|
+
getActiveTeammateCount(sessionId) {
|
|
123
|
+
const team = this.getTeamForSession(sessionId);
|
|
124
|
+
if (!team)
|
|
125
|
+
return 0;
|
|
126
|
+
return team.members.filter((m) => m.agentType !== 'team-lead').length;
|
|
127
|
+
}
|
|
128
|
+
// ========== Private Methods ==========
|
|
129
|
+
poll() {
|
|
130
|
+
// Run async poll — errors are caught internally per method
|
|
131
|
+
this.pollAsync().catch(() => {
|
|
132
|
+
// Don't crash on polling errors — filesystem may be temporarily unavailable
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
async pollAsync() {
|
|
136
|
+
await this.pollTeams();
|
|
137
|
+
await this.pollTasks();
|
|
138
|
+
await this.pollInboxes();
|
|
139
|
+
}
|
|
140
|
+
async pollTeams() {
|
|
141
|
+
let entries;
|
|
142
|
+
try {
|
|
143
|
+
entries = await readdir(this.teamsDir);
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
const currentTeamNames = new Set();
|
|
149
|
+
for (const entry of entries) {
|
|
150
|
+
const configPath = join(this.teamsDir, entry, 'config.json');
|
|
151
|
+
currentTeamNames.add(entry);
|
|
152
|
+
// Check mtime to skip unchanged configs
|
|
153
|
+
let mtime;
|
|
154
|
+
try {
|
|
155
|
+
mtime = (await stat(configPath)).mtimeMs;
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
// File doesn't exist or was removed between readdir and stat
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
if (this.configMtimes.get(entry) === mtime)
|
|
162
|
+
continue;
|
|
163
|
+
this.configMtimes.set(entry, mtime);
|
|
164
|
+
// Skip if locked
|
|
165
|
+
if (await this.isLocked(join(this.teamsDir, entry, 'config.json')))
|
|
166
|
+
continue;
|
|
167
|
+
const config = await this.readJson(configPath);
|
|
168
|
+
if (!config || !config.name || !config.leadSessionId || !Array.isArray(config.members))
|
|
169
|
+
continue;
|
|
170
|
+
const existing = this.teams.get(entry);
|
|
171
|
+
this.teams.set(entry, config);
|
|
172
|
+
// Maintain reverse index
|
|
173
|
+
if (existing && existing.leadSessionId !== config.leadSessionId) {
|
|
174
|
+
this.sessionToTeam.delete(existing.leadSessionId);
|
|
175
|
+
}
|
|
176
|
+
this.sessionToTeam.set(config.leadSessionId, entry);
|
|
177
|
+
if (existing) {
|
|
178
|
+
this.emit('teamUpdated', config);
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
this.emit('teamCreated', config);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
// Detect removed teams
|
|
185
|
+
for (const name of this.teams.keys()) {
|
|
186
|
+
if (!currentTeamNames.has(name)) {
|
|
187
|
+
const removed = this.teams.get(name);
|
|
188
|
+
this.teams.delete(name);
|
|
189
|
+
this.configMtimes.delete(name);
|
|
190
|
+
// Clean up reverse index
|
|
191
|
+
if (removed) {
|
|
192
|
+
this.sessionToTeam.delete(removed.leadSessionId);
|
|
193
|
+
}
|
|
194
|
+
// Prune stale mtime entries for removed teams
|
|
195
|
+
this.taskMtimes.delete(name);
|
|
196
|
+
for (const key of this.inboxMtimes.keys()) {
|
|
197
|
+
if (key.startsWith(`${name}/`)) {
|
|
198
|
+
this.inboxMtimes.delete(key);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
if (removed) {
|
|
202
|
+
this.emit('teamRemoved', removed);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
async pollTasks() {
|
|
208
|
+
let teamDirs;
|
|
209
|
+
try {
|
|
210
|
+
teamDirs = await readdir(this.tasksDir);
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
for (const teamName of teamDirs) {
|
|
216
|
+
const teamTaskDir = join(this.tasksDir, teamName);
|
|
217
|
+
// Use directory mtime as a cheap change indicator (single stat instead of N)
|
|
218
|
+
const mtimeKey = teamName;
|
|
219
|
+
try {
|
|
220
|
+
const dirStat = await stat(teamTaskDir);
|
|
221
|
+
const dirMtime = `${dirStat.mtimeMs}`;
|
|
222
|
+
if (this.taskMtimes.get(mtimeKey) === dirMtime)
|
|
223
|
+
continue;
|
|
224
|
+
this.taskMtimes.set(mtimeKey, dirMtime);
|
|
225
|
+
}
|
|
226
|
+
catch {
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
let taskFiles;
|
|
230
|
+
try {
|
|
231
|
+
taskFiles = (await readdir(teamTaskDir)).filter((f) => f.endsWith('.json') && f !== '.lock');
|
|
232
|
+
}
|
|
233
|
+
catch {
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
// Skip if locked
|
|
237
|
+
if (await this.isLocked(join(teamTaskDir, '.lock')))
|
|
238
|
+
continue;
|
|
239
|
+
const tasks = [];
|
|
240
|
+
for (const f of taskFiles) {
|
|
241
|
+
const task = await this.readJson(join(teamTaskDir, f));
|
|
242
|
+
if (task && task.id) {
|
|
243
|
+
tasks.push(task);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
this.teamTasks.set(teamName, tasks);
|
|
247
|
+
this.emit('taskUpdated', { teamName, tasks });
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
async pollInboxes() {
|
|
251
|
+
// Inbox files live under ~/.claude/teams/{name}/inboxes/
|
|
252
|
+
for (const [teamName] of this.teams.entries()) {
|
|
253
|
+
const inboxDir = join(this.teamsDir, teamName, 'inboxes');
|
|
254
|
+
let inboxFiles;
|
|
255
|
+
try {
|
|
256
|
+
inboxFiles = (await readdir(inboxDir)).filter((f) => f.endsWith('.json'));
|
|
257
|
+
}
|
|
258
|
+
catch {
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
for (const f of inboxFiles) {
|
|
262
|
+
const filePath = join(inboxDir, f);
|
|
263
|
+
const memberName = f.replace('.json', '');
|
|
264
|
+
const cacheKey = `${teamName}/${memberName}`;
|
|
265
|
+
// Check mtime
|
|
266
|
+
try {
|
|
267
|
+
const mtime = (await stat(filePath)).mtimeMs;
|
|
268
|
+
if (this.inboxMtimes.get(cacheKey) === mtime)
|
|
269
|
+
continue;
|
|
270
|
+
this.inboxMtimes.set(cacheKey, mtime);
|
|
271
|
+
}
|
|
272
|
+
catch {
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
// Skip if locked
|
|
276
|
+
if (await this.isLocked(filePath))
|
|
277
|
+
continue;
|
|
278
|
+
const messages = await this.readJson(filePath);
|
|
279
|
+
if (!Array.isArray(messages))
|
|
280
|
+
continue;
|
|
281
|
+
const previous = this.inboxCache.get(cacheKey);
|
|
282
|
+
this.inboxCache.set(cacheKey, messages);
|
|
283
|
+
// Emit new messages — compare by timestamp to handle deletions/reordering
|
|
284
|
+
const prevTimestamps = new Set(previous?.map((m) => m.timestamp) || []);
|
|
285
|
+
for (const msg of messages) {
|
|
286
|
+
if (!prevTimestamps.has(msg.timestamp)) {
|
|
287
|
+
this.emit('inboxMessage', { teamName, member: memberName, message: msg });
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
/** Check for directory-based lock (mkdir atomic locking) */
|
|
294
|
+
async isLocked(path) {
|
|
295
|
+
const lockDir = `${path}.lock`;
|
|
296
|
+
try {
|
|
297
|
+
return (await stat(lockDir)).isDirectory();
|
|
298
|
+
}
|
|
299
|
+
catch {
|
|
300
|
+
return false;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
async readJson(filePath) {
|
|
304
|
+
try {
|
|
305
|
+
const content = await readFile(filePath, 'utf-8');
|
|
306
|
+
return JSON.parse(content);
|
|
307
|
+
}
|
|
308
|
+
catch {
|
|
309
|
+
return null;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
//# sourceMappingURL=team-watcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"team-watcher.js","sourceRoot":"","sources":["../src/team-watcher.ts"],"names":[],"mappings":"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"}
|