glad-web 1.0.46 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/README.md +4 -192
  2. package/THIRD_PARTY_NOTICES.md +27 -0
  3. package/bin/glad.cjs +56 -0
  4. package/package.json +19 -61
  5. package/README.zh-CN.md +0 -198
  6. package/assets/logo.svg +0 -43
  7. package/bin/cli.js +0 -65
  8. package/lib/ai-tools/demo/enhanced-demo.js +0 -625
  9. package/lib/ai-tools/demo/index.js +0 -24
  10. package/lib/ai-tools/demo/responses.js +0 -88
  11. package/lib/ai-tools/detector.js +0 -76
  12. package/lib/ai-tools/registry.js +0 -300
  13. package/lib/claude/cli-usage.js +0 -95
  14. package/lib/claude/config.js +0 -82
  15. package/lib/claude/structured-session.js +0 -884
  16. package/lib/claude/transcript-repository.js +0 -216
  17. package/lib/codex/image-store.js +0 -174
  18. package/lib/codex/structured-session.js +0 -1590
  19. package/lib/commands/config.js +0 -78
  20. package/lib/commands/tools.js +0 -128
  21. package/lib/commands/web.js +0 -605
  22. package/lib/config/constants.js +0 -17
  23. package/lib/config/manager.js +0 -108
  24. package/lib/git/service.js +0 -83
  25. package/lib/notifications/message-formatter.js +0 -94
  26. package/lib/notifications/notification-service.js +0 -143
  27. package/lib/notifications/serverchan-client.js +0 -58
  28. package/lib/notifications/serverchan-settings-store.js +0 -115
  29. package/lib/schedule/job-runner.js +0 -162
  30. package/lib/schedule/job-store.js +0 -167
  31. package/lib/schedule/key-sequences.js +0 -49
  32. package/lib/schedule/scheduler-service.js +0 -39
  33. package/lib/server/routes/notifications.js +0 -52
  34. package/lib/server/routes/providers.js +0 -114
  35. package/lib/server/routes/schedules.js +0 -54
  36. package/lib/server/routes/skillhub.js +0 -104
  37. package/lib/server/routes/usage.js +0 -23
  38. package/lib/server/routes/workspace.js +0 -77
  39. package/lib/session/buffer.js +0 -102
  40. package/lib/session/file-attachment-store.js +0 -168
  41. package/lib/session/pty-manager.js +0 -255
  42. package/lib/session/rendered-history.js +0 -225
  43. package/lib/session/session-manager.js +0 -1032
  44. package/lib/session/text-history.js +0 -274
  45. package/lib/skillhub/client.js +0 -121
  46. package/lib/skillhub/settings-store.js +0 -168
  47. package/lib/skillhub/skill-installer.js +0 -320
  48. package/lib/usage/ccusage-runner.js +0 -128
  49. package/lib/usage/source-catalog.js +0 -26
  50. package/lib/usage/usage-service.js +0 -226
  51. package/lib/utils/logger.js +0 -74
  52. package/lib/utils/pid.js +0 -67
  53. package/lib/utils/validation.js +0 -53
  54. package/lib/web/bootstrap.js +0 -34
  55. package/lib/web/claude.js +0 -1150
  56. package/lib/web/codex.js +0 -1045
  57. package/lib/web/composer.js +0 -493
  58. package/lib/web/core.js +0 -385
  59. package/lib/web/git.js +0 -535
  60. package/lib/web/gitgraph.js +0 -293
  61. package/lib/web/index.html +0 -547
  62. package/lib/web/layout.js +0 -69
  63. package/lib/web/notifications.js +0 -164
  64. package/lib/web/schedules.js +0 -245
  65. package/lib/web/session.js +0 -361
  66. package/lib/web/shell.js +0 -74
  67. package/lib/web/skillhub.js +0 -197
  68. package/lib/web/styles.css +0 -932
  69. package/lib/web/terminal-scroll.js +0 -81
  70. package/lib/web/theme.js +0 -60
  71. package/lib/web/timed-inputs.js +0 -216
  72. package/lib/web/usage.js +0 -323
  73. package/lib/workspace/service.js +0 -77
  74. package/scripts/check-syntax.js +0 -26
