aicodeman 0.2.8 → 0.3.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.
- package/README.md +91 -0
- package/dist/ai-idle-checker.d.ts.map +1 -1
- package/dist/ai-idle-checker.js +3 -2
- package/dist/ai-idle-checker.js.map +1 -1
- package/dist/ai-plan-checker.d.ts.map +1 -1
- package/dist/ai-plan-checker.js +3 -2
- package/dist/ai-plan-checker.js.map +1 -1
- package/dist/bash-tool-parser.d.ts +2 -3
- package/dist/bash-tool-parser.d.ts.map +1 -1
- package/dist/bash-tool-parser.js +14 -31
- package/dist/bash-tool-parser.js.map +1 -1
- package/dist/config/ai-defaults.d.ts +16 -0
- package/dist/config/ai-defaults.d.ts.map +1 -0
- package/dist/config/ai-defaults.js +16 -0
- package/dist/config/ai-defaults.js.map +1 -0
- package/dist/config/auth-config.d.ts +19 -0
- package/dist/config/auth-config.d.ts.map +1 -0
- package/dist/config/auth-config.js +28 -0
- package/dist/config/auth-config.js.map +1 -0
- package/dist/config/exec-timeout.d.ts +10 -0
- package/dist/config/exec-timeout.d.ts.map +1 -0
- package/dist/config/exec-timeout.js +10 -0
- package/dist/config/exec-timeout.js.map +1 -0
- package/dist/config/map-limits.d.ts +4 -0
- package/dist/config/map-limits.d.ts.map +1 -1
- package/dist/config/map-limits.js +7 -0
- package/dist/config/map-limits.js.map +1 -1
- package/dist/config/server-timing.d.ts +36 -0
- package/dist/config/server-timing.d.ts.map +1 -0
- package/dist/config/server-timing.js +51 -0
- package/dist/config/server-timing.js.map +1 -0
- package/dist/config/team-config.d.ts +16 -0
- package/dist/config/team-config.d.ts.map +1 -0
- package/dist/config/team-config.js +16 -0
- package/dist/config/team-config.js.map +1 -0
- package/dist/config/terminal-limits.d.ts +18 -0
- package/dist/config/terminal-limits.d.ts.map +1 -0
- package/dist/config/terminal-limits.js +18 -0
- package/dist/config/terminal-limits.js.map +1 -0
- package/dist/config/tunnel-config.d.ts +27 -0
- package/dist/config/tunnel-config.d.ts.map +1 -0
- package/dist/config/tunnel-config.js +36 -0
- package/dist/config/tunnel-config.js.map +1 -0
- package/dist/hooks-config.d.ts.map +1 -1
- package/dist/hooks-config.js +7 -6
- package/dist/hooks-config.js.map +1 -1
- package/dist/image-watcher.d.ts +4 -4
- package/dist/image-watcher.d.ts.map +1 -1
- package/dist/image-watcher.js +17 -30
- package/dist/image-watcher.js.map +1 -1
- package/dist/index.js +1 -2
- package/dist/index.js.map +1 -1
- package/dist/plan-orchestrator.d.ts +2 -24
- package/dist/plan-orchestrator.d.ts.map +1 -1
- package/dist/plan-orchestrator.js.map +1 -1
- package/dist/push-store.d.ts +1 -1
- package/dist/push-store.d.ts.map +1 -1
- package/dist/push-store.js +4 -12
- package/dist/push-store.js.map +1 -1
- package/dist/ralph-fix-plan-watcher.d.ts +91 -0
- package/dist/ralph-fix-plan-watcher.d.ts.map +1 -0
- package/dist/ralph-fix-plan-watcher.js +326 -0
- package/dist/ralph-fix-plan-watcher.js.map +1 -0
- package/dist/ralph-plan-tracker.d.ts +201 -0
- package/dist/ralph-plan-tracker.d.ts.map +1 -0
- package/dist/ralph-plan-tracker.js +325 -0
- package/dist/ralph-plan-tracker.js.map +1 -0
- package/dist/ralph-stall-detector.d.ts +84 -0
- package/dist/ralph-stall-detector.d.ts.map +1 -0
- package/dist/ralph-stall-detector.js +139 -0
- package/dist/ralph-stall-detector.js.map +1 -0
- package/dist/ralph-status-parser.d.ts +141 -0
- package/dist/ralph-status-parser.d.ts.map +1 -0
- package/dist/ralph-status-parser.js +478 -0
- package/dist/ralph-status-parser.js.map +1 -0
- package/dist/ralph-tracker.d.ts +194 -685
- package/dist/ralph-tracker.d.ts.map +1 -1
- package/dist/ralph-tracker.js +349 -1713
- package/dist/ralph-tracker.js.map +1 -1
- package/dist/respawn-adaptive-timing.d.ts +61 -0
- package/dist/respawn-adaptive-timing.d.ts.map +1 -0
- package/dist/respawn-adaptive-timing.js +105 -0
- package/dist/respawn-adaptive-timing.js.map +1 -0
- package/dist/respawn-controller.d.ts +14 -101
- package/dist/respawn-controller.d.ts.map +1 -1
- package/dist/respawn-controller.js +155 -594
- package/dist/respawn-controller.js.map +1 -1
- package/dist/respawn-health.d.ts +54 -0
- package/dist/respawn-health.d.ts.map +1 -0
- package/dist/respawn-health.js +183 -0
- package/dist/respawn-health.js.map +1 -0
- package/dist/respawn-metrics.d.ts +81 -0
- package/dist/respawn-metrics.d.ts.map +1 -0
- package/dist/respawn-metrics.js +198 -0
- package/dist/respawn-metrics.js.map +1 -0
- package/dist/respawn-patterns.d.ts +45 -0
- package/dist/respawn-patterns.d.ts.map +1 -0
- package/dist/respawn-patterns.js +125 -0
- package/dist/respawn-patterns.js.map +1 -0
- package/dist/session-auto-ops.d.ts +89 -0
- package/dist/session-auto-ops.d.ts.map +1 -0
- package/dist/session-auto-ops.js +224 -0
- package/dist/session-auto-ops.js.map +1 -0
- package/dist/session-cli-builder.d.ts +62 -0
- package/dist/session-cli-builder.d.ts.map +1 -0
- package/dist/session-cli-builder.js +121 -0
- package/dist/session-cli-builder.js.map +1 -0
- package/dist/session-task-cache.d.ts +52 -0
- package/dist/session-task-cache.d.ts.map +1 -0
- package/dist/session-task-cache.js +90 -0
- package/dist/session-task-cache.js.map +1 -0
- package/dist/session.d.ts +2 -33
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +58 -309
- package/dist/session.js.map +1 -1
- package/dist/state-store.d.ts +9 -2
- package/dist/state-store.d.ts.map +1 -1
- package/dist/state-store.js +112 -39
- package/dist/state-store.js.map +1 -1
- package/dist/subagent-watcher.d.ts +16 -9
- package/dist/subagent-watcher.d.ts.map +1 -1
- package/dist/subagent-watcher.js +126 -147
- package/dist/subagent-watcher.js.map +1 -1
- package/dist/team-watcher.d.ts +3 -0
- package/dist/team-watcher.d.ts.map +1 -1
- package/dist/team-watcher.js +54 -5
- package/dist/team-watcher.js.map +1 -1
- package/dist/tmux-manager.d.ts.map +1 -1
- package/dist/tmux-manager.js +1 -2
- package/dist/tmux-manager.js.map +1 -1
- package/dist/tunnel-manager.d.ts +26 -0
- package/dist/tunnel-manager.d.ts.map +1 -1
- package/dist/tunnel-manager.js +127 -7
- package/dist/tunnel-manager.js.map +1 -1
- package/dist/types/api.d.ts +93 -0
- package/dist/types/api.d.ts.map +1 -0
- package/dist/types/api.js +83 -0
- package/dist/types/api.js.map +1 -0
- package/dist/types/app-state.d.ts +100 -0
- package/dist/types/app-state.d.ts.map +1 -0
- package/dist/types/app-state.js +59 -0
- package/dist/types/app-state.js.map +1 -0
- package/dist/types/common.d.ts +70 -0
- package/dist/types/common.d.ts.map +1 -0
- package/dist/types/common.js +8 -0
- package/dist/types/common.js.map +1 -0
- package/dist/types/index.d.ts +18 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +18 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/lifecycle.d.ts +17 -0
- package/dist/types/lifecycle.d.ts.map +1 -0
- package/dist/types/lifecycle.js +5 -0
- package/dist/types/lifecycle.js.map +1 -0
- package/dist/types/plan.d.ts +32 -0
- package/dist/types/plan.d.ts.map +1 -0
- package/dist/types/plan.js +5 -0
- package/dist/types/plan.js.map +1 -0
- package/dist/types/push.d.ts +23 -0
- package/dist/types/push.d.ts.map +1 -0
- package/dist/types/push.js +5 -0
- package/dist/types/push.js.map +1 -0
- package/dist/types/ralph.d.ts +241 -0
- package/dist/types/ralph.d.ts.map +1 -0
- package/dist/types/ralph.js +49 -0
- package/dist/types/ralph.js.map +1 -0
- package/dist/types/respawn.d.ts +250 -0
- package/dist/types/respawn.d.ts.map +1 -0
- package/dist/types/respawn.js +5 -0
- package/dist/types/respawn.js.map +1 -0
- package/dist/types/run-summary.d.ts +81 -0
- package/dist/types/run-summary.d.ts.map +1 -0
- package/dist/types/run-summary.js +22 -0
- package/dist/types/run-summary.js.map +1 -0
- package/dist/types/session.d.ts +130 -0
- package/dist/types/session.d.ts.map +1 -0
- package/dist/types/session.js +5 -0
- package/dist/types/session.js.map +1 -0
- package/dist/types/task.d.ts +58 -0
- package/dist/types/task.d.ts.map +1 -0
- package/dist/types/task.js +5 -0
- package/dist/types/task.js.map +1 -0
- package/dist/types/teams.d.ts +55 -0
- package/dist/types/teams.d.ts.map +1 -0
- package/dist/types/teams.js +5 -0
- package/dist/types/teams.js.map +1 -0
- package/dist/types/tools.d.ts +46 -0
- package/dist/types/tools.d.ts.map +1 -0
- package/dist/types/tools.js +5 -0
- package/dist/types/tools.js.map +1 -0
- package/dist/types.d.ts +1 -1138
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -214
- package/dist/types.js.map +1 -1
- package/dist/utils/claude-cli-resolver.d.ts.map +1 -1
- package/dist/utils/claude-cli-resolver.js +1 -2
- package/dist/utils/claude-cli-resolver.js.map +1 -1
- package/dist/utils/debouncer.d.ts +111 -0
- package/dist/utils/debouncer.d.ts.map +1 -0
- package/dist/utils/debouncer.js +162 -0
- package/dist/utils/debouncer.js.map +1 -0
- package/dist/utils/index.d.ts +3 -2
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +3 -2
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/opencode-cli-resolver.d.ts.map +1 -1
- package/dist/utils/opencode-cli-resolver.js +1 -2
- package/dist/utils/opencode-cli-resolver.js.map +1 -1
- package/dist/utils/string-similarity.d.ts +0 -57
- package/dist/utils/string-similarity.d.ts.map +1 -1
- package/dist/utils/string-similarity.js +3 -18
- package/dist/utils/string-similarity.js.map +1 -1
- package/dist/web/middleware/auth.d.ts +31 -0
- package/dist/web/middleware/auth.d.ts.map +1 -0
- package/dist/web/middleware/auth.js +154 -0
- package/dist/web/middleware/auth.js.map +1 -0
- package/dist/web/ports/auth-port.d.ts +18 -0
- package/dist/web/ports/auth-port.d.ts.map +1 -0
- package/dist/web/ports/auth-port.js +6 -0
- package/dist/web/ports/auth-port.js.map +1 -0
- package/dist/web/ports/config-port.d.ts +28 -0
- package/dist/web/ports/config-port.d.ts.map +1 -0
- package/dist/web/ports/config-port.js +6 -0
- package/dist/web/ports/config-port.js.map +1 -0
- package/dist/web/ports/event-port.d.ts +13 -0
- package/dist/web/ports/event-port.d.ts.map +1 -0
- package/dist/web/ports/event-port.js +6 -0
- package/dist/web/ports/event-port.js.map +1 -0
- package/dist/web/ports/index.d.ts +14 -0
- package/dist/web/ports/index.d.ts.map +1 -0
- package/dist/web/ports/index.js +9 -0
- package/dist/web/ports/index.js.map +1 -0
- package/dist/web/ports/infra-port.d.ts +36 -0
- package/dist/web/ports/infra-port.d.ts.map +1 -0
- package/dist/web/ports/infra-port.js +6 -0
- package/dist/web/ports/infra-port.js.map +1 -0
- package/dist/web/ports/respawn-port.d.ts +20 -0
- package/dist/web/ports/respawn-port.d.ts.map +1 -0
- package/dist/web/ports/respawn-port.js +6 -0
- package/dist/web/ports/respawn-port.js.map +1 -0
- package/dist/web/ports/session-port.d.ts +15 -0
- package/dist/web/ports/session-port.d.ts.map +1 -0
- package/dist/web/ports/session-port.js +6 -0
- package/dist/web/ports/session-port.js.map +1 -0
- package/dist/web/public/api-client.js +70 -0
- package/dist/web/public/api-client.js.br +0 -0
- package/dist/web/public/api-client.js.gz +0 -0
- package/dist/web/public/app.js +152 -236
- package/dist/web/public/app.js.br +0 -0
- package/dist/web/public/app.js.gz +0 -0
- package/dist/web/public/constants.js +238 -0
- package/dist/web/public/constants.js.br +0 -0
- package/dist/web/public/constants.js.gz +0 -0
- package/dist/web/public/index.html +11 -3
- package/dist/web/public/index.html.br +0 -0
- package/dist/web/public/index.html.gz +0 -0
- package/dist/web/public/keyboard-accessory.js +279 -0
- package/dist/web/public/keyboard-accessory.js.br +0 -0
- package/dist/web/public/keyboard-accessory.js.gz +0 -0
- package/dist/web/public/mobile-handlers.js +467 -0
- package/dist/web/public/mobile-handlers.js.br +0 -0
- package/dist/web/public/mobile-handlers.js.gz +0 -0
- package/dist/web/public/mobile.css.gz +0 -0
- package/dist/web/public/notification-manager.js +445 -0
- package/dist/web/public/notification-manager.js.br +0 -0
- package/dist/web/public/notification-manager.js.gz +0 -0
- package/dist/web/public/ralph-wizard.js +3 -3
- 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.gz +0 -0
- package/dist/web/public/subagent-windows.js +1115 -0
- package/dist/web/public/subagent-windows.js.br +0 -0
- package/dist/web/public/subagent-windows.js.gz +0 -0
- package/dist/web/public/sw.js.gz +0 -0
- package/dist/web/public/upload.html.gz +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.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-webgl.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm.css.gz +0 -0
- package/dist/web/public/vendor/xterm.min.js.gz +0 -0
- package/dist/web/public/voice-input.js +858 -0
- package/dist/web/public/voice-input.js.br +0 -0
- package/dist/web/public/voice-input.js.gz +0 -0
- package/dist/web/route-helpers.d.ts +38 -0
- package/dist/web/route-helpers.d.ts.map +1 -0
- package/dist/web/route-helpers.js +143 -0
- package/dist/web/route-helpers.js.map +1 -0
- package/dist/web/routes/case-routes.d.ts +9 -0
- package/dist/web/routes/case-routes.d.ts.map +1 -0
- package/dist/web/routes/case-routes.js +419 -0
- package/dist/web/routes/case-routes.js.map +1 -0
- package/dist/web/routes/file-routes.d.ts +8 -0
- package/dist/web/routes/file-routes.d.ts.map +1 -0
- package/dist/web/routes/file-routes.js +337 -0
- package/dist/web/routes/file-routes.js.map +1 -0
- package/dist/web/routes/hook-event-routes.d.ts +9 -0
- package/dist/web/routes/hook-event-routes.d.ts.map +1 -0
- package/dist/web/routes/hook-event-routes.js +57 -0
- package/dist/web/routes/hook-event-routes.js.map +1 -0
- package/dist/web/routes/index.d.ts +16 -0
- package/dist/web/routes/index.d.ts.map +1 -0
- package/dist/web/routes/index.js +16 -0
- package/dist/web/routes/index.js.map +1 -0
- package/dist/web/routes/mux-routes.d.ts +8 -0
- package/dist/web/routes/mux-routes.d.ts.map +1 -0
- package/dist/web/routes/mux-routes.js +32 -0
- package/dist/web/routes/mux-routes.js.map +1 -0
- package/dist/web/routes/plan-routes.d.ts +9 -0
- package/dist/web/routes/plan-routes.d.ts.map +1 -0
- package/dist/web/routes/plan-routes.js +381 -0
- package/dist/web/routes/plan-routes.js.map +1 -0
- package/dist/web/routes/push-routes.d.ts +8 -0
- package/dist/web/routes/push-routes.d.ts.map +1 -0
- package/dist/web/routes/push-routes.js +49 -0
- package/dist/web/routes/push-routes.js.map +1 -0
- package/dist/web/routes/ralph-routes.d.ts +9 -0
- package/dist/web/routes/ralph-routes.d.ts.map +1 -0
- package/dist/web/routes/ralph-routes.js +475 -0
- package/dist/web/routes/ralph-routes.js.map +1 -0
- package/dist/web/routes/respawn-routes.d.ts +8 -0
- package/dist/web/routes/respawn-routes.d.ts.map +1 -0
- package/dist/web/routes/respawn-routes.js +260 -0
- package/dist/web/routes/respawn-routes.js.map +1 -0
- package/dist/web/routes/scheduled-routes.d.ts +8 -0
- package/dist/web/routes/scheduled-routes.d.ts.map +1 -0
- package/dist/web/routes/scheduled-routes.js +51 -0
- package/dist/web/routes/scheduled-routes.js.map +1 -0
- package/dist/web/routes/session-routes.d.ts +9 -0
- package/dist/web/routes/session-routes.d.ts.map +1 -0
- package/dist/web/routes/session-routes.js +729 -0
- package/dist/web/routes/session-routes.js.map +1 -0
- package/dist/web/routes/system-routes.d.ts +9 -0
- package/dist/web/routes/system-routes.d.ts.map +1 -0
- package/dist/web/routes/system-routes.js +678 -0
- package/dist/web/routes/system-routes.js.map +1 -0
- package/dist/web/routes/team-routes.d.ts +8 -0
- package/dist/web/routes/team-routes.d.ts.map +1 -0
- package/dist/web/routes/team-routes.js +14 -0
- package/dist/web/routes/team-routes.js.map +1 -0
- package/dist/web/schemas.d.ts +43 -3
- package/dist/web/schemas.d.ts.map +1 -1
- package/dist/web/schemas.js +6 -2
- package/dist/web/schemas.js.map +1 -1
- package/dist/web/server.d.ts +10 -9
- package/dist/web/server.d.ts.map +1 -1
- package/dist/web/server.js +342 -3829
- package/dist/web/server.js.map +1 -1
- package/package.json +1 -1
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Shared helper functions for route modules.
|
|
3
|
+
*
|
|
4
|
+
* Contains pure functions extracted from server.ts and a session lookup helper
|
|
5
|
+
* that replaces ~43 inline not-found checks across route handlers.
|
|
6
|
+
*/
|
|
7
|
+
import { Session } from '../session.js';
|
|
8
|
+
import type { SessionPort } from './ports/session-port.js';
|
|
9
|
+
import type { EventPort } from './ports/event-port.js';
|
|
10
|
+
export declare const CASES_DIR: string;
|
|
11
|
+
export declare const SETTINGS_PATH: string;
|
|
12
|
+
/**
|
|
13
|
+
* Look up a session by ID or throw a structured error.
|
|
14
|
+
* Replaces the pattern: `const session = sessions.get(id); if (!session) return createErrorResponse(...)`.
|
|
15
|
+
*/
|
|
16
|
+
export declare function findSessionOrFail(ctx: SessionPort, sessionId: string): Session;
|
|
17
|
+
/**
|
|
18
|
+
* Formats uptime in seconds to a human-readable string (e.g., "1d 2h 30m 15s").
|
|
19
|
+
*/
|
|
20
|
+
export declare function formatUptime(seconds: number): string;
|
|
21
|
+
/**
|
|
22
|
+
* Sanitizes hook event data before broadcasting via SSE.
|
|
23
|
+
* Extracts only relevant fields and limits total size to prevent
|
|
24
|
+
* oversized payloads from being broadcast to all connected clients.
|
|
25
|
+
*/
|
|
26
|
+
export declare function sanitizeHookData(data: Record<string, unknown> | null | undefined): Record<string, unknown>;
|
|
27
|
+
/**
|
|
28
|
+
* Auto-configure Ralph tracker for a session.
|
|
29
|
+
*
|
|
30
|
+
* Priority order:
|
|
31
|
+
* 1. .claude/ralph-loop.local.md (official Ralph Wiggum plugin state)
|
|
32
|
+
* 2. CLAUDE.md <promise> tags (fallback)
|
|
33
|
+
*
|
|
34
|
+
* The ralph-loop.local.md file has priority because it contains
|
|
35
|
+
* the exact configuration from an active Ralph loop session.
|
|
36
|
+
*/
|
|
37
|
+
export declare function autoConfigureRalph(session: Session, workingDir: string, ctx: EventPort): void;
|
|
38
|
+
//# sourceMappingURL=route-helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-helpers.d.ts","sourceRoot":"","sources":["../../src/web/route-helpers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAGxC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAGvD,eAAO,MAAM,SAAS,QAAmC,CAAC;AAC1D,eAAO,MAAM,aAAa,QAA+C,CAAC;AAK1E;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAS9E;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAapD;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA2C1G;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,GAAG,IAAI,CAsC7F"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Shared helper functions for route modules.
|
|
3
|
+
*
|
|
4
|
+
* Contains pure functions extracted from server.ts and a session lookup helper
|
|
5
|
+
* that replaces ~43 inline not-found checks across route handlers.
|
|
6
|
+
*/
|
|
7
|
+
import { join } from 'node:path';
|
|
8
|
+
import { homedir } from 'node:os';
|
|
9
|
+
import { ApiErrorCode, createErrorResponse } from '../types.js';
|
|
10
|
+
import { parseRalphLoopConfig, extractCompletionPhrase } from '../ralph-config.js';
|
|
11
|
+
// Shared path constants used across route modules
|
|
12
|
+
export const CASES_DIR = join(homedir(), 'codeman-cases');
|
|
13
|
+
export const SETTINGS_PATH = join(homedir(), '.codeman', 'settings.json');
|
|
14
|
+
// Maximum hook data size (prevents oversized SSE broadcasts)
|
|
15
|
+
const MAX_HOOK_DATA_SIZE = 8 * 1024;
|
|
16
|
+
/**
|
|
17
|
+
* Look up a session by ID or throw a structured error.
|
|
18
|
+
* Replaces the pattern: `const session = sessions.get(id); if (!session) return createErrorResponse(...)`.
|
|
19
|
+
*/
|
|
20
|
+
export function findSessionOrFail(ctx, sessionId) {
|
|
21
|
+
const session = ctx.sessions.get(sessionId);
|
|
22
|
+
if (!session) {
|
|
23
|
+
throw Object.assign(new Error(`Session ${sessionId} not found`), {
|
|
24
|
+
statusCode: 404,
|
|
25
|
+
body: createErrorResponse(ApiErrorCode.NOT_FOUND, `Session ${sessionId} not found`),
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
return session;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Formats uptime in seconds to a human-readable string (e.g., "1d 2h 30m 15s").
|
|
32
|
+
*/
|
|
33
|
+
export function formatUptime(seconds) {
|
|
34
|
+
const days = Math.floor(seconds / 86400);
|
|
35
|
+
const hours = Math.floor((seconds % 86400) / 3600);
|
|
36
|
+
const minutes = Math.floor((seconds % 3600) / 60);
|
|
37
|
+
const secs = Math.floor(seconds % 60);
|
|
38
|
+
const parts = [];
|
|
39
|
+
if (days > 0)
|
|
40
|
+
parts.push(`${days}d`);
|
|
41
|
+
if (hours > 0)
|
|
42
|
+
parts.push(`${hours}h`);
|
|
43
|
+
if (minutes > 0)
|
|
44
|
+
parts.push(`${minutes}m`);
|
|
45
|
+
if (secs > 0 || parts.length === 0)
|
|
46
|
+
parts.push(`${secs}s`);
|
|
47
|
+
return parts.join(' ');
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Sanitizes hook event data before broadcasting via SSE.
|
|
51
|
+
* Extracts only relevant fields and limits total size to prevent
|
|
52
|
+
* oversized payloads from being broadcast to all connected clients.
|
|
53
|
+
*/
|
|
54
|
+
export function sanitizeHookData(data) {
|
|
55
|
+
if (!data || typeof data !== 'object')
|
|
56
|
+
return {};
|
|
57
|
+
// Only forward known safe fields from Claude Code hook stdin
|
|
58
|
+
const safeFields = {};
|
|
59
|
+
const allowedKeys = [
|
|
60
|
+
'hook_event_name',
|
|
61
|
+
'tool_name',
|
|
62
|
+
'tool_input',
|
|
63
|
+
'session_id',
|
|
64
|
+
'cwd',
|
|
65
|
+
'permission_mode',
|
|
66
|
+
'stop_hook_active',
|
|
67
|
+
'transcript_path',
|
|
68
|
+
];
|
|
69
|
+
for (const key of allowedKeys) {
|
|
70
|
+
if (key in data && data[key] !== undefined) {
|
|
71
|
+
safeFields[key] = data[key];
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// For tool_input, extract only summary fields (not full file content)
|
|
75
|
+
if (safeFields.tool_input && typeof safeFields.tool_input === 'object') {
|
|
76
|
+
const input = safeFields.tool_input;
|
|
77
|
+
const summary = {};
|
|
78
|
+
if (input.command)
|
|
79
|
+
summary.command = String(input.command).slice(0, 500);
|
|
80
|
+
if (input.file_path)
|
|
81
|
+
summary.file_path = String(input.file_path).slice(0, 500);
|
|
82
|
+
if (input.description)
|
|
83
|
+
summary.description = String(input.description).slice(0, 200);
|
|
84
|
+
if (input.query)
|
|
85
|
+
summary.query = String(input.query).slice(0, 200);
|
|
86
|
+
if (input.url)
|
|
87
|
+
summary.url = String(input.url).slice(0, 500);
|
|
88
|
+
if (input.pattern)
|
|
89
|
+
summary.pattern = String(input.pattern).slice(0, 200);
|
|
90
|
+
if (input.prompt)
|
|
91
|
+
summary.prompt = String(input.prompt).slice(0, 200);
|
|
92
|
+
safeFields.tool_input = summary;
|
|
93
|
+
}
|
|
94
|
+
// Final size check - drop if serialized data exceeds limit
|
|
95
|
+
const serialized = JSON.stringify(safeFields);
|
|
96
|
+
if (serialized.length > MAX_HOOK_DATA_SIZE) {
|
|
97
|
+
return { tool_name: safeFields.tool_name, _truncated: true };
|
|
98
|
+
}
|
|
99
|
+
return safeFields;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Auto-configure Ralph tracker for a session.
|
|
103
|
+
*
|
|
104
|
+
* Priority order:
|
|
105
|
+
* 1. .claude/ralph-loop.local.md (official Ralph Wiggum plugin state)
|
|
106
|
+
* 2. CLAUDE.md <promise> tags (fallback)
|
|
107
|
+
*
|
|
108
|
+
* The ralph-loop.local.md file has priority because it contains
|
|
109
|
+
* the exact configuration from an active Ralph loop session.
|
|
110
|
+
*/
|
|
111
|
+
export function autoConfigureRalph(session, workingDir, ctx) {
|
|
112
|
+
// First, try to read the official Ralph Wiggum plugin state file
|
|
113
|
+
const ralphConfig = parseRalphLoopConfig(workingDir);
|
|
114
|
+
if (ralphConfig && ralphConfig.completionPromise) {
|
|
115
|
+
session.ralphTracker.enable();
|
|
116
|
+
session.ralphTracker.startLoop(ralphConfig.completionPromise, ralphConfig.maxIterations ?? undefined);
|
|
117
|
+
// Restore iteration count if available
|
|
118
|
+
if (ralphConfig.iteration > 0) {
|
|
119
|
+
// The tracker's cycleCount will be updated when we detect iteration patterns
|
|
120
|
+
// in the terminal output, but we can set maxIterations now
|
|
121
|
+
console.log(`[auto-detect] Ralph loop at iteration ${ralphConfig.iteration}/${ralphConfig.maxIterations ?? '∞'}`);
|
|
122
|
+
}
|
|
123
|
+
console.log(`[auto-detect] Configured Ralph loop for session ${session.id} from ralph-loop.local.md: ${ralphConfig.completionPromise}`);
|
|
124
|
+
ctx.broadcast('session:ralphLoopUpdate', {
|
|
125
|
+
sessionId: session.id,
|
|
126
|
+
state: session.ralphTracker.loopState,
|
|
127
|
+
});
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
// Fallback: try CLAUDE.md
|
|
131
|
+
const claudeMdPath = join(workingDir, 'CLAUDE.md');
|
|
132
|
+
const completionPhrase = extractCompletionPhrase(claudeMdPath);
|
|
133
|
+
if (completionPhrase) {
|
|
134
|
+
session.ralphTracker.enable();
|
|
135
|
+
session.ralphTracker.startLoop(completionPhrase);
|
|
136
|
+
console.log(`[auto-detect] Configured Ralph loop for session ${session.id} from CLAUDE.md: ${completionPhrase}`);
|
|
137
|
+
ctx.broadcast('session:ralphLoopUpdate', {
|
|
138
|
+
sessionId: session.id,
|
|
139
|
+
state: session.ralphTracker.loopState,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=route-helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-helpers.js","sourceRoot":"","sources":["../../src/web/route-helpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Case management routes.
|
|
3
|
+
* Handles CRUD for cases (directories under ~/codeman-cases and linked folders),
|
|
4
|
+
* fix-plan reading, and ralph-wizard file serving.
|
|
5
|
+
*/
|
|
6
|
+
import { FastifyInstance } from 'fastify';
|
|
7
|
+
import type { EventPort, ConfigPort } from '../ports/index.js';
|
|
8
|
+
export declare function registerCaseRoutes(app: FastifyInstance, ctx: EventPort & ConfigPort): void;
|
|
9
|
+
//# sourceMappingURL=case-routes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"case-routes.d.ts","sourceRoot":"","sources":["../../../src/web/routes/case-routes.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAW1C,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/D,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,SAAS,GAAG,UAAU,GAAG,IAAI,CA4c1F"}
|
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Case management routes.
|
|
3
|
+
* Handles CRUD for cases (directories under ~/codeman-cases and linked folders),
|
|
4
|
+
* fix-plan reading, and ralph-wizard file serving.
|
|
5
|
+
*/
|
|
6
|
+
import { existsSync, mkdirSync, writeFileSync, readdirSync } from 'node:fs';
|
|
7
|
+
import fs from 'node:fs/promises';
|
|
8
|
+
import { join, resolve, relative, isAbsolute } from 'node:path';
|
|
9
|
+
import { homedir } from 'node:os';
|
|
10
|
+
import { ApiErrorCode, createErrorResponse, getErrorMessage } from '../../types.js';
|
|
11
|
+
import { CreateCaseSchema, LinkCaseSchema } from '../schemas.js';
|
|
12
|
+
import { generateClaudeMd } from '../../templates/claude-md.js';
|
|
13
|
+
import { writeHooksConfig } from '../../hooks-config.js';
|
|
14
|
+
import { CASES_DIR } from '../route-helpers.js';
|
|
15
|
+
export function registerCaseRoutes(app, ctx) {
|
|
16
|
+
// ============ Case CRUD ============
|
|
17
|
+
app.get('/api/cases', async () => {
|
|
18
|
+
const cases = [];
|
|
19
|
+
// Get cases from CASES_DIR
|
|
20
|
+
try {
|
|
21
|
+
const entries = await fs.readdir(CASES_DIR, { withFileTypes: true });
|
|
22
|
+
for (const e of entries) {
|
|
23
|
+
if (e.isDirectory()) {
|
|
24
|
+
cases.push({
|
|
25
|
+
name: e.name,
|
|
26
|
+
path: join(CASES_DIR, e.name),
|
|
27
|
+
hasClaudeMd: existsSync(join(CASES_DIR, e.name, 'CLAUDE.md')),
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// CASES_DIR may not exist yet
|
|
34
|
+
}
|
|
35
|
+
// Get linked cases
|
|
36
|
+
const linkedCasesFile = join(homedir(), '.codeman', 'linked-cases.json');
|
|
37
|
+
try {
|
|
38
|
+
const linkedCases = JSON.parse(await fs.readFile(linkedCasesFile, 'utf-8'));
|
|
39
|
+
for (const [name, path] of Object.entries(linkedCases)) {
|
|
40
|
+
// Only add if not already in cases (avoid duplicates) and path exists
|
|
41
|
+
if (!cases.some((c) => c.name === name) && existsSync(path)) {
|
|
42
|
+
cases.push({
|
|
43
|
+
name,
|
|
44
|
+
path,
|
|
45
|
+
hasClaudeMd: existsSync(join(path, 'CLAUDE.md')),
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
if (err.code !== 'ENOENT') {
|
|
52
|
+
console.warn('[Server] Failed to read linked cases:', err);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return cases;
|
|
56
|
+
});
|
|
57
|
+
app.post('/api/cases', async (req) => {
|
|
58
|
+
const result = CreateCaseSchema.safeParse(req.body);
|
|
59
|
+
if (!result.success) {
|
|
60
|
+
return createErrorResponse(ApiErrorCode.INVALID_INPUT, result.error.issues[0]?.message ?? 'Validation failed');
|
|
61
|
+
}
|
|
62
|
+
const { name, description } = result.data;
|
|
63
|
+
const casePath = join(CASES_DIR, name);
|
|
64
|
+
// Security: Path traversal protection - use relative path check
|
|
65
|
+
const resolvedPath = resolve(casePath);
|
|
66
|
+
const resolvedBase = resolve(CASES_DIR);
|
|
67
|
+
const relPath = relative(resolvedBase, resolvedPath);
|
|
68
|
+
if (relPath.startsWith('..') || isAbsolute(relPath)) {
|
|
69
|
+
return createErrorResponse(ApiErrorCode.INVALID_INPUT, 'Invalid case path');
|
|
70
|
+
}
|
|
71
|
+
if (existsSync(casePath)) {
|
|
72
|
+
return createErrorResponse(ApiErrorCode.ALREADY_EXISTS, 'Case already exists');
|
|
73
|
+
}
|
|
74
|
+
try {
|
|
75
|
+
mkdirSync(casePath, { recursive: true });
|
|
76
|
+
mkdirSync(join(casePath, 'src'), { recursive: true });
|
|
77
|
+
// Read settings to get custom template path
|
|
78
|
+
const templatePath = await ctx.getDefaultClaudeMdPath();
|
|
79
|
+
const claudeMd = generateClaudeMd(name, description || '', templatePath);
|
|
80
|
+
writeFileSync(join(casePath, 'CLAUDE.md'), claudeMd);
|
|
81
|
+
// Write .claude/settings.local.json with hooks for desktop notifications
|
|
82
|
+
await writeHooksConfig(casePath);
|
|
83
|
+
ctx.broadcast('case:created', { name, path: casePath });
|
|
84
|
+
return { success: true, data: { case: { name, path: casePath } } };
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
return createErrorResponse(ApiErrorCode.OPERATION_FAILED, getErrorMessage(err));
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
// Link an existing folder as a case
|
|
91
|
+
app.post('/api/cases/link', async (req) => {
|
|
92
|
+
const lcResult = LinkCaseSchema.safeParse(req.body);
|
|
93
|
+
if (!lcResult.success) {
|
|
94
|
+
return createErrorResponse(ApiErrorCode.INVALID_INPUT, 'Invalid request body');
|
|
95
|
+
}
|
|
96
|
+
const { name, path: folderPath } = lcResult.data;
|
|
97
|
+
// Expand ~ to home directory
|
|
98
|
+
const expandedPath = folderPath.startsWith('~') ? join(homedir(), folderPath.slice(1)) : folderPath;
|
|
99
|
+
// Validate the folder exists
|
|
100
|
+
if (!existsSync(expandedPath)) {
|
|
101
|
+
return createErrorResponse(ApiErrorCode.NOT_FOUND, `Folder not found: ${expandedPath}`);
|
|
102
|
+
}
|
|
103
|
+
// Check if case name already exists in CASES_DIR
|
|
104
|
+
const casePath = join(CASES_DIR, name);
|
|
105
|
+
if (existsSync(casePath)) {
|
|
106
|
+
return createErrorResponse(ApiErrorCode.ALREADY_EXISTS, 'A case with this name already exists in codeman-cases.');
|
|
107
|
+
}
|
|
108
|
+
// Load existing linked cases
|
|
109
|
+
const linkedCasesFile = join(homedir(), '.codeman', 'linked-cases.json');
|
|
110
|
+
let linkedCases = {};
|
|
111
|
+
try {
|
|
112
|
+
linkedCases = JSON.parse(await fs.readFile(linkedCasesFile, 'utf-8'));
|
|
113
|
+
}
|
|
114
|
+
catch (err) {
|
|
115
|
+
if (err.code !== 'ENOENT') {
|
|
116
|
+
console.warn('[Server] Failed to read linked cases:', err);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// Check if name is already linked
|
|
120
|
+
if (linkedCases[name]) {
|
|
121
|
+
return createErrorResponse(ApiErrorCode.ALREADY_EXISTS, `Case "${name}" is already linked to ${linkedCases[name]}`);
|
|
122
|
+
}
|
|
123
|
+
// Save the linked case
|
|
124
|
+
linkedCases[name] = expandedPath;
|
|
125
|
+
try {
|
|
126
|
+
const codemanDir = join(homedir(), '.codeman');
|
|
127
|
+
if (!existsSync(codemanDir)) {
|
|
128
|
+
mkdirSync(codemanDir, { recursive: true });
|
|
129
|
+
}
|
|
130
|
+
await fs.writeFile(linkedCasesFile, JSON.stringify(linkedCases, null, 2));
|
|
131
|
+
ctx.broadcast('case:linked', { name, path: expandedPath });
|
|
132
|
+
return { success: true, data: { case: { name, path: expandedPath } } };
|
|
133
|
+
}
|
|
134
|
+
catch (err) {
|
|
135
|
+
return createErrorResponse(ApiErrorCode.OPERATION_FAILED, getErrorMessage(err));
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
app.get('/api/cases/:name', async (req) => {
|
|
139
|
+
const { name } = req.params;
|
|
140
|
+
// Security: Path traversal protection
|
|
141
|
+
const resolvedPath = resolve(join(CASES_DIR, name));
|
|
142
|
+
const resolvedBase = resolve(CASES_DIR);
|
|
143
|
+
const relPath = relative(resolvedBase, resolvedPath);
|
|
144
|
+
if (relPath.startsWith('..') || isAbsolute(relPath)) {
|
|
145
|
+
return createErrorResponse(ApiErrorCode.INVALID_INPUT, 'Invalid case name');
|
|
146
|
+
}
|
|
147
|
+
// First check linked cases
|
|
148
|
+
const linkedCasesFile = join(homedir(), '.codeman', 'linked-cases.json');
|
|
149
|
+
try {
|
|
150
|
+
const linkedCases = JSON.parse(await fs.readFile(linkedCasesFile, 'utf-8'));
|
|
151
|
+
if (linkedCases[name]) {
|
|
152
|
+
const linkedPath = linkedCases[name];
|
|
153
|
+
return {
|
|
154
|
+
name,
|
|
155
|
+
path: linkedPath,
|
|
156
|
+
hasClaudeMd: existsSync(join(linkedPath, 'CLAUDE.md')),
|
|
157
|
+
linked: true,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
// ENOENT or parse errors - fall through to CASES_DIR check
|
|
163
|
+
}
|
|
164
|
+
// Then check CASES_DIR
|
|
165
|
+
const casePath = join(CASES_DIR, name);
|
|
166
|
+
if (!existsSync(casePath)) {
|
|
167
|
+
return createErrorResponse(ApiErrorCode.NOT_FOUND, 'Case not found');
|
|
168
|
+
}
|
|
169
|
+
return {
|
|
170
|
+
name,
|
|
171
|
+
path: casePath,
|
|
172
|
+
hasClaudeMd: existsSync(join(casePath, 'CLAUDE.md')),
|
|
173
|
+
};
|
|
174
|
+
});
|
|
175
|
+
// Read @fix_plan.md from a case directory (for wizard to detect existing plans)
|
|
176
|
+
app.get('/api/cases/:name/fix-plan', async (req) => {
|
|
177
|
+
const { name } = req.params;
|
|
178
|
+
// Security: Path traversal protection
|
|
179
|
+
const resolvedPath = resolve(join(CASES_DIR, name));
|
|
180
|
+
const resolvedBase = resolve(CASES_DIR);
|
|
181
|
+
const relPath = relative(resolvedBase, resolvedPath);
|
|
182
|
+
if (relPath.startsWith('..') || isAbsolute(relPath)) {
|
|
183
|
+
return createErrorResponse(ApiErrorCode.INVALID_INPUT, 'Invalid case name');
|
|
184
|
+
}
|
|
185
|
+
// Get case path (check linked cases first, then CASES_DIR)
|
|
186
|
+
let casePath = null;
|
|
187
|
+
const linkedCasesFile = join(homedir(), '.codeman', 'linked-cases.json');
|
|
188
|
+
try {
|
|
189
|
+
const linkedCases = JSON.parse(await fs.readFile(linkedCasesFile, 'utf-8'));
|
|
190
|
+
if (linkedCases[name]) {
|
|
191
|
+
casePath = linkedCases[name];
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
// ENOENT or parse errors - fall through to CASES_DIR
|
|
196
|
+
}
|
|
197
|
+
if (!casePath) {
|
|
198
|
+
casePath = join(CASES_DIR, name);
|
|
199
|
+
}
|
|
200
|
+
const fixPlanPath = join(casePath, '@fix_plan.md');
|
|
201
|
+
if (!existsSync(fixPlanPath)) {
|
|
202
|
+
return { success: true, exists: false, content: null, todos: [] };
|
|
203
|
+
}
|
|
204
|
+
try {
|
|
205
|
+
const content = await fs.readFile(fixPlanPath, 'utf-8');
|
|
206
|
+
// Parse todos from the content (similar to ralph-tracker's importFixPlanMarkdown)
|
|
207
|
+
const todos = [];
|
|
208
|
+
const todoPattern = /^-\s*\[([ xX-])\]\s*(.+)$/;
|
|
209
|
+
const p0HeaderPattern = /^##\s*(High Priority|Critical|P0|Critical Path)/i;
|
|
210
|
+
const p1HeaderPattern = /^##\s*(Standard|P1|Medium Priority)/i;
|
|
211
|
+
const p2HeaderPattern = /^##\s*(Nice to Have|P2|Low Priority)/i;
|
|
212
|
+
const completedHeaderPattern = /^##\s*Completed/i;
|
|
213
|
+
let currentPriority = null;
|
|
214
|
+
let inCompletedSection = false;
|
|
215
|
+
for (const line of content.split('\n')) {
|
|
216
|
+
const trimmed = line.trim();
|
|
217
|
+
if (p0HeaderPattern.test(trimmed)) {
|
|
218
|
+
currentPriority = 'P0';
|
|
219
|
+
inCompletedSection = false;
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
if (p1HeaderPattern.test(trimmed)) {
|
|
223
|
+
currentPriority = 'P1';
|
|
224
|
+
inCompletedSection = false;
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
if (p2HeaderPattern.test(trimmed)) {
|
|
228
|
+
currentPriority = 'P2';
|
|
229
|
+
inCompletedSection = false;
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
if (completedHeaderPattern.test(trimmed)) {
|
|
233
|
+
inCompletedSection = true;
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
const match = trimmed.match(todoPattern);
|
|
237
|
+
if (match) {
|
|
238
|
+
const [, checkboxState, taskContent] = match;
|
|
239
|
+
let status;
|
|
240
|
+
if (inCompletedSection || checkboxState === 'x' || checkboxState === 'X') {
|
|
241
|
+
status = 'completed';
|
|
242
|
+
}
|
|
243
|
+
else if (checkboxState === '-') {
|
|
244
|
+
status = 'in_progress';
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
status = 'pending';
|
|
248
|
+
}
|
|
249
|
+
todos.push({
|
|
250
|
+
content: taskContent.trim(),
|
|
251
|
+
status,
|
|
252
|
+
priority: inCompletedSection ? null : currentPriority,
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
// Calculate stats in a single pass for better performance
|
|
257
|
+
let pending = 0, inProgress = 0, completed = 0;
|
|
258
|
+
for (const t of todos) {
|
|
259
|
+
if (t.status === 'pending')
|
|
260
|
+
pending++;
|
|
261
|
+
else if (t.status === 'in_progress')
|
|
262
|
+
inProgress++;
|
|
263
|
+
else if (t.status === 'completed')
|
|
264
|
+
completed++;
|
|
265
|
+
}
|
|
266
|
+
const stats = { total: todos.length, pending, inProgress, completed };
|
|
267
|
+
return {
|
|
268
|
+
success: true,
|
|
269
|
+
exists: true,
|
|
270
|
+
content,
|
|
271
|
+
todos,
|
|
272
|
+
stats,
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
catch (err) {
|
|
276
|
+
return createErrorResponse(ApiErrorCode.OPERATION_FAILED, `Failed to read @fix_plan.md: ${err}`);
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
// ============ Ralph Wizard File Endpoints ============
|
|
280
|
+
app.get('/api/cases/:caseName/ralph-wizard/files', async (req) => {
|
|
281
|
+
const { caseName } = req.params;
|
|
282
|
+
let casePath = join(CASES_DIR, caseName);
|
|
283
|
+
// Security: Path traversal protection - use relative path check
|
|
284
|
+
const resolvedCase = resolve(casePath);
|
|
285
|
+
const resolvedBase = resolve(CASES_DIR);
|
|
286
|
+
const relPath = relative(resolvedBase, resolvedCase);
|
|
287
|
+
if (relPath.startsWith('..') || isAbsolute(relPath)) {
|
|
288
|
+
return createErrorResponse(ApiErrorCode.INVALID_INPUT, 'Invalid case name');
|
|
289
|
+
}
|
|
290
|
+
// Check linked cases if path doesn't exist
|
|
291
|
+
if (!existsSync(casePath)) {
|
|
292
|
+
const linkedCasesFile = join(homedir(), '.codeman', 'linked-cases.json');
|
|
293
|
+
try {
|
|
294
|
+
const linkedCases = JSON.parse(await fs.readFile(linkedCasesFile, 'utf-8'));
|
|
295
|
+
if (linkedCases[caseName]) {
|
|
296
|
+
casePath = linkedCases[caseName];
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
catch {
|
|
300
|
+
// No linked cases file
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
const wizardDir = join(casePath, 'ralph-wizard');
|
|
304
|
+
if (!existsSync(wizardDir)) {
|
|
305
|
+
return createErrorResponse(ApiErrorCode.NOT_FOUND, 'Ralph wizard directory not found');
|
|
306
|
+
}
|
|
307
|
+
// List all subdirectories and their files
|
|
308
|
+
const files = [];
|
|
309
|
+
const entries = readdirSync(wizardDir, { withFileTypes: true });
|
|
310
|
+
for (const entry of entries) {
|
|
311
|
+
if (entry.isDirectory()) {
|
|
312
|
+
const agentDir = join(wizardDir, entry.name);
|
|
313
|
+
const agentFiles = {
|
|
314
|
+
agentType: entry.name,
|
|
315
|
+
};
|
|
316
|
+
if (existsSync(join(agentDir, 'prompt.md'))) {
|
|
317
|
+
agentFiles.promptFile = `${entry.name}/prompt.md`;
|
|
318
|
+
}
|
|
319
|
+
if (existsSync(join(agentDir, 'result.json'))) {
|
|
320
|
+
agentFiles.resultFile = `${entry.name}/result.json`;
|
|
321
|
+
}
|
|
322
|
+
if (agentFiles.promptFile || agentFiles.resultFile) {
|
|
323
|
+
files.push(agentFiles);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
return { success: true, data: { files, caseName } };
|
|
328
|
+
});
|
|
329
|
+
// Read a specific ralph-wizard file
|
|
330
|
+
// Cache disabled to ensure fresh prompts when starting new plan generations
|
|
331
|
+
app.get('/api/cases/:caseName/ralph-wizard/file/:filePath', async (req, reply) => {
|
|
332
|
+
const { caseName, filePath } = req.params;
|
|
333
|
+
let casePath = join(CASES_DIR, caseName);
|
|
334
|
+
// Prevent browser caching - prompts change between plan generations
|
|
335
|
+
reply.header('Cache-Control', 'no-store, no-cache, must-revalidate');
|
|
336
|
+
reply.header('Pragma', 'no-cache');
|
|
337
|
+
reply.header('Expires', '0');
|
|
338
|
+
// Security: Path traversal protection for case name - use relative path check
|
|
339
|
+
const resolvedCase = resolve(casePath);
|
|
340
|
+
const resolvedBase = resolve(CASES_DIR);
|
|
341
|
+
const relPath = relative(resolvedBase, resolvedCase);
|
|
342
|
+
if (relPath.startsWith('..') || isAbsolute(relPath)) {
|
|
343
|
+
return createErrorResponse(ApiErrorCode.INVALID_INPUT, 'Invalid case name');
|
|
344
|
+
}
|
|
345
|
+
// Check linked cases if path doesn't exist
|
|
346
|
+
if (!existsSync(casePath)) {
|
|
347
|
+
const linkedCasesFile = join(homedir(), '.codeman', 'linked-cases.json');
|
|
348
|
+
try {
|
|
349
|
+
const linkedCases = JSON.parse(await fs.readFile(linkedCasesFile, 'utf-8'));
|
|
350
|
+
if (linkedCases[caseName]) {
|
|
351
|
+
casePath = linkedCases[caseName];
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
catch {
|
|
355
|
+
// No linked cases file
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
const wizardDir = join(casePath, 'ralph-wizard');
|
|
359
|
+
// Decode the file path (it may be URL encoded)
|
|
360
|
+
const decodedPath = decodeURIComponent(filePath);
|
|
361
|
+
const fullPath = join(wizardDir, decodedPath);
|
|
362
|
+
// Security: ensure path is within wizard directory
|
|
363
|
+
const resolvedPath = resolve(fullPath);
|
|
364
|
+
const resolvedWizard = resolve(wizardDir);
|
|
365
|
+
if (!resolvedPath.startsWith(resolvedWizard)) {
|
|
366
|
+
return createErrorResponse(ApiErrorCode.INVALID_INPUT, 'Invalid file path');
|
|
367
|
+
}
|
|
368
|
+
let content;
|
|
369
|
+
try {
|
|
370
|
+
content = await fs.readFile(fullPath, 'utf-8');
|
|
371
|
+
}
|
|
372
|
+
catch (err) {
|
|
373
|
+
if (err.code === 'ENOENT') {
|
|
374
|
+
return createErrorResponse(ApiErrorCode.NOT_FOUND, 'File not found');
|
|
375
|
+
}
|
|
376
|
+
throw err;
|
|
377
|
+
}
|
|
378
|
+
const isJson = filePath.endsWith('.json');
|
|
379
|
+
// Parse JSON content safely (may contain invalid JSON or unescaped control characters)
|
|
380
|
+
let parsed = null;
|
|
381
|
+
if (isJson) {
|
|
382
|
+
try {
|
|
383
|
+
parsed = JSON.parse(content);
|
|
384
|
+
}
|
|
385
|
+
catch {
|
|
386
|
+
// Try repairing common JSON issues (unescaped control characters, trailing commas)
|
|
387
|
+
try {
|
|
388
|
+
let repaired = content;
|
|
389
|
+
// Fix trailing commas before closing brackets
|
|
390
|
+
repaired = repaired.replace(/,(\s*[\]}])/g, '$1');
|
|
391
|
+
// Fix unescaped control characters within JSON strings
|
|
392
|
+
repaired = repaired.replace(/"([^"\\]|\\.)*"/g, (match) => {
|
|
393
|
+
return match
|
|
394
|
+
.replace(/\n/g, '\\n')
|
|
395
|
+
.replace(/\r/g, '\\r')
|
|
396
|
+
.replace(/\t/g, '\\t')
|
|
397
|
+
.replace(
|
|
398
|
+
// eslint-disable-next-line no-control-regex
|
|
399
|
+
/[\x00-\x1f]/g, (c) => `\\u${c.charCodeAt(0).toString(16).padStart(4, '0')}`);
|
|
400
|
+
});
|
|
401
|
+
parsed = JSON.parse(repaired);
|
|
402
|
+
}
|
|
403
|
+
catch {
|
|
404
|
+
// Still invalid - return null for parsed, content available as raw string
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
return {
|
|
409
|
+
success: true,
|
|
410
|
+
data: {
|
|
411
|
+
content,
|
|
412
|
+
filePath: decodedPath,
|
|
413
|
+
isJson,
|
|
414
|
+
parsed,
|
|
415
|
+
},
|
|
416
|
+
};
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
//# sourceMappingURL=case-routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"case-routes.js","sourceRoot":"","sources":["../../../src/web/routes/case-routes.ts"],"names":[],"mappings":"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"}
|