drafted 1.19.41 → 1.19.43
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/mcp/server.mjs +29 -11
- package/package.json +1 -1
package/mcp/server.mjs
CHANGED
|
@@ -1368,6 +1368,14 @@ function enforceTokenBudget(text, max = MAX_TOOL_RESULT_CHARS) {
|
|
|
1368
1368
|
return head + tail;
|
|
1369
1369
|
}
|
|
1370
1370
|
|
|
1371
|
+
// Mirrors projectIsTrashed in src/db/queries.ts and isTrashed() in home-html.mjs:
|
|
1372
|
+
// a project is out of the active listing if it has a trashedAt clock OR carries
|
|
1373
|
+
// the legacy '__archived' folder sentinel. Both are checked because pre-Trash
|
|
1374
|
+
// rows still hold the sentinel and were deliberately not migrated onto a clock.
|
|
1375
|
+
function isTrashedRow(x) {
|
|
1376
|
+
return !!(x && (x.trashedAt || x.folder === '__archived'));
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1371
1379
|
function ok(text, opts) {
|
|
1372
1380
|
const str = typeof text === 'string' ? text : JSON.stringify(text, null, 2);
|
|
1373
1381
|
const result = { content: [{ type: 'text', text: enforceTokenBudget(str) }] };
|
|
@@ -3474,7 +3482,7 @@ tool('fs', 'Navigate Drafted like a local filesystem. A FOLDER is the single con
|
|
|
3474
3482
|
// the row while wiki/skills used the form the caller typed — one result,
|
|
3475
3483
|
// two spellings of one org.
|
|
3476
3484
|
const projectRows = (Array.isArray(projects.v?.projects) ? projects.v.projects : [])
|
|
3477
|
-
.filter(x => x
|
|
3485
|
+
.filter(x => !isTrashedRow(x));
|
|
3478
3486
|
const folderById = new Map(projectRows.map(x => [x.id, x.folder || '']));
|
|
3479
3487
|
const orgAs = canonicalOrg;
|
|
3480
3488
|
section('Projects', projects, () => {
|
|
@@ -3821,7 +3829,7 @@ tool('fs', 'Navigate Drafted like a local filesystem. A FOLDER is the single con
|
|
|
3821
3829
|
// active list — mirroring the web UI. An org-scoped root lists ONLY that
|
|
3822
3830
|
// org's projects (Shape A).
|
|
3823
3831
|
const listing = await api('GET', '/api/projects');
|
|
3824
|
-
let rows = (Array.isArray(listing?.projects) ? listing.projects : []).filter(x => x
|
|
3832
|
+
let rows = (Array.isArray(listing?.projects) ? listing.projects : []).filter(x => !isTrashedRow(x));
|
|
3825
3833
|
if (orgFromPath) {
|
|
3826
3834
|
const kept = [];
|
|
3827
3835
|
for (const x of rows) {
|
|
@@ -4147,27 +4155,37 @@ tool('fs', 'Navigate Drafted like a local filesystem. A FOLDER is the single con
|
|
|
4147
4155
|
return ok(result);
|
|
4148
4156
|
}
|
|
4149
4157
|
case 'rm': {
|
|
4150
|
-
// Project-level rm =
|
|
4151
|
-
//
|
|
4152
|
-
//
|
|
4153
|
-
//
|
|
4158
|
+
// Project-level rm = move to Trash (soft delete). Frame/lane rm still
|
|
4159
|
+
// deletes those items outright, but a whole project is never
|
|
4160
|
+
// hard-deleted by an agent — a human does that from the Trash bin, or
|
|
4161
|
+
// the server's purge sweep does it after the retention window.
|
|
4162
|
+
// It now goes through DELETE (which trashes unless ?permanent=1) rather
|
|
4163
|
+
// than PATCHing folder='__archived': the sentinel overwrote the
|
|
4164
|
+
// project's real folder, so restoring dumped it at the org root.
|
|
4154
4165
|
// A layer or lane path has no filename, so it used to fall through to
|
|
4155
4166
|
// the archive branch and archive the WHOLE project — with a
|
|
4156
4167
|
// success-shaped response. /slides/deck and /slides are one keystroke
|
|
4157
|
-
// from the project path; only the bare project path may
|
|
4168
|
+
// from the project path; only the bare project path may trash.
|
|
4158
4169
|
const scope = rmScope(layer, lane, filename);
|
|
4159
4170
|
if (scope === 'directory') {
|
|
4160
4171
|
return err(new Error(
|
|
4161
4172
|
`rm on a ${lane ? 'lane' : 'layer'} path deletes nothing — Drafted has no directory delete. ` +
|
|
4162
4173
|
`Remove the frames individually: /projects/<project>/${layer}${lane ? '/' + lane : ''}/<file>. ` +
|
|
4163
|
-
`To
|
|
4174
|
+
`To trash the whole project, address the project itself: /projects/<project>`
|
|
4164
4175
|
));
|
|
4165
4176
|
}
|
|
4166
4177
|
if (scope === 'project') {
|
|
4167
4178
|
const pid = getState().projectId;
|
|
4168
|
-
if (!pid) return err(new Error('could not resolve project id for
|
|
4169
|
-
const result = await api('
|
|
4170
|
-
|
|
4179
|
+
if (!pid) return err(new Error('could not resolve project id for trash'));
|
|
4180
|
+
const result = await api('DELETE', `/api/project/${pid}`, undefined, orgHeader);
|
|
4181
|
+
const days = result?.retentionDays ?? 30;
|
|
4182
|
+
return ok({
|
|
4183
|
+
trashed: true,
|
|
4184
|
+
project: projectRef,
|
|
4185
|
+
projectId: pid,
|
|
4186
|
+
retentionDays: days,
|
|
4187
|
+
trashHint: `The project is in the Trash bin in the web UI sidebar. It keeps its folder and can be restored there for ${days} days, after which it is deleted permanently.`,
|
|
4188
|
+
});
|
|
4171
4189
|
}
|
|
4172
4190
|
const rmPath = lane ? `/${layer}/${lane}/${filename}` : `/${layer}/${filename}`;
|
|
4173
4191
|
const result = await api('DELETE', `/api/fs/${rmPath.replace(/^\//, '')}`, undefined, orgHeader);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "drafted",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.43",
|
|
4
4
|
"description": "Drafted — visual thinking surface for humans and AI agents. Renders HTML, markdown, images, and code as frames on a zoomable canvas, with MCP tools for AI agents and real-time sync for humans.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|