@@ -1,162 +0,0 @@
1
- const { sequenceForKey } = require('./key-sequences');
2
-
3
- function sleep(ms) {
4
- return new Promise(resolve => setTimeout(resolve, ms));
5
- }
6
-
7
- class SessionEndedError extends Error {
8
- constructor() {
9
- super('Session ended');
10
- this.code = 'SESSION_ENDED';
11
- }
12
- }
13
-
14
- class JobRunner {
15
- constructor({ createSession, getJob, updateJob, logger }) {
16
- this.createSession = createSession;
17
- this.getJob = getJob;
18
- this.updateJob = updateJob;
19
- this.logger = logger;
20
- this.running = new Set();
21
- }
22
-
23
- async run(jobId, options = {}) {
24
- const job = this.getJob(jobId);
25
- if (!job) throw new Error('Scheduled task not found');
26
- if (this.running.has(job.id)) {
27
- this.updateJob(job.id, {
28
- lastRunAt: Date.now(),
29
- lastRunStatus: 'skipped',
30
- lastRunMessage: 'Previous run is still active'
31
- });
32
- return { skipped: true, reason: 'Previous run is still active' };
33
- }
34
-
35
- this.running.add(job.id);
36
- this.updateJob(job.id, {
37
- running: true,
38
- lastRunAt: Date.now(),
39
- lastRunStatus: options.manual ? 'manual-running' : 'running',
40
- lastRunMessage: ''
41
- });
42
-
43
- let session = null;
44
- try {
45
- session = this.createSession({
46
- toolKey: job.target.toolKey,
47
- workingDirectory: job.target.workingDirectory,
48
- name: `${job.name}${options.manual ? ' (Test)' : ''}`
49
- });
50
-
51
- this.updateJob(job.id, {
52
- lastSessionId: session.id,
53
- lastRunMessage: `Started session ${session.id}`
54
- });
55
-
56
- const execute = async () => {
57
- try {
58
- await sleep(1000);
59
- await this.executeSteps(job, session);
60
- this.updateJob(job.id, {
61
- running: false,
62
- lastRunStatus: options.manual ? 'manual-success' : 'success',
63
- lastRunMessage: `Started session ${session.id}`,
64
- lastSessionId: session.id
65
- });
66
- } catch (error) {
67
- const ended = error && error.code === 'SESSION_ENDED';
68
- if (!ended) this.logger?.error?.(`Scheduled task failed: ${error.message}`);
69
- this.updateJob(job.id, {
70
- running: false,
71
- lastRunStatus: ended ? 'cancelled' : 'failed',
72
- lastRunMessage: ended ? 'Session ended' : error.message,
73
- lastSessionId: session?.id || null
74
- });
75
- if (!options.background) throw error;
76
- } finally {
77
- this.running.delete(job.id);
78
- this.updateJob(job.id, { running: false });
79
- }
80
- };
81
-
82
- if (options.background) {
83
- execute();
84
- return { success: true, sessionId: session.id };
85
- }
86
-
87
- await execute();
88
- return { success: true, sessionId: session.id };
89
- } catch (error) {
90
- if (!session) {
91
- this.running.delete(job.id);
92
- this.updateJob(job.id, { running: false });
93
- }
94
- this.logger?.error?.(`Scheduled task failed: ${error.message}`);
95
- this.updateJob(job.id, {
96
- running: false,
97
- lastRunStatus: 'failed',
98
- lastRunMessage: error.message,
99
- lastSessionId: session?.id || null
100
- });
101
- throw error;
102
- }
103
- }
104
-
105
- async executeSteps(job, session) {
106
- const modifiers = { ctrl: false, alt: false };
107
-
108
- for (const step of job.steps || []) {
109
- this.assertSessionRunning(session);
110
- if (step.type === 'sleep') {
111
- await this.sleepWhileRunning(session, Math.max(0, Number(step.seconds) || 0) * 1000);
112
- continue;
113
- }
114
-
115
- if (step.type === 'sendText') {
116
- if (!session.write(String(step.text || ''))) throw new SessionEndedError();
117
- continue;
118
- }
119
-
120
- if (step.type === 'sendKey') {
121
- if (!session.write(sequenceForKey(step.key, modifiers))) throw new SessionEndedError();
122
- continue;
123
- }
124
-
125
- if (step.type === 'keyDown') {
126
- const key = String(step.key || '').toLowerCase();
127
- if (key === 'ctrl' || key === 'alt') modifiers[key] = true;
128
- continue;
129
- }
130
-
131
- if (step.type === 'keyUp') {
132
- const key = String(step.key || '').toLowerCase();
133
- if (key === 'ctrl' || key === 'alt') modifiers[key] = false;
134
- continue;
135
- }
136
-
137
- if (step.type === 'stop') break;
138
-
139
- if (step.type === 'closeSession') {
140
- session.kill?.();
141
- break;
142
- }
143
- }
144
- }
145
-
146
- assertSessionRunning(session) {
147
- if (session && typeof session.isRunning === 'function' && !session.isRunning()) {
148
- throw new SessionEndedError();
149
- }
150
- }
151
-
152
- async sleepWhileRunning(session, ms) {
153
- const end = Date.now() + ms;
154
- while (Date.now() < end) {
155
- this.assertSessionRunning(session);
156
- await sleep(Math.min(500, end - Date.now()));
157
- }
158
- this.assertSessionRunning(session);
159
- }
160
- }
161
-
162
- module.exports = JobRunner;
@@ -1,167 +0,0 @@
1
- const Conf = require('conf');
2
- const path = require('path');
3
- const os = require('os');
4
- const { v4: uuidv4 } = require('uuid');
5
-
6
- const config = new Conf({
7
- projectName: 'glad',
8
- cwd: path.join(os.homedir(), '.glad'),
9
- configName: 'schedules'
10
- });
11
-
12
- function normalizeWeekdays(weekdays) {
13
- const values = Array.isArray(weekdays) ? weekdays : [];
14
- return Array.from(new Set(values.map(Number).filter(value => value >= 0 && value <= 6))).sort((a, b) => a - b);
15
- }
16
-
17
- function normalizeSteps(steps) {
18
- const values = Array.isArray(steps) ? steps : [];
19
- return values.map(step => {
20
- const type = String(step.type || '').trim();
21
- if (type === 'sleep') return { type, seconds: Math.max(0, Number(step.seconds) || 0) };
22
- if (type === 'sendText') return { type, text: String(step.text || '') };
23
- if (type === 'sendKey') return { type, key: String(step.key || 'enter') };
24
- if (type === 'keyDown' || type === 'keyUp') return { type, key: String(step.key || '') };
25
- if (type === 'stop' || type === 'closeSession') return { type };
26
- return null;
27
- }).filter(Boolean);
28
- }
29
-
30
- function computeNextRunAt(schedule, from = Date.now()) {
31
- const weekdays = normalizeWeekdays(schedule && schedule.weekdays);
32
- const time = String(schedule && schedule.time || '').trim();
33
- const match = /^([01]\d|2[0-3]):([0-5]\d)$/.exec(time);
34
- if (!match || weekdays.length === 0) return null;
35
-
36
- const hour = Number(match[1]);
37
- const minute = Number(match[2]);
38
- const start = new Date(from);
39
-
40
- for (let offset = 0; offset <= 7; offset++) {
41
- const candidate = new Date(start);
42
- candidate.setDate(start.getDate() + offset);
43
- candidate.setHours(hour, minute, 0, 0);
44
- if (candidate.getTime() <= from) continue;
45
- if (weekdays.includes(candidate.getDay())) return candidate.getTime();
46
- }
47
-
48
- return null;
49
- }
50
-
51
- function normalizeJob(input, existing = null, options = {}) {
52
- const now = Date.now();
53
- const schedule = input.schedule || {};
54
- const target = input.target || {};
55
- const hasStoredNextRunAt = existing && typeof existing.nextRunAt === 'number';
56
- const job = {
57
- id: existing?.id || input.id || uuidv4(),
58
- name: String(input.name || existing?.name || 'Scheduled Task').trim() || 'Scheduled Task',
59
- enabled: Boolean(input.enabled ?? existing?.enabled ?? true),
60
- schedule: {
61
- time: String(schedule.time || existing?.schedule?.time || '09:00'),
62
- weekdays: normalizeWeekdays(schedule.weekdays ?? existing?.schedule?.weekdays ?? [1, 2, 3, 4, 5])
63
- },
64
- target: {
65
- toolKey: String(target.toolKey || existing?.target?.toolKey || 'demo'),
66
- workingDirectory: String(target.workingDirectory ?? existing?.target?.workingDirectory ?? '')
67
- },
68
- steps: normalizeSteps(input.steps ?? existing?.steps ?? []),
69
- createdAt: existing?.createdAt || input.createdAt || now,
70
- updatedAt: options.touch ? now : (existing?.updatedAt || input.updatedAt || now),
71
- lastRunAt: existing?.lastRunAt || input.lastRunAt || null,
72
- lastRunStatus: existing?.lastRunStatus || input.lastRunStatus || 'idle',
73
- lastRunMessage: existing?.lastRunMessage || input.lastRunMessage || '',
74
- lastSessionId: existing?.lastSessionId || input.lastSessionId || null,
75
- running: Boolean(existing?.running || false)
76
- };
77
-
78
- if (options.recomputeNextRunAt || !hasStoredNextRunAt) {
79
- job.nextRunAt = job.enabled ? computeNextRunAt(job.schedule, now) : null;
80
- } else {
81
- job.nextRunAt = existing.nextRunAt;
82
- }
83
-
84
- return job;
85
- }
86
-
87
- class JobStore {
88
- list() {
89
- return config.get('jobs', []).map(job => normalizeJob(job, job));
90
- }
91
-
92
- saveAll(jobs) {
93
- config.set('jobs', jobs);
94
- }
95
-
96
- get(id) {
97
- return this.list().find(job => job.id === id) || null;
98
- }
99
-
100
- create(input) {
101
- const jobs = this.list();
102
- const job = normalizeJob(input, null, { touch: true });
103
- jobs.push(job);
104
- this.saveAll(jobs);
105
- return job;
106
- }
107
-
108
- update(id, input) {
109
- const jobs = this.list();
110
- const index = jobs.findIndex(job => job.id === id);
111
- if (index === -1) return null;
112
- const existing = jobs[index];
113
- const nextSchedule = {
114
- time: String(input.schedule?.time || existing.schedule?.time || '09:00'),
115
- weekdays: normalizeWeekdays(input.schedule?.weekdays ?? existing.schedule?.weekdays ?? [1, 2, 3, 4, 5])
116
- };
117
- const scheduleChanged = JSON.stringify(nextSchedule) !== JSON.stringify(existing.schedule);
118
- const enabledChanged = Boolean(input.enabled ?? existing.enabled ?? true) !== Boolean(existing.enabled);
119
- jobs[index] = normalizeJob(input, existing, {
120
- touch: true,
121
- recomputeNextRunAt: scheduleChanged || enabledChanged
122
- });
123
- this.saveAll(jobs);
124
- return jobs[index];
125
- }
126
-
127
- patchRuntime(id, patch) {
128
- const jobs = this.list();
129
- const index = jobs.findIndex(job => job.id === id);
130
- if (index === -1) return null;
131
- jobs[index] = { ...jobs[index], ...patch, updatedAt: Date.now() };
132
- if ('enabled' in patch || 'lastRunAt' in patch || 'schedule' in patch) {
133
- jobs[index].nextRunAt = jobs[index].enabled ? computeNextRunAt(jobs[index].schedule) : null;
134
- }
135
- this.saveAll(jobs);
136
- return jobs[index];
137
- }
138
-
139
- delete(id) {
140
- const jobs = this.list();
141
- const next = jobs.filter(job => job.id !== id);
142
- this.saveAll(next);
143
- return next.length !== jobs.length;
144
- }
145
-
146
- duplicate(id) {
147
- const source = this.get(id);
148
- if (!source) return null;
149
- return this.create({
150
- ...source,
151
- id: uuidv4(),
152
- name: `${source.name} Copy`,
153
- enabled: false,
154
- lastRunAt: null,
155
- lastRunStatus: 'idle',
156
- lastRunMessage: '',
157
- lastSessionId: null,
158
- running: false
159
- });
160
- }
161
- }
162
-
163
- module.exports = {
164
- JobStore,
165
- computeNextRunAt,
166
- normalizeJob
167
- };
@@ -1,49 +0,0 @@
1
- const KEY_SEQUENCES = {
2
- enter: '\r',
3
- return: '\r',
4
- tab: '\t',
5
- esc: '\x1b',
6
- escape: '\x1b',
7
- up: '\x1b[A',
8
- down: '\x1b[B',
9
- right: '\x1b[C',
10
- left: '\x1b[D',
11
- backspace: '\x7f',
12
- delete: '\x1b[3~',
13
- home: '\x1b[H',
14
- end: '\x1b[F'
15
- };
16
-
17
- function ctrlSequence(key) {
18
- const normalized = String(key || '').trim().toLowerCase();
19
- if (normalized.length !== 1) return null;
20
- const code = normalized.charCodeAt(0);
21
- if (code >= 97 && code <= 122) return String.fromCharCode(code - 96);
22
- if (normalized === '[') return '\x1b';
23
- if (normalized === ']') return '\x1d';
24
- if (normalized === '\\') return '\x1c';
25
- if (normalized === '^') return '\x1e';
26
- if (normalized === '_') return '\x1f';
27
- return null;
28
- }
29
-
30
- function sequenceForKey(key, modifiers = {}) {
31
- const normalized = String(key || '').trim().toLowerCase();
32
- if (!normalized) return '';
33
-
34
- if (normalized.startsWith('ctrl+')) {
35
- return ctrlSequence(normalized.slice(5)) || '';
36
- }
37
-
38
- if (modifiers.ctrl) {
39
- const sequence = ctrlSequence(normalized);
40
- if (sequence) return sequence;
41
- }
42
-
43
- const sequence = KEY_SEQUENCES[normalized] || normalized;
44
- return modifiers.alt ? '\x1b' + sequence : sequence;
45
- }
46
-
47
- module.exports = {
48
- sequenceForKey
49
- };
@@ -1,39 +0,0 @@
1
- class SchedulerService {
2
- constructor({ jobStore, jobRunner, logger, intervalMs = 30000 }) {
3
- this.jobStore = jobStore;
4
- this.jobRunner = jobRunner;
5
- this.logger = logger || console;
6
- this.intervalMs = intervalMs;
7
- this.timer = null;
8
- }
9
-
10
- start() {
11
- if (this.timer) return;
12
- this.timer = setInterval(() => {
13
- this.tick();
14
- }, this.intervalMs);
15
- }
16
-
17
- stop() {
18
- if (!this.timer) return;
19
- clearInterval(this.timer);
20
- this.timer = null;
21
- }
22
-
23
- tick(now = Date.now()) {
24
- for (const job of this.jobStore.list()) {
25
- if (!job.enabled || !job.nextRunAt || job.nextRunAt > now) continue;
26
- this.jobStore.patchRuntime(job.id, {
27
- nextRunAt: null,
28
- lastRunAt: now,
29
- lastRunStatus: 'queued',
30
- lastRunMessage: ''
31
- });
32
- this.jobRunner.run(job.id, { manual: false }).catch(error => {
33
- this.logger.error(`Scheduled task ${job.id} failed: ${error.message}`);
34
- });
35
- }
36
- }
37
- }
38
-
39
- module.exports = SchedulerService;
@@ -1,52 +0,0 @@
1
- function statusCode(error) {
2
- return Number(error?.statusCode) || 500;
3
- }
4
-
5
- function registerNotificationRoutes(app, {
6
- settingsStore,
7
- notificationService
8
- }) {
9
- app.get('/api/notifications/serverchan', (_req, res) => {
10
- res.json(settingsStore.getPublic());
11
- });
12
-
13
- app.put('/api/notifications/serverchan', (req, res) => {
14
- try {
15
- res.json({ success: true, settings: settingsStore.save(req.body || {}) });
16
- } catch (error) {
17
- res.status(statusCode(error)).json({ error: error.message });
18
- }
19
- });
20
-
21
- app.delete('/api/notifications/serverchan', (_req, res) => {
22
- const settings = settingsStore.clear();
23
- notificationService.disableAllSessions();
24
- res.json({ success: true, settings });
25
- });
26
-
27
- app.post('/api/notifications/serverchan/test', async (req, res) => {
28
- try {
29
- await notificationService.sendTest(req.body || {});
30
- res.json({ success: true });
31
- } catch (error) {
32
- res.status(statusCode(error)).json({ error: error.message });
33
- }
34
- });
35
-
36
- app.put('/api/sessions/:id/notifications/serverchan', async (req, res) => {
37
- try {
38
- const state = await notificationService.setSessionEnabled(
39
- req.params.id,
40
- Boolean(req.body?.enabled)
41
- );
42
- res.json({ success: true, state });
43
- } catch (error) {
44
- res.status(statusCode(error)).json({
45
- error: error.message,
46
- ...(error.code ? { code: error.code } : {})
47
- });
48
- }
49
- });
50
- }
51
-
52
- module.exports = registerNotificationRoutes;
@@ -1,114 +0,0 @@
1
- function registerProviderRoutes(app, { sessionManager }) {
2
- app.get('/api/sessions/:id/claude-resume-sessions', (req, res) => {
3
- const items = sessionManager.listClaudeResumeSessions(req.params.id);
4
- if (!items) return res.status(404).json({ error: 'Claude session not found' });
5
- res.json({ success: true, items });
6
- });
7
-
8
- app.patch('/api/sessions/:id/claude-settings', (req, res) => {
9
- const state = sessionManager.updateClaudeSettings(req.params.id, req.body || {});
10
- if (!state) return res.status(404).json({ error: 'Claude session not found' });
11
- res.json({ success: true, state });
12
- });
13
-
14
- app.post('/api/sessions/:id/claude-abort', (req, res) => {
15
- const success = sessionManager.abortClaude(req.params.id);
16
- if (!success) return res.status(404).json({ error: 'Claude session not found or idle' });
17
- res.json({ success: true });
18
- });
19
-
20
- app.post('/api/sessions/:id/claude-resume', (req, res) => {
21
- const resumeSessionId = req.body?.resumeSessionId;
22
- if (!resumeSessionId) return res.status(400).json({ error: 'Missing resumeSessionId' });
23
- const success = sessionManager.resumeClaude(req.params.id, resumeSessionId);
24
- if (!success) return res.status(404).json({ error: 'Claude session not found' });
25
- res.json({ success: true });
26
- });
27
-
28
- app.post('/api/sessions/:id/claude-fork', async (req, res) => {
29
- try {
30
- const result = await sessionManager.forkClaude(req.params.id, req.body?.claudeSessionId);
31
- if (!result) return res.status(404).json({ error: 'Claude session not found' });
32
- res.json({ success: true, ...result });
33
- } catch (error) {
34
- res.status(error.statusCode || 400).json({ error: error.message });
35
- }
36
- });
37
-
38
- app.patch('/api/sessions/:id/codex-settings', async (req, res) => {
39
- try {
40
- const state = await sessionManager.updateCodexSettings(req.params.id, req.body || {});
41
- if (!state) return res.status(404).json({ error: 'Codex session not found' });
42
- res.json({ success: true, state });
43
- } catch (error) {
44
- res.status(400).json({ error: error.message });
45
- }
46
- });
47
-
48
- app.get('/api/sessions/:id/codex-resume-threads', async (req, res) => {
49
- try {
50
- const items = await sessionManager.listCodexResumeThreads(req.params.id);
51
- if (!items) return res.status(404).json({ error: 'Codex session not found' });
52
- res.json({ success: true, items });
53
- } catch (error) {
54
- res.status(400).json({ error: error.message });
55
- }
56
- });
57
-
58
- app.get('/api/sessions/:id/codex-prompts', async (req, res) => {
59
- try {
60
- const result = await sessionManager.listCodexPrompts(req.params.id, {
61
- offset: req.query?.offset,
62
- limit: req.query?.limit
63
- });
64
- if (!result) return res.status(404).json({ error: 'Codex session not found' });
65
- res.json({ success: true, ...result });
66
- } catch (error) {
67
- res.status(400).json({ error: error.message });
68
- }
69
- });
70
-
71
- app.get('/api/sessions/:id/codex-skills', async (req, res) => {
72
- try {
73
- const result = await sessionManager.listCodexSkills(req.params.id, req.query?.forceReload === 'true');
74
- if (!result) return res.status(404).json({ error: 'Codex session not found' });
75
- res.json({ success: true, ...result });
76
- } catch (error) {
77
- res.status(400).json({ error: error.message });
78
- }
79
- });
80
-
81
- app.post('/api/sessions/:id/codex-abort', (req, res) => {
82
- const success = sessionManager.abortCodex(req.params.id);
83
- if (!success) return res.status(409).json({ error: 'Codex session is idle or unavailable' });
84
- res.json({ success: true });
85
- });
86
-
87
- app.post('/api/sessions/:id/codex-resume', async (req, res) => {
88
- try {
89
- const success = await sessionManager.resumeCodex(req.params.id, req.body?.threadId);
90
- if (!success) return res.status(409).json({ error: 'Codex session is busy or no thread is available' });
91
- res.json({ success: true });
92
- } catch (error) {
93
- res.status(400).json({ error: error.message });
94
- }
95
- });
96
-
97
- app.post('/api/sessions/:id/codex-fork', async (req, res) => {
98
- try {
99
- const session = await sessionManager.forkCodex(req.params.id, req.body?.threadId);
100
- if (!session) return res.status(404).json({ error: 'Codex session not found' });
101
- res.json({ success: true, id: session.id, name: session.name, threadId: session.threadId });
102
- } catch (error) {
103
- res.status(error.statusCode || 400).json({ error: error.message });
104
- }
105
- });
106
-
107
- app.post('/api/debug/client-log', (req, res) => {
108
- const { sessionId, event, payload } = req.body || {};
109
- sessionManager.logClientDebug(sessionId, event, payload);
110
- res.json({ success: true });
111
- });
112
- }
113
-
114
- module.exports = registerProviderRoutes;
@@ -1,54 +0,0 @@
1
- function registerScheduleRoutes(app, { jobStore, jobRunner }) {
2
- app.get('/api/schedules', (req, res) => {
3
- res.json(jobStore.list());
4
- });
5
-
6
- app.post('/api/schedules', (req, res) => {
7
- try {
8
- res.json(jobStore.create(req.body || {}));
9
- } catch (error) {
10
- res.status(400).json({ error: error.message });
11
- }
12
- });
13
-
14
- app.get('/api/schedules/:id', (req, res) => {
15
- const job = jobStore.get(req.params.id);
16
- if (!job) return res.status(404).json({ error: 'Scheduled task not found' });
17
- res.json(job);
18
- });
19
-
20
- app.patch('/api/schedules/:id', (req, res) => {
21
- const job = jobStore.update(req.params.id, req.body || {});
22
- if (!job) return res.status(404).json({ error: 'Scheduled task not found' });
23
- res.json(job);
24
- });
25
-
26
- app.patch('/api/schedules/:id/enabled', (req, res) => {
27
- const job = jobStore.patchRuntime(req.params.id, { enabled: Boolean(req.body?.enabled) });
28
- if (!job) return res.status(404).json({ error: 'Scheduled task not found' });
29
- res.json(job);
30
- });
31
-
32
- app.delete('/api/schedules/:id', (req, res) => {
33
- res.json({ success: jobStore.delete(req.params.id) });
34
- });
35
-
36
- app.post('/api/schedules/:id/duplicate', (req, res) => {
37
- const job = jobStore.duplicate(req.params.id);
38
- if (!job) return res.status(404).json({ error: 'Scheduled task not found' });
39
- res.json(job);
40
- });
41
-
42
- const runJob = options => async (req, res) => {
43
- try {
44
- res.json(await jobRunner.run(req.params.id, options));
45
- } catch (error) {
46
- res.status(400).json({ error: error.message });
47
- }
48
- };
49
-
50
- app.post('/api/schedules/:id/run', runJob({ manual: false }));
51
- app.post('/api/schedules/:id/simulate', runJob({ manual: true, background: true }));
52
- }
53
-
54
- module.exports = registerScheduleRoutes;