@tom2012/cc-web 2026.5.24-i → 2026.6.8-a
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 +1 -1
- package/backend/dist/__tests__/browser-chrome.test.js +3 -0
- package/backend/dist/__tests__/browser-chrome.test.js.map +1 -1
- package/backend/dist/browser-chrome/session-manager.d.ts +6 -1
- package/backend/dist/browser-chrome/session-manager.d.ts.map +1 -1
- package/backend/dist/browser-chrome/session-manager.js +1 -0
- package/backend/dist/browser-chrome/session-manager.js.map +1 -1
- package/backend/dist/index.d.ts.map +1 -1
- package/backend/dist/index.js +14 -0
- package/backend/dist/index.js.map +1 -1
- package/backend/dist/mcp/daemon-client.d.ts +16 -0
- package/backend/dist/mcp/daemon-client.d.ts.map +1 -0
- package/backend/dist/mcp/daemon-client.js +136 -0
- package/backend/dist/mcp/daemon-client.js.map +1 -0
- package/backend/dist/mcp/server.d.ts +2 -0
- package/backend/dist/mcp/server.d.ts.map +1 -0
- package/backend/dist/mcp/server.js +33 -0
- package/backend/dist/mcp/server.js.map +1 -0
- package/backend/dist/mcp/tools.d.ts +12 -0
- package/backend/dist/mcp/tools.d.ts.map +1 -0
- package/backend/dist/mcp/tools.js +215 -0
- package/backend/dist/mcp/tools.js.map +1 -0
- package/backend/dist/routes/browser-chrome.d.ts.map +1 -1
- package/backend/dist/routes/browser-chrome.js +119 -0
- package/backend/dist/routes/browser-chrome.js.map +1 -1
- package/backend/dist/routes/projects.d.ts.map +1 -1
- package/backend/dist/routes/projects.js +79 -0
- package/backend/dist/routes/projects.js.map +1 -1
- package/backend/package-lock.json +594 -8
- package/backend/package.json +1 -0
- package/bin/ccweb.js +16 -0
- package/frontend/dist/assets/{ChatOverlay-Os7GgFbk.js → ChatOverlay-BCmamNeY.js} +1 -1
- package/frontend/dist/assets/{GraphPreview-DkuOMyQQ.js → GraphPreview-DDfW4Ga1.js} +1 -1
- package/frontend/dist/assets/{MobilePage-BQVHck3e.js → MobilePage-DlrSEbwf.js} +3 -3
- package/frontend/dist/assets/{OfficePreview-DR6er_Lj.js → OfficePreview-BAyVAKCq.js} +2 -2
- package/frontend/dist/assets/{PdfPreview-D9fdCH2K.js → PdfPreview-JZP_GIo5.js} +1 -1
- package/frontend/dist/assets/{ProjectPage-BJxgLZ4L.js → ProjectPage-D6XI_syc.js} +4 -4
- package/frontend/dist/assets/{SettingsPage-C3J_dzmo.js → SettingsPage-Cesy5VBi.js} +1 -1
- package/frontend/dist/assets/{SkillHubPage-f9toVVpj.js → SkillHubPage-D-LrJx4v.js} +1 -1
- package/frontend/dist/assets/{chevron-down-jZ8WxG0q.js → chevron-down-BNy_ld5o.js} +1 -1
- package/frontend/dist/assets/{index-BpcF4a4l.js → index-BUBRc674.js} +2 -2
- package/frontend/dist/assets/{index-C7y8R0HA.js → index-Cs28h9_C.js} +1 -1
- package/frontend/dist/assets/{index-BkMm42LT.js → index-DxDu5WkP.js} +1 -1
- package/frontend/dist/assets/{jszip.min-CjSK3Cp5.js → jszip.min--CjHKRwc.js} +1 -1
- package/frontend/dist/assets/{search-DjmaTK6c.js → search-BUgyHPYV.js} +1 -1
- package/frontend/dist/assets/{select-B-gs9Xqu.js → select-opuUXbEP.js} +1 -1
- package/frontend/dist/index.html +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerTools = registerTools;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const daemon_client_js_1 = require("./daemon-client.js");
|
|
6
|
+
const PROJECT_ID = zod_1.z
|
|
7
|
+
.string()
|
|
8
|
+
.regex(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i, 'projectId must be a UUID');
|
|
9
|
+
function ok(payload) {
|
|
10
|
+
return { content: [{ type: 'text', text: JSON.stringify(payload, null, 2) }] };
|
|
11
|
+
}
|
|
12
|
+
function err(message) {
|
|
13
|
+
return { content: [{ type: 'text', text: message }], isError: true };
|
|
14
|
+
}
|
|
15
|
+
async function safe(fn) {
|
|
16
|
+
try {
|
|
17
|
+
return await fn();
|
|
18
|
+
}
|
|
19
|
+
catch (e) {
|
|
20
|
+
return err(e instanceof Error ? e.message : String(e));
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function registerTools(server) {
|
|
24
|
+
const client = (0, daemon_client_js_1.getDaemonClient)();
|
|
25
|
+
// ─── projects ─────────────────────────────────────────────────────────────
|
|
26
|
+
server.registerTool('list_projects', {
|
|
27
|
+
title: 'List projects',
|
|
28
|
+
description: 'List all projects visible to the caller. Filter by `archived: true|false`. Omitting `archived` returns every project (active + archived).',
|
|
29
|
+
inputSchema: { archived: zod_1.z.boolean().optional() },
|
|
30
|
+
}, async ({ archived }) => safe(async () => {
|
|
31
|
+
const projects = await client.request('GET', '/api/projects');
|
|
32
|
+
const filtered = archived === undefined
|
|
33
|
+
? projects
|
|
34
|
+
: projects.filter((p) => !!p.archived === archived);
|
|
35
|
+
return ok(filtered.map((p) => ({
|
|
36
|
+
id: p.id,
|
|
37
|
+
name: p.name,
|
|
38
|
+
folderPath: p.folderPath,
|
|
39
|
+
cliTool: p.cliTool,
|
|
40
|
+
archived: !!p.archived,
|
|
41
|
+
status: p.status,
|
|
42
|
+
tags: p.tags ?? [],
|
|
43
|
+
})));
|
|
44
|
+
}));
|
|
45
|
+
server.registerTool('archive_project', {
|
|
46
|
+
title: 'Archive a project',
|
|
47
|
+
description: 'Move a project to the archived list. Stops its terminal first.',
|
|
48
|
+
inputSchema: { projectId: PROJECT_ID },
|
|
49
|
+
}, async ({ projectId }) => safe(async () => {
|
|
50
|
+
const result = await client.request('PATCH', `/api/projects/${projectId}/archive`);
|
|
51
|
+
return ok({ id: result.id, name: result.name, archived: !!result.archived });
|
|
52
|
+
}));
|
|
53
|
+
server.registerTool('unarchive_project', {
|
|
54
|
+
title: 'Unarchive a project',
|
|
55
|
+
description: 'Move a project back from the archived list. Does not auto-start its terminal.',
|
|
56
|
+
inputSchema: { projectId: PROJECT_ID },
|
|
57
|
+
}, async ({ projectId }) => safe(async () => {
|
|
58
|
+
const result = await client.request('PATCH', `/api/projects/${projectId}/unarchive`);
|
|
59
|
+
return ok({ id: result.id, name: result.name, archived: !!result.archived });
|
|
60
|
+
}));
|
|
61
|
+
// ─── filesystem ───────────────────────────────────────────────────────────
|
|
62
|
+
server.registerTool('list_files', {
|
|
63
|
+
title: 'List a project directory',
|
|
64
|
+
description: 'List files and directories inside the project folder. `subPath` is relative to the project root; omit to list root.',
|
|
65
|
+
inputSchema: { projectId: PROJECT_ID, subPath: zod_1.z.string().optional() },
|
|
66
|
+
}, async ({ projectId, subPath }) => safe(async () => {
|
|
67
|
+
const projects = await client.request('GET', '/api/projects');
|
|
68
|
+
const project = projects.find((p) => p.id === projectId);
|
|
69
|
+
if (!project)
|
|
70
|
+
return err(`Project ${projectId} not found`);
|
|
71
|
+
const target = subPath
|
|
72
|
+
? `${project.folderPath}/${subPath}`.replace(/\/+/g, '/')
|
|
73
|
+
: project.folderPath;
|
|
74
|
+
const result = await client.request('GET', `/api/filesystem?path=${encodeURIComponent(target)}`);
|
|
75
|
+
return ok({
|
|
76
|
+
path: result.path,
|
|
77
|
+
entries: result.entries.map((e) => ({
|
|
78
|
+
name: e.name,
|
|
79
|
+
type: e.type,
|
|
80
|
+
relativePath: e.path.startsWith(project.folderPath + '/')
|
|
81
|
+
? e.path.slice(project.folderPath.length + 1)
|
|
82
|
+
: e.path,
|
|
83
|
+
})),
|
|
84
|
+
});
|
|
85
|
+
}));
|
|
86
|
+
server.registerTool('read_file', {
|
|
87
|
+
title: 'Read a file from a project',
|
|
88
|
+
description: 'Read a UTF-8 text file from the project. `path` may be absolute or relative to the project root. Files > 5 MB or binary return metadata only (no content).',
|
|
89
|
+
inputSchema: { projectId: PROJECT_ID, path: zod_1.z.string() },
|
|
90
|
+
}, async ({ projectId, path: filePath }) => safe(async () => {
|
|
91
|
+
const projects = await client.request('GET', '/api/projects');
|
|
92
|
+
const project = projects.find((p) => p.id === projectId);
|
|
93
|
+
if (!project)
|
|
94
|
+
return err(`Project ${projectId} not found`);
|
|
95
|
+
const target = filePath.startsWith('/')
|
|
96
|
+
? filePath
|
|
97
|
+
: `${project.folderPath}/${filePath}`;
|
|
98
|
+
const result = await client.request('GET', `/api/filesystem/file?path=${encodeURIComponent(target)}`);
|
|
99
|
+
if (result.tooLarge) {
|
|
100
|
+
return ok({
|
|
101
|
+
path: result.path,
|
|
102
|
+
size: result.size,
|
|
103
|
+
tooLarge: true,
|
|
104
|
+
note: 'File exceeds the 5 MB inline read limit. Read it from disk directly or have the user split it before retrying.',
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
if (result.binary) {
|
|
108
|
+
return ok({
|
|
109
|
+
path: result.path,
|
|
110
|
+
size: result.size,
|
|
111
|
+
binary: true,
|
|
112
|
+
note: 'File contains binary data (null bytes in first 8KB). Cannot return as text.',
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
return ok({ path: result.path, size: result.size, content: result.content });
|
|
116
|
+
}));
|
|
117
|
+
// ─── memory ───────────────────────────────────────────────────────────────
|
|
118
|
+
server.registerTool('read_memory', {
|
|
119
|
+
title: 'Read project memory prompts',
|
|
120
|
+
description: 'List all memory prompts (CLAUDE.md / AGENTS.md fragments) for a project, including which are currently inserted into the instructions file.',
|
|
121
|
+
inputSchema: { projectId: PROJECT_ID },
|
|
122
|
+
}, async ({ projectId }) => safe(async () => {
|
|
123
|
+
const result = await client.request('GET', `/api/memory/project/${projectId}`);
|
|
124
|
+
return ok({
|
|
125
|
+
instructionsFilename: result.instructionsFilename,
|
|
126
|
+
instructionsFileLineCount: result.claudeMdLineCount,
|
|
127
|
+
prompts: result.items.map((p) => ({
|
|
128
|
+
filename: p.filename,
|
|
129
|
+
inserted: p.inserted,
|
|
130
|
+
body: p.body,
|
|
131
|
+
})),
|
|
132
|
+
});
|
|
133
|
+
}));
|
|
134
|
+
// ─── LLM I/O ──────────────────────────────────────────────────────────────
|
|
135
|
+
server.registerTool('send_to_llm', {
|
|
136
|
+
title: 'Send a prompt to a project\'s LLM',
|
|
137
|
+
description: 'Send text into the project\'s CLI session (paste-mode by default, which submits via Enter). Returns `{ ok, sentAt }` immediately — does NOT wait for the LLM to respond. Pass the returned `sentAt` to `wait_for_llm` so it can recognize the new assistant turn even if it completes very quickly. Use mode="raw" for slash commands like "/help" that need to be typed line-start.',
|
|
138
|
+
inputSchema: {
|
|
139
|
+
projectId: PROJECT_ID,
|
|
140
|
+
text: zod_1.z.string(),
|
|
141
|
+
mode: zod_1.z.enum(['paste', 'raw']).optional(),
|
|
142
|
+
},
|
|
143
|
+
}, async ({ projectId, text, mode }) => safe(async () => {
|
|
144
|
+
const result = await client.request('POST', `/api/projects/${projectId}/send-input`, { text, mode });
|
|
145
|
+
return ok({ ok: result.ok, sentAt: result.sentAt });
|
|
146
|
+
}));
|
|
147
|
+
server.registerTool('wait_for_llm', {
|
|
148
|
+
title: 'Wait for the LLM to finish a turn',
|
|
149
|
+
description: 'Wait for the project\'s LLM turn to complete, then return the chat blocks the LLM produced. Pass the `sentAt` returned by `send_to_llm` (recommended) — wait_for_llm will return as soon as a NEW assistant ChatBlock with timestamp > sentAt has arrived AND the PTY has been quiet for ~30s. Without sentAt the tool falls back to active→idle edge detection, which can miss turns shorter than the 1s poll interval. `timeoutMs` defaults to 600000 (10 min).',
|
|
150
|
+
inputSchema: {
|
|
151
|
+
projectId: PROJECT_ID,
|
|
152
|
+
sentAt: zod_1.z.string().datetime().optional(),
|
|
153
|
+
timeoutMs: zod_1.z.number().int().positive().max(3600000).optional(),
|
|
154
|
+
limit: zod_1.z.number().int().positive().max(200).optional(),
|
|
155
|
+
},
|
|
156
|
+
}, async ({ projectId, sentAt, timeoutMs, limit }) => safe(async () => {
|
|
157
|
+
const deadline = Date.now() + (timeoutMs ?? 600000);
|
|
158
|
+
const POLL_MS = 1000;
|
|
159
|
+
const sentAtMs = sentAt ? Date.parse(sentAt) : null;
|
|
160
|
+
const historyLimit = limit ?? 10;
|
|
161
|
+
let observedActive = false;
|
|
162
|
+
let sawIdle = false;
|
|
163
|
+
let sawNewAssistant = false;
|
|
164
|
+
// Returns true once we believe the turn the caller anchored is done.
|
|
165
|
+
// Two-conditions when sentAt is provided:
|
|
166
|
+
// 1. there is at least one assistant ChatBlock with timestamp > sentAt
|
|
167
|
+
// 2. semantic-status is currently idle (active=false) — guards against
|
|
168
|
+
// returning between two assistant blocks in the same turn (Claude
|
|
169
|
+
// can emit multiple blocks if it uses tools mid-turn)
|
|
170
|
+
// Falls back to active-edge detection when sentAt is absent.
|
|
171
|
+
const checkDone = async () => {
|
|
172
|
+
const status = await client.request('GET', `/api/projects/${projectId}/semantic-status`);
|
|
173
|
+
if (status.active) {
|
|
174
|
+
observedActive = true;
|
|
175
|
+
sawIdle = false;
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
178
|
+
// active=false from here on
|
|
179
|
+
if (sentAtMs !== null) {
|
|
180
|
+
// Cheap check first: only fetch history if we haven't yet observed
|
|
181
|
+
// a new assistant block.
|
|
182
|
+
if (!sawNewAssistant) {
|
|
183
|
+
const recent = await client.request('GET', `/api/projects/${projectId}/chat-history?limit=${historyLimit}`);
|
|
184
|
+
sawNewAssistant = recent.blocks.some((b) => b.role === 'assistant' && b.timestamp && Date.parse(b.timestamp) > sentAtMs);
|
|
185
|
+
}
|
|
186
|
+
if (sawNewAssistant) {
|
|
187
|
+
sawIdle = true;
|
|
188
|
+
return true;
|
|
189
|
+
}
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
// Legacy path: rely on active→idle edge.
|
|
193
|
+
if (observedActive) {
|
|
194
|
+
sawIdle = true;
|
|
195
|
+
return true;
|
|
196
|
+
}
|
|
197
|
+
return false;
|
|
198
|
+
};
|
|
199
|
+
while (Date.now() < deadline) {
|
|
200
|
+
if (await checkDone())
|
|
201
|
+
break;
|
|
202
|
+
await new Promise((r) => setTimeout(r, POLL_MS));
|
|
203
|
+
}
|
|
204
|
+
const history = await client.request('GET', `/api/projects/${projectId}/chat-history?limit=${historyLimit}`);
|
|
205
|
+
const deadlineHit = Date.now() >= deadline;
|
|
206
|
+
return ok({
|
|
207
|
+
observedActive,
|
|
208
|
+
idle: sawIdle,
|
|
209
|
+
sawNewAssistant: sentAtMs !== null ? sawNewAssistant : undefined,
|
|
210
|
+
deadlineHit,
|
|
211
|
+
blocks: history.blocks,
|
|
212
|
+
});
|
|
213
|
+
}));
|
|
214
|
+
}
|
|
215
|
+
//# sourceMappingURL=tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/mcp/tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser-chrome.d.ts","sourceRoot":"","sources":["../../src/routes/browser-chrome.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAmC,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"browser-chrome.d.ts","sourceRoot":"","sources":["../../src/routes/browser-chrome.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAmC,MAAM,SAAS,CAAC;AA6BlE,QAAA,MAAM,MAAM,EAAE,MAAiB,CAAC;AAkMhC,eAAe,MAAM,CAAC"}
|
|
@@ -1,11 +1,60 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
2
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
39
|
const express_1 = require("express");
|
|
40
|
+
const multer_1 = __importDefault(require("multer"));
|
|
41
|
+
const fs = __importStar(require("fs"));
|
|
42
|
+
const os = __importStar(require("os"));
|
|
43
|
+
const path = __importStar(require("path"));
|
|
4
44
|
const auth_1 = require("../auth");
|
|
5
45
|
const config_1 = require("../config");
|
|
6
46
|
const session_manager_1 = require("../browser-chrome/session-manager");
|
|
7
47
|
const browser_proxy_1 = require("./browser-proxy");
|
|
8
48
|
const logger_1 = require("../logger");
|
|
49
|
+
const uploadHandler = (0, multer_1.default)({
|
|
50
|
+
dest: path.join(os.tmpdir(), 'ccweb-browser-chrome-uploads'),
|
|
51
|
+
limits: { fileSize: 50 * 1024 * 1024 }, // 50MB per file
|
|
52
|
+
});
|
|
53
|
+
// multer/busboy decodes filename as latin-1, but browsers send UTF-8 — same
|
|
54
|
+
// reasoning as routes/filesystem.ts upload. Re-encode to recover CJK names.
|
|
55
|
+
function decodeUploadName(name) {
|
|
56
|
+
return Buffer.from(name, 'latin1').toString('utf8');
|
|
57
|
+
}
|
|
9
58
|
const log = (0, logger_1.modLogger)('browser-chrome:route');
|
|
10
59
|
const router = (0, express_1.Router)();
|
|
11
60
|
function requireBearerAdmin(req, res, next) {
|
|
@@ -139,6 +188,76 @@ router.get('/:sid/download/:dlId', (req, res) => {
|
|
|
139
188
|
// click once. If user wants the file again they re-download.
|
|
140
189
|
session.downloads.delete(dlId);
|
|
141
190
|
});
|
|
191
|
+
/**
|
|
192
|
+
* POST /:sid/upload — multipart upload bridged into chromium's pending
|
|
193
|
+
* file chooser dialog. The page must have triggered a filechooser event
|
|
194
|
+
* within the last ~30s (playwright's default chooser timeout); otherwise
|
|
195
|
+
* we return 410.
|
|
196
|
+
*
|
|
197
|
+
* Authenticated via `?token=...` for the same reason as /download: the
|
|
198
|
+
* frontend uses fetch with multipart body, where attaching Authorization
|
|
199
|
+
* is fine, but keeping the auth model consistent with download avoids
|
|
200
|
+
* having to support both styles.
|
|
201
|
+
*/
|
|
202
|
+
router.post('/:sid/upload', uploadHandler.array('files', 20), async (req, res) => {
|
|
203
|
+
const sid = req.params['sid'];
|
|
204
|
+
const token = req.query['token'];
|
|
205
|
+
if (typeof token !== 'string' || !token) {
|
|
206
|
+
res.status(401).json({ error: 'token required' });
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
const claim = (0, session_manager_1.verifySessionToken)(token);
|
|
210
|
+
if (!claim || claim.sid !== sid) {
|
|
211
|
+
res.status(403).json({ error: 'Invalid token' });
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
const session = session_manager_1.browserChromeSessions.get(sid, claim.username);
|
|
215
|
+
if (!session) {
|
|
216
|
+
res.status(404).json({ error: 'Session not found' });
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
const pending = session.pendingChooser;
|
|
220
|
+
if (!pending) {
|
|
221
|
+
res.status(410).json({ error: 'No pending file chooser — chromium dialog may have timed out' });
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
const files = req.files;
|
|
225
|
+
if (!files || files.length === 0) {
|
|
226
|
+
res.status(400).json({ error: 'No files uploaded' });
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
// multer writes each file to a tmp path with a random name; chromium
|
|
230
|
+
// setFiles takes file system paths (or in-memory Buffer descriptors).
|
|
231
|
+
// We rename to preserve the user's original filename so the page sees
|
|
232
|
+
// the right name in <input>.files[].name.
|
|
233
|
+
const renamed = [];
|
|
234
|
+
try {
|
|
235
|
+
for (const f of files) {
|
|
236
|
+
const decoded = decodeUploadName(f.originalname || 'file');
|
|
237
|
+
const safe = decoded.replace(/[\/\\\0]/g, '_');
|
|
238
|
+
const dest = path.join(path.dirname(f.path), `${path.basename(f.path)}-${safe}`);
|
|
239
|
+
fs.renameSync(f.path, dest);
|
|
240
|
+
renamed.push(dest);
|
|
241
|
+
}
|
|
242
|
+
await pending.chooser.setFiles(renamed);
|
|
243
|
+
session.pendingChooser = null;
|
|
244
|
+
res.json({ ok: true, count: renamed.length });
|
|
245
|
+
}
|
|
246
|
+
catch (err) {
|
|
247
|
+
log.warn({ err, sid }, 'setFiles failed');
|
|
248
|
+
res.status(500).json({ error: 'Upload bridge failed', detail: err.message });
|
|
249
|
+
}
|
|
250
|
+
finally {
|
|
251
|
+
// Always clean up tmp files (chromium has already read them into the
|
|
252
|
+
// page context if setFiles succeeded; if not, they're not needed either).
|
|
253
|
+
for (const p of renamed) {
|
|
254
|
+
try {
|
|
255
|
+
fs.unlinkSync(p);
|
|
256
|
+
}
|
|
257
|
+
catch { /* already gone */ }
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
});
|
|
142
261
|
/**
|
|
143
262
|
* DELETE /:sid — explicit session teardown. Otherwise SessionManager idle
|
|
144
263
|
* sweep eventually destroys it after 5 minutes of inactivity.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser-chrome.js","sourceRoot":"","sources":["../../src/routes/browser-chrome.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"browser-chrome.js","sourceRoot":"","sources":["../../src/routes/browser-chrome.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../../src/routes/projects.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../../src/routes/projects.ts"],"names":[],"mappings":"AAyCA,QAAA,MAAM,MAAM,4CAAW,CAAC;AA0uBxB,eAAe,MAAM,CAAC"}
|
|
@@ -41,6 +41,7 @@ const config_1 = require("../config");
|
|
|
41
41
|
const cli_prompt_detector_1 = require("../cli-prompt-detector");
|
|
42
42
|
const user_prefs_1 = require("../user-prefs");
|
|
43
43
|
const terminal_manager_1 = require("../terminal-manager");
|
|
44
|
+
const terminal_paste_1 = require("../terminal-paste");
|
|
44
45
|
const session_manager_1 = require("../session-manager");
|
|
45
46
|
const adapters_1 = require("../adapters");
|
|
46
47
|
const chat_backup_1 = require("../chat-backup");
|
|
@@ -760,5 +761,83 @@ router.post('/:id/cli-prompt-respond', (req, res) => {
|
|
|
760
761
|
res.status(500).json({ error: err.message });
|
|
761
762
|
}
|
|
762
763
|
});
|
|
764
|
+
/**
|
|
765
|
+
* POST /api/projects/:id/send-input { text: string, mode?: 'paste' | 'raw' }
|
|
766
|
+
*
|
|
767
|
+
* MCP-friendly entry to inject text into the CLI's PTY. Default 'paste' mode
|
|
768
|
+
* wraps body in bracketed-paste sequence + trailing CR (writeTerminalInputSplit
|
|
769
|
+
* handles the Ink TUI paste-submit timing). 'raw' mode writes text + '\r' as-is
|
|
770
|
+
* — use for slash commands like '/help' which only trigger when typed line-start.
|
|
771
|
+
*
|
|
772
|
+
* Write permission gate matches cli-prompt-respond: owner / admin / edit-share.
|
|
773
|
+
*/
|
|
774
|
+
router.post('/:id/send-input', (req, res) => {
|
|
775
|
+
const project = (0, config_1.getProject)(req.params.id);
|
|
776
|
+
if (!project) {
|
|
777
|
+
res.status(404).json({ error: 'Not found' });
|
|
778
|
+
return;
|
|
779
|
+
}
|
|
780
|
+
const username = req.user?.username;
|
|
781
|
+
const isOwner = (0, config_1.isProjectOwner)(project, username);
|
|
782
|
+
const share = project.shares?.find((s) => s.username === username);
|
|
783
|
+
const canWrite = isOwner || (0, config_1.isAdminUser)(username) || share?.permission === 'edit';
|
|
784
|
+
if (!canWrite) {
|
|
785
|
+
res.status(403).json({ error: 'Forbidden' });
|
|
786
|
+
return;
|
|
787
|
+
}
|
|
788
|
+
const body = req.body;
|
|
789
|
+
if (typeof body.text !== 'string') {
|
|
790
|
+
res.status(400).json({ error: 'text must be a string' });
|
|
791
|
+
return;
|
|
792
|
+
}
|
|
793
|
+
const mode = body.mode === 'raw' ? 'raw' : 'paste';
|
|
794
|
+
if (!terminal_manager_1.terminalManager.hasTerminal(req.params.id)) {
|
|
795
|
+
res.status(503).json({ error: 'Terminal is not running for this project' });
|
|
796
|
+
return;
|
|
797
|
+
}
|
|
798
|
+
try {
|
|
799
|
+
if (mode === 'raw') {
|
|
800
|
+
// Strip trailing whitespace + \r\n, append a single \r for submission.
|
|
801
|
+
const trimmed = body.text.replace(/[\r\n\s]+$/, '');
|
|
802
|
+
terminal_manager_1.terminalManager.writeRaw(req.params.id, trimmed + '\r');
|
|
803
|
+
}
|
|
804
|
+
else {
|
|
805
|
+
(0, terminal_paste_1.writeTerminalInputSplit)(req.params.id, (0, terminal_paste_1.buildPaste)(body.text));
|
|
806
|
+
}
|
|
807
|
+
// sentAt anchors `wait_for_llm` — it can match the new assistant block
|
|
808
|
+
// by ChatBlock.timestamp > sentAt, which is robust against turns that
|
|
809
|
+
// finish faster than the 1s semantic-status poll interval.
|
|
810
|
+
res.json({ ok: true, sentAt: new Date().toISOString() });
|
|
811
|
+
}
|
|
812
|
+
catch (err) {
|
|
813
|
+
res.status(500).json({ error: err.message });
|
|
814
|
+
}
|
|
815
|
+
});
|
|
816
|
+
/**
|
|
817
|
+
* GET /api/projects/:id/semantic-status
|
|
818
|
+
*
|
|
819
|
+
* Returns the current semantic snapshot { active, semantic? }. MCP wait_for_llm
|
|
820
|
+
* polls this; `active: false` means the LLM has been quiet for at least
|
|
821
|
+
* SEMANTIC_STALE_MS (30s) — close-enough signal that the current turn finished.
|
|
822
|
+
*/
|
|
823
|
+
router.get('/:id/semantic-status', (req, res) => {
|
|
824
|
+
const project = (0, config_1.getProject)(req.params.id);
|
|
825
|
+
if (!project) {
|
|
826
|
+
res.status(404).json({ error: 'Not found' });
|
|
827
|
+
return;
|
|
828
|
+
}
|
|
829
|
+
if (!(0, config_1.isProjectOwner)(project, req.user?.username) &&
|
|
830
|
+
!project.shares?.some((s) => s.username === req.user?.username) &&
|
|
831
|
+
!(0, config_1.isAdminUser)(req.user?.username)) {
|
|
832
|
+
res.status(403).json({ error: 'Forbidden' });
|
|
833
|
+
return;
|
|
834
|
+
}
|
|
835
|
+
const semantic = session_manager_1.sessionManager.getSemanticStatus(req.params.id);
|
|
836
|
+
const fresh = semantic && Date.now() - semantic.updatedAt <= 30000;
|
|
837
|
+
res.json({
|
|
838
|
+
active: !!(semantic && fresh),
|
|
839
|
+
semantic: fresh ? semantic : undefined,
|
|
840
|
+
});
|
|
841
|
+
});
|
|
763
842
|
exports.default = router;
|
|
764
843
|
//# sourceMappingURL=projects.js.map
|