@displaydev/cli 0.21.1 → 0.23.1
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/dist/api-client.js +105 -2
- package/dist/main.js +95 -8
- package/dist/mcp-server.js +23 -0
- package/package.json +1 -1
package/dist/api-client.js
CHANGED
|
@@ -285,6 +285,22 @@ function _ts_generator(thisArg, body) {
|
|
|
285
285
|
* HTTP client for the display.dev API.
|
|
286
286
|
* Used by the stdio MCP server to proxy tool calls to the REST API.
|
|
287
287
|
*/ import { readLatestVersionFromResponse } from './update-notice.js';
|
|
288
|
+
/**
|
|
289
|
+
* Auto-detect actor type at ApiClient construction. Any of stdin /
|
|
290
|
+
* stdout / stderr being a TTY counts as interactive — handles the
|
|
291
|
+
* common `dsp publish < file.html` case where stdin is piped but the
|
|
292
|
+
* user is still at the terminal watching output. Non-TTY → `agent`,
|
|
293
|
+
* the assumption being that scripted/agent invocations outnumber
|
|
294
|
+
* humans-on-the-terminal as the agent-native model takes hold.
|
|
295
|
+
*
|
|
296
|
+
* Spec §3.2: detection happens once per `ApiClient` instance, not per
|
|
297
|
+
* request — process stdio doesn't change mid-run.
|
|
298
|
+
*/ export function detectActorTypeFromTty() {
|
|
299
|
+
var stdinTty = Boolean(process.stdin.isTTY);
|
|
300
|
+
var stdoutTty = Boolean(process.stdout.isTTY);
|
|
301
|
+
var stderrTty = Boolean(process.stderr.isTTY);
|
|
302
|
+
return stdinTty || stdoutTty || stderrTty ? 'human' : 'agent';
|
|
303
|
+
}
|
|
288
304
|
export var ApiError = /*#__PURE__*/ function(Error1) {
|
|
289
305
|
"use strict";
|
|
290
306
|
_inherits(ApiError, Error1);
|
|
@@ -312,26 +328,84 @@ export var ApiClient = /*#__PURE__*/ function() {
|
|
|
312
328
|
"use strict";
|
|
313
329
|
function ApiClient(config) {
|
|
314
330
|
_class_call_check(this, ApiClient);
|
|
315
|
-
var _config_clientType, _config_version, _config_clientSource;
|
|
331
|
+
var _config_clientType, _config_version, _config_clientSource, _config_actorType;
|
|
316
332
|
_define_property(this, "baseUrl", void 0);
|
|
317
333
|
_define_property(this, "apiKey", void 0);
|
|
318
334
|
_define_property(this, "clientType", void 0);
|
|
319
335
|
_define_property(this, "version", void 0);
|
|
320
336
|
_define_property(this, "clientSource", void 0);
|
|
337
|
+
/**
|
|
338
|
+
* Final `X-Actor-Type` value. Defaults to the auto-detected value
|
|
339
|
+
* (TTY → `human`, non-TTY → `agent`) but `dsp mcp` clears it so
|
|
340
|
+
* the server's transport-based classification (`mcp` → `agent`)
|
|
341
|
+
* isn't layered on top of a CLI isTTY signal that's incoherent
|
|
342
|
+
* inside the spawned MCP server's request lifecycle.
|
|
343
|
+
*/ _define_property(this, "actorType", void 0);
|
|
344
|
+
/**
|
|
345
|
+
* Per-request actor-name source. Resolved lazily at every fetch so
|
|
346
|
+
* the MCP server can plug in `() => server.server.getClientVersion()`
|
|
347
|
+
* without worrying about the `oninitialized` notification race —
|
|
348
|
+
* `getClientVersion()` is populated synchronously inside the SDK's
|
|
349
|
+
* `initialize` request handler, well before any subsequent tool call
|
|
350
|
+
* lands. Direct `dsp` subcommands set a static value via
|
|
351
|
+
* `setActorName(...)` from the `--actor-name` flag or
|
|
352
|
+
* `DISPLAYDEV_ACTOR_NAME` env.
|
|
353
|
+
*/ _define_property(this, "actorNameProvider", null);
|
|
321
354
|
this.baseUrl = config.baseUrl.replace(/\/$/, '');
|
|
322
355
|
this.apiKey = config.apiKey;
|
|
323
356
|
this.clientType = (_config_clientType = config.clientType) !== null && _config_clientType !== void 0 ? _config_clientType : 'mcp-stdio';
|
|
324
357
|
this.version = (_config_version = config.version) !== null && _config_version !== void 0 ? _config_version : '';
|
|
325
358
|
this.clientSource = (_config_clientSource = config.clientSource) !== null && _config_clientSource !== void 0 ? _config_clientSource : '';
|
|
359
|
+
this.actorType = (_config_actorType = config.actorType) !== null && _config_actorType !== void 0 ? _config_actorType : detectActorTypeFromTty();
|
|
360
|
+
if (config.actorName) {
|
|
361
|
+
this.setActorName(config.actorName);
|
|
362
|
+
}
|
|
326
363
|
}
|
|
327
364
|
_create_class(ApiClient, [
|
|
365
|
+
{
|
|
366
|
+
/** Clear the auto-detected `X-Actor-Type` (used by `dsp mcp`). */ key: "clearActorType",
|
|
367
|
+
value: function clearActorType() {
|
|
368
|
+
this.actorType = null;
|
|
369
|
+
}
|
|
370
|
+
},
|
|
371
|
+
{
|
|
372
|
+
/**
|
|
373
|
+
* Set a static `X-Actor-Name` value. Equivalent to passing a
|
|
374
|
+
* provider that always returns `name`. Pass `null` to clear.
|
|
375
|
+
* Normalization (ASCII strip + 128-char truncate) runs at wire
|
|
376
|
+
* time inside `resolveActorName`.
|
|
377
|
+
*/ key: "setActorName",
|
|
378
|
+
value: function setActorName(name) {
|
|
379
|
+
if (name === null) {
|
|
380
|
+
this.actorNameProvider = null;
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
this.actorNameProvider = function() {
|
|
384
|
+
return name;
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
},
|
|
388
|
+
{
|
|
389
|
+
/**
|
|
390
|
+
* Set a callback resolved on every outgoing request. Used by the
|
|
391
|
+
* stdio MCP server to forward `server.server.getClientVersion()`
|
|
392
|
+
* lazily — the cached value lands during the SDK's `initialize`
|
|
393
|
+
* request handler (synchronously), so by the time the next tool
|
|
394
|
+
* call lands, the provider returns the correct
|
|
395
|
+
* `${name}@${version}` regardless of when `oninitialized` fires.
|
|
396
|
+
*/ key: "setActorNameProvider",
|
|
397
|
+
value: function setActorNameProvider(provider) {
|
|
398
|
+
this.actorNameProvider = provider;
|
|
399
|
+
}
|
|
400
|
+
},
|
|
328
401
|
{
|
|
329
402
|
key: "clientHeaders",
|
|
330
403
|
value: /**
|
|
331
404
|
* Build the request-side header set. Always carries `X-Client-Type`;
|
|
332
405
|
* adds `X-Client-Version` when the client was constructed with one;
|
|
333
406
|
* adds `X-Client-Source` when a distribution-channel attribution was
|
|
334
|
-
* configured
|
|
407
|
+
* configured; adds `X-Actor-Name` when a provider returns a non-empty
|
|
408
|
+
* normalized value.
|
|
335
409
|
*/ function clientHeaders(extra) {
|
|
336
410
|
var headers = _object_spread({
|
|
337
411
|
'X-Client-Type': this.clientType
|
|
@@ -339,10 +413,39 @@ export var ApiClient = /*#__PURE__*/ function() {
|
|
|
339
413
|
'X-Client-Version': this.version
|
|
340
414
|
} : {}, this.clientSource ? {
|
|
341
415
|
'X-Client-Source': this.clientSource
|
|
416
|
+
} : {}, this.actorType ? {
|
|
417
|
+
'X-Actor-Type': this.actorType
|
|
342
418
|
} : {}, extra);
|
|
419
|
+
var actor = this.resolveActorName();
|
|
420
|
+
if (actor) {
|
|
421
|
+
headers['X-Actor-Name'] = actor;
|
|
422
|
+
}
|
|
343
423
|
return headers;
|
|
344
424
|
}
|
|
345
425
|
},
|
|
426
|
+
{
|
|
427
|
+
key: "resolveActorName",
|
|
428
|
+
value: /**
|
|
429
|
+
* Resolve and normalize the current actor name. Returns `null` when
|
|
430
|
+
* no provider is set or the provider returns an empty string after
|
|
431
|
+
* sanitization. We strip non-ASCII and truncate to 128 chars as a
|
|
432
|
+
* defensive cleanup; the API re-normalizes (including comma-split
|
|
433
|
+
* + trim) in `normalizeActorName`, so the persisted value is
|
|
434
|
+
* authoritative — these client-side passes just keep the wire
|
|
435
|
+
* frame within bounds.
|
|
436
|
+
*/ function resolveActorName() {
|
|
437
|
+
if (!this.actorNameProvider) {
|
|
438
|
+
return null;
|
|
439
|
+
}
|
|
440
|
+
var raw = this.actorNameProvider();
|
|
441
|
+
if (!raw) {
|
|
442
|
+
return null;
|
|
443
|
+
}
|
|
444
|
+
var cleaned = raw// eslint-disable-next-line no-control-regex
|
|
445
|
+
.replace(/[^\x20-\x7e]/g, '').slice(0, 128);
|
|
446
|
+
return cleaned.length > 0 ? cleaned : null;
|
|
447
|
+
}
|
|
448
|
+
},
|
|
346
449
|
{
|
|
347
450
|
key: "observeResponse",
|
|
348
451
|
value: /**
|
package/dist/main.js
CHANGED
|
@@ -310,13 +310,58 @@ function resolveClientSource() {
|
|
|
310
310
|
}
|
|
311
311
|
return undefined;
|
|
312
312
|
}
|
|
313
|
+
/**
|
|
314
|
+
* User-grade override for the CLI's auto-detected isTTY classification
|
|
315
|
+
* — needed when a human pipes output (auto-detected as `agent`) or a
|
|
316
|
+
* custom script flips an interactive shell to `agent`. Server enforces
|
|
317
|
+
* the `{human, agent}` closed range; unknown values trip a clear error
|
|
318
|
+
* here so the user gets feedback instead of silent fallthrough. An
|
|
319
|
+
* explicit blank (`--actor-type=`) resets to "no override".
|
|
320
|
+
*/ var actorFromFlag;
|
|
321
|
+
var actorFlagPassed = false;
|
|
322
|
+
function parseActorOrExit(raw, source) {
|
|
323
|
+
var lower = raw.trim().toLowerCase();
|
|
324
|
+
if (lower === 'human' || lower === 'agent') {
|
|
325
|
+
return lower;
|
|
326
|
+
}
|
|
327
|
+
console.error("Invalid ".concat(source, ": ").concat(raw, ". Use human or agent."));
|
|
328
|
+
process.exit(1);
|
|
329
|
+
}
|
|
330
|
+
function resolveActorOverride() {
|
|
331
|
+
if (actorFlagPassed) {
|
|
332
|
+
return actorFromFlag;
|
|
333
|
+
}
|
|
334
|
+
var env = process.env.DISPLAYDEV_ACTOR_TYPE;
|
|
335
|
+
if (typeof env === 'string' && env.length > 0) {
|
|
336
|
+
return parseActorOrExit(env, 'DISPLAYDEV_ACTOR_TYPE');
|
|
337
|
+
}
|
|
338
|
+
return undefined;
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Independent of `--actor-type` — any actor type can carry a name
|
|
342
|
+
* (e.g. a script-mode label for a human, the key-name proxy for an
|
|
343
|
+
* org-key write).
|
|
344
|
+
*/ var actorNameFromFlag;
|
|
345
|
+
var actorNameFlagPassed = false;
|
|
346
|
+
function resolveActorName() {
|
|
347
|
+
if (actorNameFlagPassed) {
|
|
348
|
+
return actorNameFromFlag;
|
|
349
|
+
}
|
|
350
|
+
var env = process.env.DISPLAYDEV_ACTOR_NAME;
|
|
351
|
+
if (typeof env === 'string' && env.length > 0) {
|
|
352
|
+
return env;
|
|
353
|
+
}
|
|
354
|
+
return undefined;
|
|
355
|
+
}
|
|
313
356
|
function createClient(auth) {
|
|
314
357
|
return new ApiClient({
|
|
315
358
|
baseUrl: auth.apiUrl,
|
|
316
359
|
apiKey: auth.apiKey,
|
|
317
360
|
clientType: 'cli',
|
|
318
361
|
version: version,
|
|
319
|
-
clientSource: resolveClientSource()
|
|
362
|
+
clientSource: resolveClientSource(),
|
|
363
|
+
actorType: resolveActorOverride(),
|
|
364
|
+
actorName: resolveActorName()
|
|
320
365
|
});
|
|
321
366
|
}
|
|
322
367
|
var program = new Command().name('dsp').description('display.dev CLI — publish artifacts behind company auth').version(version);
|
|
@@ -465,7 +510,9 @@ program.command('publish <path>').description('Publish an HTML or Markdown file.
|
|
|
465
510
|
apiKey: '',
|
|
466
511
|
clientType: 'cli',
|
|
467
512
|
version: version,
|
|
468
|
-
clientSource: resolveClientSource()
|
|
513
|
+
clientSource: resolveClientSource(),
|
|
514
|
+
actorType: resolveActorOverride(),
|
|
515
|
+
actorName: resolveActorName()
|
|
469
516
|
});
|
|
470
517
|
_state.label = 10;
|
|
471
518
|
case 10:
|
|
@@ -504,11 +551,11 @@ program.command('publish <path>').description('Publish an HTML or Markdown file.
|
|
|
504
551
|
console.log(JSON.stringify(publicResult));
|
|
505
552
|
process.stderr.write([
|
|
506
553
|
'',
|
|
507
|
-
"Published anonymously
|
|
554
|
+
"Published anonymously. Claim it to make it yours.",
|
|
508
555
|
" Preview: ".concat(publicResult.previewUrl),
|
|
509
556
|
" Claim: ".concat(publicResult.claimUrl),
|
|
510
557
|
" Expires: ".concat(publicResult.expiresAt),
|
|
511
|
-
"Sign
|
|
558
|
+
"Sign up at the claim URL to move it into your display.dev organization.",
|
|
512
559
|
''
|
|
513
560
|
].join('\n'));
|
|
514
561
|
return [
|
|
@@ -2391,7 +2438,40 @@ program.command('mcp').description('Start MCP server over stdin/stdout').action(
|
|
|
2391
2438
|
}
|
|
2392
2439
|
}
|
|
2393
2440
|
}
|
|
2441
|
+
/**
|
|
2442
|
+
* Actor flags walk the command tree alongside `--client-source` so
|
|
2443
|
+
* every direct-HTTP subcommand can override the auto-detected isTTY
|
|
2444
|
+
* classification or stamp a display name. The flags are also
|
|
2445
|
+
* registered on `mcp` so `dsp mcp --actor-name foo` is silently
|
|
2446
|
+
* accepted; the mcp action builds its `ApiClient` without reading the
|
|
2447
|
+
* stash AND clears `actorType` afterwards so the spawned MCP server's
|
|
2448
|
+
* actor model stays clean.
|
|
2449
|
+
*/ function addActorOptionsRecursive(cmd) {
|
|
2450
|
+
cmd.option('--actor-type <type>', 'Actor classification: human or agent. Overrides the auto-detected isTTY classification.');
|
|
2451
|
+
cmd.option('--actor-name <name>', 'Display name stamped on X-Actor-Name (≤128 chars, ASCII; e.g. ci-deploy-bot, manual-cleanup-batch-3).');
|
|
2452
|
+
var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
|
|
2453
|
+
try {
|
|
2454
|
+
for(var _iterator = cmd.commands[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
|
|
2455
|
+
var child = _step.value;
|
|
2456
|
+
addActorOptionsRecursive(child);
|
|
2457
|
+
}
|
|
2458
|
+
} catch (err) {
|
|
2459
|
+
_didIteratorError = true;
|
|
2460
|
+
_iteratorError = err;
|
|
2461
|
+
} finally{
|
|
2462
|
+
try {
|
|
2463
|
+
if (!_iteratorNormalCompletion && _iterator.return != null) {
|
|
2464
|
+
_iterator.return();
|
|
2465
|
+
}
|
|
2466
|
+
} finally{
|
|
2467
|
+
if (_didIteratorError) {
|
|
2468
|
+
throw _iteratorError;
|
|
2469
|
+
}
|
|
2470
|
+
}
|
|
2471
|
+
}
|
|
2472
|
+
}
|
|
2394
2473
|
addClientSourceOptionRecursive(program);
|
|
2474
|
+
addActorOptionsRecursive(program);
|
|
2395
2475
|
/**
|
|
2396
2476
|
* Resolve the parsed flag value before each action. Program-level
|
|
2397
2477
|
* `preAction` hooks fire ahead of every subcommand action, so a single
|
|
@@ -2402,11 +2482,18 @@ addClientSourceOptionRecursive(program);
|
|
|
2402
2482
|
*/ program.hook('preAction', function(_thisCommand, actionCommand) {
|
|
2403
2483
|
var cursor = actionCommand;
|
|
2404
2484
|
while(cursor){
|
|
2405
|
-
var
|
|
2406
|
-
if (typeof
|
|
2485
|
+
var opts = cursor.opts();
|
|
2486
|
+
if (!clientSourceFlagPassed && typeof opts.clientSource === 'string') {
|
|
2407
2487
|
clientSourceFlagPassed = true;
|
|
2408
|
-
clientSourceFromFlag =
|
|
2409
|
-
|
|
2488
|
+
clientSourceFromFlag = opts.clientSource.length > 0 ? opts.clientSource : undefined;
|
|
2489
|
+
}
|
|
2490
|
+
if (!actorFlagPassed && typeof opts.actorType === 'string') {
|
|
2491
|
+
actorFlagPassed = true;
|
|
2492
|
+
actorFromFlag = opts.actorType.length > 0 ? parseActorOrExit(opts.actorType, '--actor-type') : undefined;
|
|
2493
|
+
}
|
|
2494
|
+
if (!actorNameFlagPassed && typeof opts.actorName === 'string') {
|
|
2495
|
+
actorNameFlagPassed = true;
|
|
2496
|
+
actorNameFromFlag = opts.actorName.length > 0 ? opts.actorName : undefined;
|
|
2410
2497
|
}
|
|
2411
2498
|
cursor = cursor.parent;
|
|
2412
2499
|
}
|
package/dist/mcp-server.js
CHANGED
|
@@ -279,6 +279,29 @@ export function startMcpServer(_0) {
|
|
|
279
279
|
}, {
|
|
280
280
|
instructions: mode === 'public' ? PUBLIC_INSTRUCTIONS : AUTHENTICATED_INSTRUCTIONS
|
|
281
281
|
});
|
|
282
|
+
// The spawned MCP server is its own actor model: transport=`mcp` +
|
|
283
|
+
// `clientInfo`-derived `actorName`. Layering the CLI's auto-
|
|
284
|
+
// detected `X-Actor-Type` on top of MCP requests would be incoherent
|
|
285
|
+
// (the `dsp mcp` host's TTY shape says nothing about the agent
|
|
286
|
+
// talking through the MCP server), so clear it here — server-side
|
|
287
|
+
// resolveActor classifies MCP transport as `agent` via rule 6.
|
|
288
|
+
apiClient.clearActorType();
|
|
289
|
+
// Plug the SDK's cached `clientInfo` into the apiClient on every
|
|
290
|
+
// outgoing HTTP request. The MCP protocol populates the cache
|
|
291
|
+
// synchronously inside the `initialize` request handler, which
|
|
292
|
+
// completes before any subsequent tool call lands — using a lazy
|
|
293
|
+
// provider (rather than the `oninitialized` notification handler)
|
|
294
|
+
// sidesteps the notification-dispatch race where a fast client
|
|
295
|
+
// pipelines tool calls right after `notifications/initialized`.
|
|
296
|
+
// Server-side construction per spec §3.3 — the wire value is built
|
|
297
|
+
// from SDK-cached fields, never from a client-supplied header.
|
|
298
|
+
apiClient.setActorNameProvider(function() {
|
|
299
|
+
var info = server.server.getClientVersion();
|
|
300
|
+
if (!info || !info.name) {
|
|
301
|
+
return null;
|
|
302
|
+
}
|
|
303
|
+
return info.version ? "".concat(info.name, "@").concat(info.version) : info.name;
|
|
304
|
+
});
|
|
282
305
|
if (mode === 'public') {
|
|
283
306
|
registerPublicTools(server, apiClient);
|
|
284
307
|
} else {
|