drafted 1.11.10 → 1.11.11
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/cli/drafted.mjs +18 -12
- package/package.json +1 -1
package/cli/drafted.mjs
CHANGED
|
@@ -234,14 +234,17 @@ function withQuery(base, params) {
|
|
|
234
234
|
}
|
|
235
235
|
|
|
236
236
|
// GET a Drafted API path with the stored session and return parsed JSON.
|
|
237
|
-
// Strictly read-only: callers only ever issue GETs through this seam.
|
|
238
|
-
//
|
|
239
|
-
|
|
237
|
+
// Strictly read-only: callers only ever issue GETs through this seam. An
|
|
238
|
+
// optional --org override is forwarded as the X-Drafted-Org header (the server
|
|
239
|
+
// validates it against the caller's memberships). On any failure it emits a
|
|
240
|
+
// structured error (for --json) and exits non-zero.
|
|
241
|
+
async function readApiGet(command, apiPath, org) {
|
|
240
242
|
requireLogin();
|
|
241
243
|
const serverUrl = getServerUrl();
|
|
244
|
+
const headers = org ? { 'X-Drafted-Org': org } : {};
|
|
242
245
|
let res;
|
|
243
246
|
try {
|
|
244
|
-
res = await authFetch(`${serverUrl}${apiPath}
|
|
247
|
+
res = await authFetch(`${serverUrl}${apiPath}`, { headers });
|
|
245
248
|
} catch (err) {
|
|
246
249
|
jsonOut(false, command, `Could not reach server at ${serverUrl}: ${err.message}`);
|
|
247
250
|
console.error(`❌ Could not reach server at ${serverUrl}: ${err.message}`);
|
|
@@ -1145,10 +1148,9 @@ program
|
|
|
1145
1148
|
//
|
|
1146
1149
|
// Project scoping: --project <id> selects the project (passed through as a query
|
|
1147
1150
|
// param). When omitted, the server resolves the caller's active project. Org is
|
|
1148
|
-
// the logged-in session's active org
|
|
1149
|
-
//
|
|
1150
|
-
//
|
|
1151
|
-
// yet scope.)
|
|
1151
|
+
// the logged-in session's active org unless --org <id|name> is given, which the
|
|
1152
|
+
// server validates against the caller's memberships and scopes per-request via
|
|
1153
|
+
// the X-Drafted-Org header — without mutating the shared session's active org.
|
|
1152
1154
|
|
|
1153
1155
|
// Command: ls (alias: list) — list layers / lanes / frames
|
|
1154
1156
|
program
|
|
@@ -1156,6 +1158,7 @@ program
|
|
|
1156
1158
|
.alias('list')
|
|
1157
1159
|
.description('List layers, lanes, or frames in a project (read-only)')
|
|
1158
1160
|
.option('--project <id>', 'Target project ID (defaults to your active project)')
|
|
1161
|
+
.option('--org <org>', 'Resolve against this org (id or name); scopes per-request without switching the session')
|
|
1159
1162
|
.option('--recursive', 'Recurse into subdirectories (forces summary mode)')
|
|
1160
1163
|
.option('--summary', 'Include size, updatedAt, and title for frames')
|
|
1161
1164
|
.option('--pattern <glob>', 'Filter frame filenames (e.g. "*.html")')
|
|
@@ -1163,7 +1166,7 @@ program
|
|
|
1163
1166
|
const params = { path: path || '/', projectId: options.project, pattern: options.pattern };
|
|
1164
1167
|
if (options.recursive) { params.recursive = 'true'; params.summary = 'true'; }
|
|
1165
1168
|
else if (options.summary) params.summary = 'true';
|
|
1166
|
-
const data = await readApiGet('ls', withQuery('/api/fs/', params));
|
|
1169
|
+
const data = await readApiGet('ls', withQuery('/api/fs/', params), options.org);
|
|
1167
1170
|
jsonOut(true, 'ls', data);
|
|
1168
1171
|
printLs(data);
|
|
1169
1172
|
});
|
|
@@ -1174,6 +1177,7 @@ program
|
|
|
1174
1177
|
.aliases(['get', 'cat'])
|
|
1175
1178
|
.description("Read a frame's content (HTML/text/markdown), or binary metadata, by path / frame URL / ID (read-only)")
|
|
1176
1179
|
.option('--project <id>', 'Target project ID (defaults to your active project)')
|
|
1180
|
+
.option('--org <org>', 'Resolve against this org (id or name); scopes per-request without switching the session')
|
|
1177
1181
|
.option('--lines <range>', 'Line range to read, e.g. "1-40" or "20"')
|
|
1178
1182
|
.action(async (pathOrId, options) => {
|
|
1179
1183
|
let apiPath;
|
|
@@ -1184,7 +1188,7 @@ program
|
|
|
1184
1188
|
console.error(`❌ ${err.message}`);
|
|
1185
1189
|
process.exit(1);
|
|
1186
1190
|
}
|
|
1187
|
-
const data = await readApiGet('read', apiPath);
|
|
1191
|
+
const data = await readApiGet('read', apiPath, options.org);
|
|
1188
1192
|
jsonOut(true, 'read', data);
|
|
1189
1193
|
if (data.type === 'binary') {
|
|
1190
1194
|
console.log(`# ${data.path} (binary)`);
|
|
@@ -1206,10 +1210,11 @@ assetCmd
|
|
|
1206
1210
|
.command('list')
|
|
1207
1211
|
.description('List supporting assets (CSS/JS/images/fonts) in a project')
|
|
1208
1212
|
.requiredOption('--project <id>', 'Target project ID')
|
|
1213
|
+
.option('--org <org>', 'Resolve against this org (id or name); scopes per-request without switching the session')
|
|
1209
1214
|
.option('--frame <id>', 'Only assets associated with this frame ID')
|
|
1210
1215
|
.action(async (options) => {
|
|
1211
1216
|
const apiPath = withQuery(`/api/projects/${encodeURIComponent(options.project)}/assets`, { frameId: options.frame });
|
|
1212
|
-
const data = await readApiGet('asset-list', apiPath);
|
|
1217
|
+
const data = await readApiGet('asset-list', apiPath, options.org);
|
|
1213
1218
|
jsonOut(true, 'asset-list', data);
|
|
1214
1219
|
const assets = data.assets || [];
|
|
1215
1220
|
if (assets.length === 0) { console.log('No assets'); return; }
|
|
@@ -1223,8 +1228,9 @@ assetCmd
|
|
|
1223
1228
|
.command('get <asset_path>')
|
|
1224
1229
|
.description("Show a single asset's metadata (path, type, size, frame). Metadata only — asset bytes are not served over the API.")
|
|
1225
1230
|
.requiredOption('--project <id>', 'Target project ID')
|
|
1231
|
+
.option('--org <org>', 'Resolve against this org (id or name); scopes per-request without switching the session')
|
|
1226
1232
|
.action(async (assetPath, options) => {
|
|
1227
|
-
const data = await readApiGet('asset-get', `/api/projects/${encodeURIComponent(options.project)}/assets
|
|
1233
|
+
const data = await readApiGet('asset-get', `/api/projects/${encodeURIComponent(options.project)}/assets`, options.org);
|
|
1228
1234
|
const wanted = assetPath.replace(/^\/+/, '');
|
|
1229
1235
|
const asset = (data.assets || []).find(a => a.path === assetPath || a.path === wanted);
|
|
1230
1236
|
if (!asset) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "drafted",
|
|
3
|
-
"version": "1.11.
|
|
3
|
+
"version": "1.11.11",
|
|
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": [
|