@loomweaver/mcp 0.11.0 → 0.12.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/dist/main.mjs +65 -12
- package/package.json +1 -1
package/dist/main.mjs
CHANGED
|
@@ -31458,7 +31458,7 @@ function pause(): Promise<void> {
|
|
|
31458
31458
|
}
|
|
31459
31459
|
|
|
31460
31460
|
// ../devkit/src/recipes/angular-weaver/agent-files.ts
|
|
31461
|
-
var AG_UI_ADAPTER_VERSION = "0.
|
|
31461
|
+
var AG_UI_ADAPTER_VERSION = "0.12.0";
|
|
31462
31462
|
var AG_UI_PROTOCOL_VERSION = "0.0.x";
|
|
31463
31463
|
function connectionFile(w) {
|
|
31464
31464
|
return `import { signal } from '@angular/core';
|
|
@@ -31470,11 +31470,6 @@ import {
|
|
|
31470
31470
|
} from '@loomweaver/ag-ui';
|
|
31471
31471
|
import type { PluginContext } from '@loomweaver/plugin-sdk';
|
|
31472
31472
|
|
|
31473
|
-
// Commands an agent may not run on its own word. Each one asks the person at the keyboard first, and
|
|
31474
|
-
// declining stops it: the workbench never sees the call. This weaver's own command is listed as an
|
|
31475
|
-
// example \u2014 replace it with the ones that actually cost something.
|
|
31476
|
-
const CONSEQUENTIAL = new Set(['${w.id}.hello']);
|
|
31477
|
-
|
|
31478
31473
|
// A factory, not a module-level connection: everything a run needs lives in the closure, so a second
|
|
31479
31474
|
// one never shares state with the first.
|
|
31480
31475
|
export function ${w.propertyName}Connection(ctx: PluginContext): CommandTools {
|
|
@@ -31485,11 +31480,21 @@ export function ${w.propertyName}Connection(ctx: PluginContext): CommandTools {
|
|
|
31485
31480
|
// deactivate(), so the panel renders an honest empty state either side of that.
|
|
31486
31481
|
export const ${w.propertyName}Agent = signal<CommandTools | null>(null);
|
|
31487
31482
|
|
|
31483
|
+
// What an agent's word is enough for is the command's own statement, declared where the command is
|
|
31484
|
+
// registered and read off the call here. No list of ids lives beside the commands: a list drifts from
|
|
31485
|
+
// what it describes, and it cannot speak for a command another plugin registered. Acting on the
|
|
31486
|
+
// statement is this weaver's half: the workbench states it and enforces nothing.
|
|
31488
31487
|
async function decide(
|
|
31489
31488
|
ctx: PluginContext,
|
|
31490
31489
|
call: PendingToolCall,
|
|
31491
31490
|
): Promise<ToolDecision> {
|
|
31492
|
-
if (
|
|
31491
|
+
if (call.agentConsent === 'never') {
|
|
31492
|
+
return {
|
|
31493
|
+
decision: 'decline',
|
|
31494
|
+
reason: 'an agent may not run this one on its own word.',
|
|
31495
|
+
};
|
|
31496
|
+
}
|
|
31497
|
+
if (call.agentConsent !== 'ask' && call.agentConsent !== 'ask-always') {
|
|
31493
31498
|
return { decision: 'run' };
|
|
31494
31499
|
}
|
|
31495
31500
|
const yes = await ctx.ui.confirm({
|
|
@@ -31520,7 +31525,8 @@ interface Asked {
|
|
|
31520
31525
|
function contextThat(confirms: boolean, ran: Asked[]): PluginContext {
|
|
31521
31526
|
return {
|
|
31522
31527
|
invocableCommands: () => [
|
|
31523
|
-
|
|
31528
|
+
// agentConsent travels with the command, which is what the connection reads off the call.
|
|
31529
|
+
{ id: '${w.id}.hello', title: '${w.name} action', description: 'Shows a short message.', agentConsent: 'ask' },
|
|
31524
31530
|
],
|
|
31525
31531
|
invokeCommand: (id: string, args?: CommandArguments) => {
|
|
31526
31532
|
ran.push({ id, args });
|
|
@@ -31806,6 +31812,11 @@ function commandBlock(w) {
|
|
|
31806
31812
|
` answers: '${w.id}.actionAnswers',`,
|
|
31807
31813
|
` shortcut: '${w.features.shortcut}',`,
|
|
31808
31814
|
" callable: true,",
|
|
31815
|
+
...w.features.agent ? [
|
|
31816
|
+
" // What an agent's word is enough for. The platform states it and enforces nothing:",
|
|
31817
|
+
" // the asking is the connection's half, which reads this off the call.",
|
|
31818
|
+
" agentConsent: 'ask',"
|
|
31819
|
+
] : [],
|
|
31809
31820
|
" run: (_context, args) => {",
|
|
31810
31821
|
" const tone = toneOf(args?.['tone']);",
|
|
31811
31822
|
` ctx.ui.toast({ message: '${w.id}.action', kind: tone });`,
|
|
@@ -32453,7 +32464,7 @@ var framePlugin = {
|
|
|
32453
32464
|
};
|
|
32454
32465
|
|
|
32455
32466
|
// ../devkit/src/recipes/platform-version.ts
|
|
32456
|
-
var PLATFORM_VERSION = "0.
|
|
32467
|
+
var PLATFORM_VERSION = "0.12.0";
|
|
32457
32468
|
|
|
32458
32469
|
// ../devkit/src/recipes/angular-distribution/amendments.ts
|
|
32459
32470
|
var DISTRIBUTION_INITIAL_BUDGET = {
|
|
@@ -32712,6 +32723,10 @@ function readme2(d) {
|
|
|
32712
32723
|
"",
|
|
32713
32724
|
"A switch takes the **affordance and the gesture**: turning `splitRight` off removes the toolbar",
|
|
32714
32725
|
"button, the drop edges *and* `mod+\\`, so the capability cannot come back through a second door.",
|
|
32726
|
+
"Two switches are finer, and named for it: `splitRightButton` and `splitDownButton` leave out the",
|
|
32727
|
+
"pane toolbar's split button alone, for a product that offers splitting by dragging a tab to a",
|
|
32728
|
+
"pane's edge. The command and the tab menu's entry are removed by naming them in",
|
|
32729
|
+
"`provideShell({ omit })` instead, so each decision keeps one place.",
|
|
32715
32730
|
"Fields merge group by group, so name only what you turn off. The groups are `content`,",
|
|
32716
32731
|
"`sidebar`, `rail`, `workspaces`, `windows` and `commands`; everything is on by default except",
|
|
32717
32732
|
"`content.escalate`, the unlabelled double-click cycle on a tab.",
|
|
@@ -34193,6 +34208,7 @@ function read(ts, file2, call) {
|
|
|
34193
34208
|
return { ...empty, unreadable: "its id is not a string literal" };
|
|
34194
34209
|
}
|
|
34195
34210
|
const callable = properties.get("callable");
|
|
34211
|
+
const consent = properties.get("agentConsent");
|
|
34196
34212
|
return {
|
|
34197
34213
|
at: at2,
|
|
34198
34214
|
id: id.text,
|
|
@@ -34200,9 +34216,40 @@ function read(ts, file2, call) {
|
|
|
34200
34216
|
described: properties.has("description"),
|
|
34201
34217
|
answers: properties.has("answers"),
|
|
34202
34218
|
returnsValue: returnsValue(ts, properties.get("run")),
|
|
34203
|
-
arguments: readArguments(ts, properties.get("arguments"))
|
|
34219
|
+
arguments: readArguments(ts, properties.get("arguments")),
|
|
34220
|
+
...consentOf(ts, consent)
|
|
34204
34221
|
};
|
|
34205
34222
|
}
|
|
34223
|
+
function consentOf(ts, declared) {
|
|
34224
|
+
const value = unwrapped(ts, declared);
|
|
34225
|
+
return value && ts.isStringLiteral(value) ? { agentConsent: value.text } : {};
|
|
34226
|
+
}
|
|
34227
|
+
function unwrapped(ts, value) {
|
|
34228
|
+
if (!value) {
|
|
34229
|
+
return void 0;
|
|
34230
|
+
}
|
|
34231
|
+
return ts.isAsExpression(value) || ts.isSatisfiesExpression(value) || ts.isParenthesizedExpression(value) ? unwrapped(ts, value.expression) : value;
|
|
34232
|
+
}
|
|
34233
|
+
var STATED = ["allow", "ask", "ask-always", "never"];
|
|
34234
|
+
function consentLine(consent) {
|
|
34235
|
+
switch (consent) {
|
|
34236
|
+
case "allow": {
|
|
34237
|
+
return "says an agent's word is enough to run it.";
|
|
34238
|
+
}
|
|
34239
|
+
case "ask": {
|
|
34240
|
+
return "says the person is asked first; whoever runs it on an agent's behalf does the asking.";
|
|
34241
|
+
}
|
|
34242
|
+
case "ask-always": {
|
|
34243
|
+
return "says the person is asked every time; whoever runs it on an agent's behalf does the asking.";
|
|
34244
|
+
}
|
|
34245
|
+
case "never": {
|
|
34246
|
+
return "says it is not to be run on an agent's word; closing it to other callers is what enforces that.";
|
|
34247
|
+
}
|
|
34248
|
+
default: {
|
|
34249
|
+
return consent === void 0 ? "says nothing about whether an agent's word is enough to run it." : `declares "${consent}" about an agent's word, which is none of ${STATED.join(", ")}, so nothing reads it.`;
|
|
34250
|
+
}
|
|
34251
|
+
}
|
|
34252
|
+
}
|
|
34206
34253
|
function readArguments(ts, value) {
|
|
34207
34254
|
if (!value || !ts.isArrayLiteralExpression(value)) {
|
|
34208
34255
|
return [];
|
|
@@ -34306,6 +34353,12 @@ function judge(registration) {
|
|
|
34306
34353
|
message: `${id}: offered to an agent, with ${count} described argument${count === 1 ? "" : "s"}${registration.answers ? " and a declared answer" : ""}.`
|
|
34307
34354
|
});
|
|
34308
34355
|
}
|
|
34356
|
+
findings.push({
|
|
34357
|
+
level: "info",
|
|
34358
|
+
code: "command.consent",
|
|
34359
|
+
path: at2,
|
|
34360
|
+
message: `${id}: ${consentLine(registration.agentConsent)}`
|
|
34361
|
+
});
|
|
34309
34362
|
return findings;
|
|
34310
34363
|
}
|
|
34311
34364
|
|
|
@@ -34417,7 +34470,7 @@ function inputSchema(descriptor) {
|
|
|
34417
34470
|
function createMcpServer() {
|
|
34418
34471
|
const server = new McpServer({
|
|
34419
34472
|
name: "loomweaver-devkit",
|
|
34420
|
-
version: "0.
|
|
34473
|
+
version: "0.12.0"
|
|
34421
34474
|
});
|
|
34422
34475
|
server.registerTool(
|
|
34423
34476
|
"list_generators",
|
|
@@ -34462,7 +34515,7 @@ function createMcpServer() {
|
|
|
34462
34515
|
server.registerTool(
|
|
34463
34516
|
"validate_commands",
|
|
34464
34517
|
{
|
|
34465
|
-
description: "Say, per command a plugin registers, whether an agent is offered it
|
|
34518
|
+
description: "Say, per command a plugin registers, whether an agent is offered it, what would leave the agent guessing, and what the command states about an agent's word being enough to run it. Input: files = { <path>: <TypeScript source> }. Only a callable command without a description is a warning; the rest is information, and a command that states nothing about an agent's word is reported as stating nothing rather than faulted.",
|
|
34466
34519
|
inputSchema: {
|
|
34467
34520
|
files: external_exports.record(external_exports.string(), external_exports.string())
|
|
34468
34521
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@loomweaver/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "LoomWeaver: open-source plugin platform for Angular workbenches. The MCP server: scaffolding and validation as tools, so an AI assistant in any product repo can build weavers without a checkout.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"loomweaver",
|