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
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Claude Code hooks configuration generator
|
|
3
|
+
*
|
|
4
|
+
* Generates .claude/settings.local.json with hook definitions that POST
|
|
5
|
+
* to Codeman's /api/hook-event endpoint when Claude Code fires
|
|
6
|
+
* notification or stop hooks. Uses $CODEMAN_API_URL and
|
|
7
|
+
* $CODEMAN_SESSION_ID env vars (set on every managed session) so the
|
|
8
|
+
* config is static per case directory.
|
|
9
|
+
*/
|
|
10
|
+
import { existsSync } from 'node:fs';
|
|
11
|
+
import { readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
12
|
+
import { join } from 'node:path';
|
|
13
|
+
/**
|
|
14
|
+
* Generates the hooks section for .claude/settings.local.json
|
|
15
|
+
*
|
|
16
|
+
* The hook commands read stdin JSON from Claude Code (contains tool_name,
|
|
17
|
+
* tool_input, etc.) and forward it as the `data` field to Codeman's API.
|
|
18
|
+
* Env vars are resolved at runtime by the shell, so the config is static
|
|
19
|
+
* per case directory.
|
|
20
|
+
*/
|
|
21
|
+
export function generateHooksConfig() {
|
|
22
|
+
// Read Claude Code's stdin JSON and forward it as the data field.
|
|
23
|
+
// Falls back to empty object if stdin is unavailable or malformed.
|
|
24
|
+
const curlCmd = (event) => `HOOK_DATA=$(cat 2>/dev/null || echo '{}'); ` +
|
|
25
|
+
`printf '{"event":"${event}","sessionId":"%s","data":%s}' "$CODEMAN_SESSION_ID" "$HOOK_DATA" | ` +
|
|
26
|
+
`curl -s -X POST "$CODEMAN_API_URL/api/hook-event" ` +
|
|
27
|
+
`-H 'Content-Type: application/json' ` +
|
|
28
|
+
`--data @- ` +
|
|
29
|
+
`2>/dev/null || true`;
|
|
30
|
+
return {
|
|
31
|
+
hooks: {
|
|
32
|
+
Notification: [
|
|
33
|
+
{
|
|
34
|
+
matcher: 'idle_prompt',
|
|
35
|
+
hooks: [{ type: 'command', command: curlCmd('idle_prompt'), timeout: 10000 }],
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
matcher: 'permission_prompt',
|
|
39
|
+
hooks: [{ type: 'command', command: curlCmd('permission_prompt'), timeout: 10000 }],
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
matcher: 'elicitation_dialog',
|
|
43
|
+
hooks: [{ type: 'command', command: curlCmd('elicitation_dialog'), timeout: 10000 }],
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
Stop: [
|
|
47
|
+
{
|
|
48
|
+
hooks: [{ type: 'command', command: curlCmd('stop'), timeout: 10000 }],
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
TeammateIdle: [
|
|
52
|
+
{
|
|
53
|
+
hooks: [{ type: 'command', command: curlCmd('teammate_idle'), timeout: 10000 }],
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
TaskCompleted: [
|
|
57
|
+
{
|
|
58
|
+
hooks: [{ type: 'command', command: curlCmd('task_completed'), timeout: 10000 }],
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Updates env vars in .claude/settings.local.json for the given case path.
|
|
66
|
+
* Merges with existing env field; removes vars set to empty string.
|
|
67
|
+
*/
|
|
68
|
+
export async function updateCaseEnvVars(casePath, envVars) {
|
|
69
|
+
const claudeDir = join(casePath, '.claude');
|
|
70
|
+
if (!existsSync(claudeDir)) {
|
|
71
|
+
await mkdir(claudeDir, { recursive: true });
|
|
72
|
+
}
|
|
73
|
+
const settingsPath = join(claudeDir, 'settings.local.json');
|
|
74
|
+
let existing = {};
|
|
75
|
+
try {
|
|
76
|
+
existing = JSON.parse(await readFile(settingsPath, 'utf-8'));
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
existing = {};
|
|
80
|
+
}
|
|
81
|
+
const currentEnv = existing.env || {};
|
|
82
|
+
for (const [key, value] of Object.entries(envVars)) {
|
|
83
|
+
if (value) {
|
|
84
|
+
currentEnv[key] = value;
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
delete currentEnv[key];
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
existing.env = currentEnv;
|
|
91
|
+
await writeFile(settingsPath, JSON.stringify(existing, null, 2) + '\n');
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Writes hooks config to .claude/settings.local.json in the given case path.
|
|
95
|
+
* Merges with existing file content, only touching the `hooks` key.
|
|
96
|
+
*/
|
|
97
|
+
export async function writeHooksConfig(casePath) {
|
|
98
|
+
const claudeDir = join(casePath, '.claude');
|
|
99
|
+
if (!existsSync(claudeDir)) {
|
|
100
|
+
await mkdir(claudeDir, { recursive: true });
|
|
101
|
+
}
|
|
102
|
+
const settingsPath = join(claudeDir, 'settings.local.json');
|
|
103
|
+
let existing = {};
|
|
104
|
+
try {
|
|
105
|
+
existing = JSON.parse(await readFile(settingsPath, 'utf-8'));
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
// If file is malformed or doesn't exist, start fresh
|
|
109
|
+
existing = {};
|
|
110
|
+
}
|
|
111
|
+
const hooksConfig = generateHooksConfig();
|
|
112
|
+
const merged = { ...existing, ...hooksConfig };
|
|
113
|
+
await writeFile(settingsPath, JSON.stringify(merged, null, 2) + '\n');
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=hooks-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks-config.js","sourceRoot":"","sources":["../src/hooks-config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Image Watcher - Detects new image files in session working directories
|
|
3
|
+
*
|
|
4
|
+
* Watches session working directories for new image files (screenshots, generated images)
|
|
5
|
+
* and emits events to trigger automatic popup display in the web UI.
|
|
6
|
+
*
|
|
7
|
+
* Uses chokidar for reliable cross-platform file watching with awaitWriteFinish
|
|
8
|
+
* to ensure files are fully written before emitting detection events.
|
|
9
|
+
*/
|
|
10
|
+
import { EventEmitter } from 'node:events';
|
|
11
|
+
import type { ImageDetectedEvent } from './types.js';
|
|
12
|
+
export interface ImageWatcherEvents {
|
|
13
|
+
'image:detected': (event: ImageDetectedEvent) => void;
|
|
14
|
+
'image:error': (error: Error, sessionId?: string) => void;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Watches session working directories for new image files.
|
|
18
|
+
*
|
|
19
|
+
* Follows the SubagentWatcher pattern: extends EventEmitter, manages
|
|
20
|
+
* file watchers in Maps, emits typed events.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* const watcher = new ImageWatcher();
|
|
25
|
+
* watcher.on('image:detected', (event) => {
|
|
26
|
+
* console.log(`New image in session ${event.sessionId}: ${event.fileName}`);
|
|
27
|
+
* });
|
|
28
|
+
* watcher.watchSession('session-123', '/path/to/working/dir');
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export declare class ImageWatcher extends EventEmitter {
|
|
32
|
+
/** Map of sessionId -> FSWatcher for per-session directory watching */
|
|
33
|
+
private sessionWatchers;
|
|
34
|
+
/** Map of sessionId -> working directory path */
|
|
35
|
+
private sessionDirs;
|
|
36
|
+
/** Debounce timers for rapid image creation (keyed by filePath) */
|
|
37
|
+
private debounceTimers;
|
|
38
|
+
/** Track which session owns each debounce timer (for cleanup) */
|
|
39
|
+
private timerToSession;
|
|
40
|
+
/** Per-session burst tracking: sessionId -> { count, windowStart } */
|
|
41
|
+
private burstTrackers;
|
|
42
|
+
/** Whether the watcher is currently running */
|
|
43
|
+
private _isRunning;
|
|
44
|
+
constructor();
|
|
45
|
+
/**
|
|
46
|
+
* Check if the watcher is currently running
|
|
47
|
+
*/
|
|
48
|
+
isRunning(): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Start the image watcher.
|
|
51
|
+
* After calling start(), use watchSession() to add directories to monitor.
|
|
52
|
+
*/
|
|
53
|
+
start(): void;
|
|
54
|
+
/**
|
|
55
|
+
* Stop the image watcher and clean up all resources.
|
|
56
|
+
*/
|
|
57
|
+
stop(): void;
|
|
58
|
+
/**
|
|
59
|
+
* Start watching a session's working directory for new images.
|
|
60
|
+
*
|
|
61
|
+
* @param sessionId - Codeman session ID
|
|
62
|
+
* @param workingDir - Path to the session's working directory
|
|
63
|
+
*/
|
|
64
|
+
watchSession(sessionId: string, workingDir: string): void;
|
|
65
|
+
/**
|
|
66
|
+
* Stop watching a session's working directory.
|
|
67
|
+
*
|
|
68
|
+
* @param sessionId - Codeman session ID to stop watching
|
|
69
|
+
*/
|
|
70
|
+
unwatchSession(sessionId: string): void;
|
|
71
|
+
/**
|
|
72
|
+
* Get list of currently watched session IDs.
|
|
73
|
+
*/
|
|
74
|
+
getWatchedSessions(): string[];
|
|
75
|
+
/**
|
|
76
|
+
* Handle a new file being detected.
|
|
77
|
+
* Verifies it's an image and emits the detection event.
|
|
78
|
+
*/
|
|
79
|
+
private handleNewFile;
|
|
80
|
+
/**
|
|
81
|
+
* Emit the image:detected event with file metadata.
|
|
82
|
+
*/
|
|
83
|
+
private emitImageDetected;
|
|
84
|
+
}
|
|
85
|
+
export declare const imageWatcher: ImageWatcher;
|
|
86
|
+
//# sourceMappingURL=image-watcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-watcher.d.ts","sourceRoot":"","sources":["../src/image-watcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAI3C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAIrD,MAAM,WAAW,kBAAkB;IACjC,gBAAgB,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAC;IACtD,aAAa,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CAC3D;AAwBD;;;;;;;;;;;;;;GAcG;AACH,qBAAa,YAAa,SAAQ,YAAY;IAC5C,uEAAuE;IACvE,OAAO,CAAC,eAAe,CAAgC;IAEvD,iDAAiD;IACjD,OAAO,CAAC,WAAW,CAA6B;IAEhD,mEAAmE;IACnE,OAAO,CAAC,cAAc,CAAqC;IAE3D,iEAAiE;IACjE,OAAO,CAAC,cAAc,CAA6B;IAEnD,sEAAsE;IACtE,OAAO,CAAC,aAAa,CAA6D;IAElF,+CAA+C;IAC/C,OAAO,CAAC,UAAU,CAAS;;IAS3B;;OAEG;IACH,SAAS,IAAI,OAAO;IAIpB;;;OAGG;IACH,KAAK,IAAI,IAAI;IAKb;;OAEG;IACH,IAAI,IAAI,IAAI;IAuBZ;;;;;OAKG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IA8DzD;;;;OAIG;IACH,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IA+BvC;;OAEG;IACH,kBAAkB,IAAI,MAAM,EAAE;IAM9B;;;OAGG;IACH,OAAO,CAAC,aAAa;IA4CrB;;OAEG;IACH,OAAO,CAAC,iBAAiB;CAuB1B;AAGD,eAAO,MAAM,YAAY,cAAqB,CAAC"}
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Image Watcher - Detects new image files in session working directories
|
|
3
|
+
*
|
|
4
|
+
* Watches session working directories for new image files (screenshots, generated images)
|
|
5
|
+
* and emits events to trigger automatic popup display in the web UI.
|
|
6
|
+
*
|
|
7
|
+
* Uses chokidar for reliable cross-platform file watching with awaitWriteFinish
|
|
8
|
+
* to ensure files are fully written before emitting detection events.
|
|
9
|
+
*/
|
|
10
|
+
import { EventEmitter } from 'node:events';
|
|
11
|
+
import { watch } from 'chokidar';
|
|
12
|
+
import { basename, extname, relative } from 'node:path';
|
|
13
|
+
import { statSync } from 'node:fs';
|
|
14
|
+
// ========== Constants ==========
|
|
15
|
+
/** Supported image file extensions (lowercase) */
|
|
16
|
+
const IMAGE_EXTENSIONS = new Set(['.png', '.jpg', '.jpeg', '.gif', '.webp', '.bmp', '.svg']);
|
|
17
|
+
/** Time to wait for file writes to stabilize (ms) */
|
|
18
|
+
const STABILITY_THRESHOLD_MS = 500;
|
|
19
|
+
/** Poll interval for checking file write stability (ms) */
|
|
20
|
+
const POLL_INTERVAL_MS = 100;
|
|
21
|
+
/** Debounce delay for rapid image creation (ms) */
|
|
22
|
+
const DEBOUNCE_DELAY_MS = 200;
|
|
23
|
+
/** Max images emitted per session within the burst window before throttling */
|
|
24
|
+
const BURST_LIMIT = 20;
|
|
25
|
+
/** Time window for burst detection (ms) — resets after this period of quiet */
|
|
26
|
+
const BURST_WINDOW_MS = 10_000;
|
|
27
|
+
// ========== ImageWatcher Class ==========
|
|
28
|
+
/**
|
|
29
|
+
* Watches session working directories for new image files.
|
|
30
|
+
*
|
|
31
|
+
* Follows the SubagentWatcher pattern: extends EventEmitter, manages
|
|
32
|
+
* file watchers in Maps, emits typed events.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```typescript
|
|
36
|
+
* const watcher = new ImageWatcher();
|
|
37
|
+
* watcher.on('image:detected', (event) => {
|
|
38
|
+
* console.log(`New image in session ${event.sessionId}: ${event.fileName}`);
|
|
39
|
+
* });
|
|
40
|
+
* watcher.watchSession('session-123', '/path/to/working/dir');
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export class ImageWatcher extends EventEmitter {
|
|
44
|
+
/** Map of sessionId -> FSWatcher for per-session directory watching */
|
|
45
|
+
sessionWatchers = new Map();
|
|
46
|
+
/** Map of sessionId -> working directory path */
|
|
47
|
+
sessionDirs = new Map();
|
|
48
|
+
/** Debounce timers for rapid image creation (keyed by filePath) */
|
|
49
|
+
debounceTimers = new Map();
|
|
50
|
+
/** Track which session owns each debounce timer (for cleanup) */
|
|
51
|
+
timerToSession = new Map();
|
|
52
|
+
/** Per-session burst tracking: sessionId -> { count, windowStart } */
|
|
53
|
+
burstTrackers = new Map();
|
|
54
|
+
/** Whether the watcher is currently running */
|
|
55
|
+
_isRunning = false;
|
|
56
|
+
constructor() {
|
|
57
|
+
super();
|
|
58
|
+
this.setMaxListeners(50);
|
|
59
|
+
}
|
|
60
|
+
// ========== Public API ==========
|
|
61
|
+
/**
|
|
62
|
+
* Check if the watcher is currently running
|
|
63
|
+
*/
|
|
64
|
+
isRunning() {
|
|
65
|
+
return this._isRunning;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Start the image watcher.
|
|
69
|
+
* After calling start(), use watchSession() to add directories to monitor.
|
|
70
|
+
*/
|
|
71
|
+
start() {
|
|
72
|
+
if (this._isRunning)
|
|
73
|
+
return;
|
|
74
|
+
this._isRunning = true;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Stop the image watcher and clean up all resources.
|
|
78
|
+
*/
|
|
79
|
+
stop() {
|
|
80
|
+
this._isRunning = false;
|
|
81
|
+
// Close all session watchers
|
|
82
|
+
for (const [sessionId, watcher] of this.sessionWatchers) {
|
|
83
|
+
try {
|
|
84
|
+
watcher.close();
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
this.emit('image:error', error instanceof Error ? error : new Error(String(error)), sessionId);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
this.sessionWatchers.clear();
|
|
91
|
+
this.sessionDirs.clear();
|
|
92
|
+
// Clear all debounce timers
|
|
93
|
+
for (const timer of this.debounceTimers.values()) {
|
|
94
|
+
clearTimeout(timer);
|
|
95
|
+
}
|
|
96
|
+
this.debounceTimers.clear();
|
|
97
|
+
this.timerToSession.clear();
|
|
98
|
+
this.burstTrackers.clear();
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Start watching a session's working directory for new images.
|
|
102
|
+
*
|
|
103
|
+
* @param sessionId - Codeman session ID
|
|
104
|
+
* @param workingDir - Path to the session's working directory
|
|
105
|
+
*/
|
|
106
|
+
watchSession(sessionId, workingDir) {
|
|
107
|
+
if (!this._isRunning) {
|
|
108
|
+
this.start();
|
|
109
|
+
}
|
|
110
|
+
// Don't double-watch the same session
|
|
111
|
+
if (this.sessionWatchers.has(sessionId)) {
|
|
112
|
+
// If working directory changed, unwatch old and watch new
|
|
113
|
+
if (this.sessionDirs.get(sessionId) !== workingDir) {
|
|
114
|
+
this.unwatchSession(sessionId);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
this.sessionDirs.set(sessionId, workingDir);
|
|
121
|
+
try {
|
|
122
|
+
// Create chokidar watcher for the directory
|
|
123
|
+
const watcher = watch(workingDir, {
|
|
124
|
+
// Only detect NEW files, not existing ones
|
|
125
|
+
ignoreInitial: true,
|
|
126
|
+
// Wait for file writes to stabilize before emitting
|
|
127
|
+
awaitWriteFinish: {
|
|
128
|
+
stabilityThreshold: STABILITY_THRESHOLD_MS,
|
|
129
|
+
pollInterval: POLL_INTERVAL_MS,
|
|
130
|
+
},
|
|
131
|
+
// Watch all subdirectories (images may be saved in src/, assets/, etc.)
|
|
132
|
+
// Ignore common heavy directories for performance
|
|
133
|
+
ignored: (path) => {
|
|
134
|
+
// Skip node_modules, .git, and other heavy directories
|
|
135
|
+
if (path.includes('/node_modules/') ||
|
|
136
|
+
path.includes('/.git/') ||
|
|
137
|
+
path.includes('/dist/') ||
|
|
138
|
+
path.includes('/.next/')) {
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
const ext = extname(path).toLowerCase();
|
|
142
|
+
// Don't ignore directories (needed for watching to work)
|
|
143
|
+
// Ignore files that aren't images
|
|
144
|
+
return ext !== '' && !IMAGE_EXTENSIONS.has(ext);
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
// Handle new file detection
|
|
148
|
+
watcher.on('add', (filePath) => {
|
|
149
|
+
this.handleNewFile(sessionId, filePath);
|
|
150
|
+
});
|
|
151
|
+
// Handle watcher errors
|
|
152
|
+
watcher.on('error', (error) => {
|
|
153
|
+
this.emit('image:error', error, sessionId);
|
|
154
|
+
});
|
|
155
|
+
this.sessionWatchers.set(sessionId, watcher);
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
this.emit('image:error', error instanceof Error ? error : new Error(String(error)), sessionId);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Stop watching a session's working directory.
|
|
163
|
+
*
|
|
164
|
+
* @param sessionId - Codeman session ID to stop watching
|
|
165
|
+
*/
|
|
166
|
+
unwatchSession(sessionId) {
|
|
167
|
+
const watcher = this.sessionWatchers.get(sessionId);
|
|
168
|
+
if (watcher) {
|
|
169
|
+
try {
|
|
170
|
+
watcher.close();
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
this.emit('image:error', error instanceof Error ? error : new Error(String(error)), sessionId);
|
|
174
|
+
}
|
|
175
|
+
this.sessionWatchers.delete(sessionId);
|
|
176
|
+
}
|
|
177
|
+
this.sessionDirs.delete(sessionId);
|
|
178
|
+
// Clear any pending debounce timers for this session
|
|
179
|
+
// Collect keys first to avoid iterator invalidation during deletion
|
|
180
|
+
const toDelete = [];
|
|
181
|
+
for (const [filePath, ownerId] of this.timerToSession) {
|
|
182
|
+
if (ownerId === sessionId) {
|
|
183
|
+
toDelete.push(filePath);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
for (const filePath of toDelete) {
|
|
187
|
+
const timer = this.debounceTimers.get(filePath);
|
|
188
|
+
if (timer) {
|
|
189
|
+
clearTimeout(timer);
|
|
190
|
+
this.debounceTimers.delete(filePath);
|
|
191
|
+
}
|
|
192
|
+
this.timerToSession.delete(filePath);
|
|
193
|
+
}
|
|
194
|
+
this.burstTrackers.delete(sessionId);
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Get list of currently watched session IDs.
|
|
198
|
+
*/
|
|
199
|
+
getWatchedSessions() {
|
|
200
|
+
return Array.from(this.sessionWatchers.keys());
|
|
201
|
+
}
|
|
202
|
+
// ========== Private Methods ==========
|
|
203
|
+
/**
|
|
204
|
+
* Handle a new file being detected.
|
|
205
|
+
* Verifies it's an image and emits the detection event.
|
|
206
|
+
*/
|
|
207
|
+
handleNewFile(sessionId, filePath) {
|
|
208
|
+
const ext = extname(filePath).toLowerCase();
|
|
209
|
+
// Double-check it's an image extension
|
|
210
|
+
if (!IMAGE_EXTENSIONS.has(ext)) {
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
// Burst limit: skip if too many images detected for this session in a short window
|
|
214
|
+
const now = Date.now();
|
|
215
|
+
let burst = this.burstTrackers.get(sessionId);
|
|
216
|
+
if (burst) {
|
|
217
|
+
if (now - burst.windowStart > BURST_WINDOW_MS) {
|
|
218
|
+
// Window expired, reset
|
|
219
|
+
burst = { count: 0, windowStart: now };
|
|
220
|
+
this.burstTrackers.set(sessionId, burst);
|
|
221
|
+
}
|
|
222
|
+
if (burst.count >= BURST_LIMIT) {
|
|
223
|
+
return; // Throttled — too many images in this window
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
227
|
+
burst = { count: 0, windowStart: now };
|
|
228
|
+
this.burstTrackers.set(sessionId, burst);
|
|
229
|
+
}
|
|
230
|
+
// Debounce rapid file creation (e.g., multiple screenshots quickly)
|
|
231
|
+
const existingTimer = this.debounceTimers.get(filePath);
|
|
232
|
+
if (existingTimer) {
|
|
233
|
+
clearTimeout(existingTimer);
|
|
234
|
+
}
|
|
235
|
+
const timer = setTimeout(() => {
|
|
236
|
+
this.debounceTimers.delete(filePath);
|
|
237
|
+
this.timerToSession.delete(filePath);
|
|
238
|
+
this.emitImageDetected(sessionId, filePath);
|
|
239
|
+
// Increment burst count on actual emission (not on detection)
|
|
240
|
+
const b = this.burstTrackers.get(sessionId);
|
|
241
|
+
if (b)
|
|
242
|
+
b.count++;
|
|
243
|
+
}, DEBOUNCE_DELAY_MS);
|
|
244
|
+
this.debounceTimers.set(filePath, timer);
|
|
245
|
+
this.timerToSession.set(filePath, sessionId);
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Emit the image:detected event with file metadata.
|
|
249
|
+
*/
|
|
250
|
+
emitImageDetected(sessionId, filePath) {
|
|
251
|
+
try {
|
|
252
|
+
const stat = statSync(filePath);
|
|
253
|
+
const fileName = basename(filePath);
|
|
254
|
+
const workingDir = this.sessionDirs.get(sessionId);
|
|
255
|
+
// Compute relative path from working directory (for file-raw endpoint)
|
|
256
|
+
const relativePath = workingDir ? relative(workingDir, filePath) : fileName;
|
|
257
|
+
const event = {
|
|
258
|
+
sessionId,
|
|
259
|
+
filePath,
|
|
260
|
+
relativePath,
|
|
261
|
+
fileName,
|
|
262
|
+
timestamp: Date.now(),
|
|
263
|
+
size: stat.size,
|
|
264
|
+
};
|
|
265
|
+
this.emit('image:detected', event);
|
|
266
|
+
}
|
|
267
|
+
catch (error) {
|
|
268
|
+
// File may have been deleted between detection and stat
|
|
269
|
+
this.emit('image:error', error instanceof Error ? error : new Error(String(error)), sessionId);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
// Export singleton instance for convenience
|
|
274
|
+
export const imageWatcher = new ImageWatcher();
|
|
275
|
+
//# sourceMappingURL=image-watcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-watcher.js","sourceRoot":"","sources":["../src/image-watcher.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview Codeman CLI entry point
|
|
4
|
+
*
|
|
5
|
+
* This is the main executable entry point for the Codeman CLI.
|
|
6
|
+
* It sets up global error handlers and invokes the CLI parser.
|
|
7
|
+
*
|
|
8
|
+
* @module index
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;GAOG"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview Codeman CLI entry point
|
|
4
|
+
*
|
|
5
|
+
* This is the main executable entry point for the Codeman CLI.
|
|
6
|
+
* It sets up global error handlers and invokes the CLI parser.
|
|
7
|
+
*
|
|
8
|
+
* @module index
|
|
9
|
+
*/
|
|
10
|
+
import { program } from './cli.js';
|
|
11
|
+
// Detect if we're running the web server (long-lived process)
|
|
12
|
+
// In web mode, we should NOT exit on transient errors — log and continue
|
|
13
|
+
const isWebMode = process.argv.includes('web');
|
|
14
|
+
// Track consecutive unhandled errors in web mode — restart after too many
|
|
15
|
+
let consecutiveErrors = 0;
|
|
16
|
+
const MAX_CONSECUTIVE_ERRORS = 5;
|
|
17
|
+
const ERROR_RESET_MS = 60000; // Reset counter after 1 minute of no errors
|
|
18
|
+
let errorResetTimer = null;
|
|
19
|
+
function trackError() {
|
|
20
|
+
consecutiveErrors++;
|
|
21
|
+
if (errorResetTimer)
|
|
22
|
+
clearTimeout(errorResetTimer);
|
|
23
|
+
errorResetTimer = setTimeout(() => {
|
|
24
|
+
consecutiveErrors = 0;
|
|
25
|
+
}, ERROR_RESET_MS);
|
|
26
|
+
if (consecutiveErrors >= MAX_CONSECUTIVE_ERRORS) {
|
|
27
|
+
console.error(`[FATAL] ${MAX_CONSECUTIVE_ERRORS} consecutive unhandled errors — exiting for systemd restart`);
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// Handle uncaught errors
|
|
32
|
+
process.on('uncaughtException', (err) => {
|
|
33
|
+
console.error('Uncaught exception:', err.message);
|
|
34
|
+
if (isWebMode) {
|
|
35
|
+
console.error('[RECOVERED] Server continuing after uncaught exception:', err.stack);
|
|
36
|
+
trackError();
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
process.on('unhandledRejection', (reason) => {
|
|
43
|
+
console.error('Unhandled rejection:', reason);
|
|
44
|
+
if (isWebMode) {
|
|
45
|
+
console.error('[RECOVERED] Server continuing after unhandled rejection');
|
|
46
|
+
trackError();
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
// Run CLI
|
|
53
|
+
program.parse();
|
|
54
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;GAOG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAEnC,8DAA8D;AAC9D,yEAAyE;AACzE,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAE/C,0EAA0E;AAC1E,IAAI,iBAAiB,GAAG,CAAC,CAAC;AAC1B,MAAM,sBAAsB,GAAG,CAAC,CAAC;AACjC,MAAM,cAAc,GAAG,KAAK,CAAC,CAAC,4CAA4C;AAC1E,IAAI,eAAe,GAAyC,IAAI,CAAC;AAEjE,SAAS,UAAU;IACjB,iBAAiB,EAAE,CAAC;IACpB,IAAI,eAAe;QAAE,YAAY,CAAC,eAAe,CAAC,CAAC;IACnD,eAAe,GAAG,UAAU,CAAC,GAAG,EAAE;QAChC,iBAAiB,GAAG,CAAC,CAAC;IACxB,CAAC,EAAE,cAAc,CAAC,CAAC;IAEnB,IAAI,iBAAiB,IAAI,sBAAsB,EAAE,CAAC;QAChD,OAAO,CAAC,KAAK,CAAC,WAAW,sBAAsB,6DAA6D,CAAC,CAAC;QAC9G,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,yBAAyB;AACzB,OAAO,CAAC,EAAE,CAAC,mBAAmB,EAAE,CAAC,GAAG,EAAE,EAAE;IACtC,OAAO,CAAC,KAAK,CAAC,qBAAqB,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IAClD,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,CAAC,KAAK,CAAC,yDAAyD,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;QACpF,UAAU,EAAE,CAAC;IACf,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,OAAO,CAAC,EAAE,CAAC,oBAAoB,EAAE,CAAC,MAAM,EAAE,EAAE;IAC1C,OAAO,CAAC,KAAK,CAAC,sBAAsB,EAAE,MAAM,CAAC,CAAC;IAC9C,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,CAAC,KAAK,CAAC,yDAAyD,CAAC,CAAC;QACzE,UAAU,EAAE,CAAC;IACf,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,UAAU;AACV,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Factory for creating the terminal multiplexer (tmux).
|
|
3
|
+
*
|
|
4
|
+
* @module mux-factory
|
|
5
|
+
*/
|
|
6
|
+
import type { TerminalMultiplexer } from './mux-interface.js';
|
|
7
|
+
/**
|
|
8
|
+
* Create a TerminalMultiplexer instance.
|
|
9
|
+
*
|
|
10
|
+
* Requires tmux to be installed. Throws with install instructions if not found.
|
|
11
|
+
*/
|
|
12
|
+
export declare function createMultiplexer(): TerminalMultiplexer;
|
|
13
|
+
//# sourceMappingURL=mux-factory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mux-factory.d.ts","sourceRoot":"","sources":["../src/mux-factory.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAG9D;;;;GAIG;AACH,wBAAgB,iBAAiB,IAAI,mBAAmB,CAOvD"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Factory for creating the terminal multiplexer (tmux).
|
|
3
|
+
*
|
|
4
|
+
* @module mux-factory
|
|
5
|
+
*/
|
|
6
|
+
import { TmuxManager } from './tmux-manager.js';
|
|
7
|
+
/**
|
|
8
|
+
* Create a TerminalMultiplexer instance.
|
|
9
|
+
*
|
|
10
|
+
* Requires tmux to be installed. Throws with install instructions if not found.
|
|
11
|
+
*/
|
|
12
|
+
export function createMultiplexer() {
|
|
13
|
+
if (!TmuxManager.isTmuxAvailable()) {
|
|
14
|
+
throw new Error('tmux not found. Install: sudo apt install tmux');
|
|
15
|
+
}
|
|
16
|
+
console.log('[MuxFactory] Using tmux backend');
|
|
17
|
+
return new TmuxManager();
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=mux-factory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mux-factory.js","sourceRoot":"","sources":["../src/mux-factory.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD;;;;GAIG;AACH,MAAM,UAAU,iBAAiB;IAC/B,IAAI,CAAC,WAAW,CAAC,eAAe,EAAE,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;IACpE,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;IAC/C,OAAO,IAAI,WAAW,EAAE,CAAC;AAC3B,CAAC"}
|