@stigmer/cli 3.18.1-dev.20260919070736 → 3.19.0
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/commands/apply.js +3 -1
- package/commands/apply.js.map +1 -1
- package/commands/install.js +2 -1
- package/commands/install.js.map +1 -1
- package/commands/marketplace.js +3 -3
- package/commands/marketplace.js.map +1 -1
- package/commands/push.js +3 -1
- package/commands/push.js.map +1 -1
- package/marketplace/config.d.ts.map +1 -1
- package/marketplace/config.js +13 -9
- package/marketplace/config.js.map +1 -1
- package/marketplace/render.d.ts.map +1 -1
- package/marketplace/render.js +1 -7
- package/marketplace/render.js.map +1 -1
- package/package.json +7 -7
- package/resources/connect/oauth.d.ts.map +1 -1
- package/resources/connect/oauth.js +4 -1
- package/resources/connect/oauth.js.map +1 -1
- package/resources/plugin.d.ts +27 -0
- package/resources/plugin.d.ts.map +1 -1
- package/resources/plugin.js +113 -8
- package/resources/plugin.js.map +1 -1
- package/src/commands/apply.ts +6 -1
- package/src/commands/install.test.ts +20 -21
- package/src/commands/install.ts +2 -1
- package/src/commands/marketplace.test.ts +10 -19
- package/src/commands/marketplace.ts +3 -3
- package/src/commands/push.ts +6 -1
- package/src/local/plugins/defaults.test.ts +28 -28
- package/src/marketplace/__fixtures__/cursor-marketplace.ts +16 -12
- package/src/marketplace/config.test.ts +12 -28
- package/src/marketplace/config.ts +13 -9
- package/src/marketplace/install.test.ts +19 -19
- package/src/marketplace/read.test.ts +6 -6
- package/src/marketplace/render.ts +1 -10
- package/src/resources/connect/oauth.test.ts +2 -2
- package/src/resources/connect/oauth.ts +4 -1
- package/src/resources/plugin.test.ts +119 -2
- package/src/resources/plugin.ts +140 -8
package/src/resources/plugin.ts
CHANGED
|
@@ -23,6 +23,15 @@
|
|
|
23
23
|
// and what `stigmer up` compares with the server's digest before deciding
|
|
24
24
|
// to push. `validate -f`, `push plugin --dry-run` and `push plugin` share one
|
|
25
25
|
// description renderer so the author reads one vocabulary at every step.
|
|
26
|
+
//
|
|
27
|
+
// `readNextSteps` is what the install leaves the user to do, read from the
|
|
28
|
+
// servers the push produced: a sign-in an OAuth server needs (`stigmer
|
|
29
|
+
// connect mcp-server` runs it), the variables an API-key server wants and
|
|
30
|
+
// where they are asked, and, for a plugin that installed tools and no
|
|
31
|
+
// agent, the agent the tools still need. Best-effort by design: a server
|
|
32
|
+
// or a grant the CLI cannot read yields no line rather than a failed
|
|
33
|
+
// install, because the install itself succeeded. `stigmer up` does not
|
|
34
|
+
// read them: its plugin is the built-in assistant, not a user's act.
|
|
26
35
|
|
|
27
36
|
import { readdirSync, readFileSync, statSync } from "node:fs";
|
|
28
37
|
import { join } from "node:path";
|
|
@@ -48,6 +57,10 @@ import {
|
|
|
48
57
|
PushPluginRequestSchema,
|
|
49
58
|
type PluginMember,
|
|
50
59
|
} from "@stigmer/protos/ai/stigmer/agentic/plugin/v1/io_pb";
|
|
60
|
+
import {
|
|
61
|
+
GetOAuthGrantStatusInputSchema,
|
|
62
|
+
OAuthConnectionHealth,
|
|
63
|
+
} from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/io_pb";
|
|
51
64
|
import { PluginDialect as PluginDialectProto } from "@stigmer/protos/ai/stigmer/agentic/plugin/v1/spec_pb";
|
|
52
65
|
import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
|
|
53
66
|
import type { ApiResourceVisibility } from "@stigmer/protos/ai/stigmer/commons/apiresource/enum_pb";
|
|
@@ -390,6 +403,113 @@ export async function pushPlugin(
|
|
|
390
403
|
export interface RenderPushOptions {
|
|
391
404
|
/** Where the archive came from when it was not a folder: the marketplace's name and source. */
|
|
392
405
|
readonly installedFrom?: string;
|
|
406
|
+
/** What the install leaves the user to do, from `readNextSteps`. */
|
|
407
|
+
readonly next?: readonly NextStep[];
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/** One thing standing between an installed MCP server and its first tool call, or the agent the tools still need. */
|
|
411
|
+
export type NextStep =
|
|
412
|
+
| { readonly kind: "sign-in"; readonly server: string; readonly command: string }
|
|
413
|
+
| { readonly kind: "signed-in"; readonly server: string }
|
|
414
|
+
| {
|
|
415
|
+
readonly kind: "api-key";
|
|
416
|
+
readonly server: string;
|
|
417
|
+
readonly variables: readonly string[];
|
|
418
|
+
/** Where the variables are asked: the agent's first session, or `stigmer connect mcp-server --env`. */
|
|
419
|
+
readonly askedAt: "agent" | "connect";
|
|
420
|
+
readonly command?: string;
|
|
421
|
+
}
|
|
422
|
+
| { readonly kind: "add-to-agent"; readonly servers: readonly string[] };
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* What the install leaves the user to do, read from each MCP server the
|
|
426
|
+
* push produced. Best-effort: a server or grant this CLI cannot read yields
|
|
427
|
+
* no step, never a failure, because the install itself succeeded.
|
|
428
|
+
*/
|
|
429
|
+
export async function readNextSteps(
|
|
430
|
+
client: Stigmer,
|
|
431
|
+
org: string,
|
|
432
|
+
members: readonly PluginMember[],
|
|
433
|
+
): Promise<NextStep[]> {
|
|
434
|
+
const servers = members.filter((m) => m.kind === ApiResourceKind.mcp_server);
|
|
435
|
+
const hasAgent = members.some((m) => m.kind === ApiResourceKind.agent);
|
|
436
|
+
const steps: NextStep[] = [];
|
|
437
|
+
for (const member of servers) {
|
|
438
|
+
try {
|
|
439
|
+
const server = await client.mcpServer.getByReference({
|
|
440
|
+
org,
|
|
441
|
+
slug: member.slug,
|
|
442
|
+
});
|
|
443
|
+
const auth = server.spec?.auth;
|
|
444
|
+
const variables = Object.keys(server.spec?.env ?? {});
|
|
445
|
+
if (auth?.targetEnvVar) {
|
|
446
|
+
let connected = false;
|
|
447
|
+
try {
|
|
448
|
+
const grant = await client.mcpServer.getOAuthGrantStatus(
|
|
449
|
+
create(GetOAuthGrantStatusInputSchema, {
|
|
450
|
+
resourceId: server.metadata?.id ?? "",
|
|
451
|
+
org,
|
|
452
|
+
}),
|
|
453
|
+
);
|
|
454
|
+
connected =
|
|
455
|
+
grant.connected &&
|
|
456
|
+
grant.connectionHealth !==
|
|
457
|
+
OAuthConnectionHealth.OAUTH_CONNECTION_HEALTH_TOKEN_EXPIRED;
|
|
458
|
+
} catch {
|
|
459
|
+
// Fail closed: a grant the CLI cannot read is a sign-in still owed.
|
|
460
|
+
}
|
|
461
|
+
steps.push(
|
|
462
|
+
connected
|
|
463
|
+
? { kind: "signed-in", server: member.slug }
|
|
464
|
+
: {
|
|
465
|
+
kind: "sign-in",
|
|
466
|
+
server: member.slug,
|
|
467
|
+
command: `stigmer connect mcp-server ${member.slug}`,
|
|
468
|
+
},
|
|
469
|
+
);
|
|
470
|
+
} else if (variables.length > 0) {
|
|
471
|
+
steps.push({
|
|
472
|
+
kind: "api-key",
|
|
473
|
+
server: member.slug,
|
|
474
|
+
variables,
|
|
475
|
+
askedAt: hasAgent ? "agent" : "connect",
|
|
476
|
+
...(hasAgent
|
|
477
|
+
? {}
|
|
478
|
+
: {
|
|
479
|
+
command: `stigmer connect mcp-server ${member.slug} --env ${variables.map((v) => `${v}=...`).join(" --env ")}`,
|
|
480
|
+
}),
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
} catch {
|
|
484
|
+
// A server the CLI cannot read has no line; the Installed section still names it.
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
if (!hasAgent && servers.length > 0) {
|
|
488
|
+
steps.push({
|
|
489
|
+
kind: "add-to-agent",
|
|
490
|
+
servers: servers.map((m) => m.slug),
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
return steps;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
function describeNextStep(step: NextStep): string {
|
|
497
|
+
switch (step.kind) {
|
|
498
|
+
case "sign-in":
|
|
499
|
+
return `Sign in to ${step.server}: ${step.command}`;
|
|
500
|
+
case "signed-in":
|
|
501
|
+
return `${step.server}: signed in`;
|
|
502
|
+
case "api-key":
|
|
503
|
+
return step.askedAt === "agent"
|
|
504
|
+
? `${step.server} needs ${step.variables.join(", ")}; the agent asks at its first session`
|
|
505
|
+
: `${step.server} needs ${step.variables.join(", ")}; set them when you connect: ${step.command ?? ""}`;
|
|
506
|
+
case "add-to-agent":
|
|
507
|
+
return `Add these tools to an agent: list ${step.servers.map((s) => `'${s}'`).join(", ")} under mcp_server_usages in an agent's YAML, or from the plugin's page in the console`;
|
|
508
|
+
default: {
|
|
509
|
+
const exhaustive: never = step;
|
|
510
|
+
return exhaustive;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
393
513
|
}
|
|
394
514
|
|
|
395
515
|
/** The install as the user reads it: what landed, what was skipped, what to know. */
|
|
@@ -400,14 +520,20 @@ export function renderPushOutcome(
|
|
|
400
520
|
const { plugin, members } = outcome;
|
|
401
521
|
const warnings = plugin.status?.warnings ?? [];
|
|
402
522
|
const counts = plugin.status?.materialized;
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
523
|
+
// Only the kinds the plugin installed are named, as the console's
|
|
524
|
+
// `summariseInstall` names them: most catalogue plugins install tools
|
|
525
|
+
// alone, and "0 skills, 1 MCP server, 0 agents" reads as three facts.
|
|
526
|
+
const named = (
|
|
527
|
+
[
|
|
528
|
+
[counts?.skills ?? 0, "skill"],
|
|
529
|
+
[counts?.mcpServers ?? 0, "MCP server"],
|
|
530
|
+
[counts?.agents ?? 0, "agent"],
|
|
531
|
+
[counts?.workflows ?? 0, "workflow"],
|
|
532
|
+
] as const
|
|
533
|
+
)
|
|
534
|
+
.filter(([n]) => n > 0)
|
|
535
|
+
.map(([n, noun]) => count(n, noun));
|
|
536
|
+
const summary = named.length === 0 ? "nothing installed" : named.join(", ");
|
|
411
537
|
const headline = `Installed plugin '${plugin.metadata?.slug ?? plugin.spec?.name ?? ""}' (${summary})`;
|
|
412
538
|
const result =
|
|
413
539
|
warnings.length === 0
|
|
@@ -447,9 +573,15 @@ export function renderPushOutcome(
|
|
|
447
573
|
const section = result.addSection("Warnings");
|
|
448
574
|
for (const warning of warnings) section.item(warning.message);
|
|
449
575
|
}
|
|
576
|
+
const next = options.next ?? [];
|
|
577
|
+
if (next.length > 0) {
|
|
578
|
+
const section = result.addSection("Next");
|
|
579
|
+
for (const step of next) section.item(describeNextStep(step));
|
|
580
|
+
}
|
|
450
581
|
return result.withData({
|
|
451
582
|
plugin: toJson(PluginSchema, plugin),
|
|
452
583
|
members: members.map((m) => toJson(PluginMemberSchema, m)),
|
|
584
|
+
...(options.next !== undefined && { next: options.next }),
|
|
453
585
|
});
|
|
454
586
|
}
|
|
455
587
|
|