@loomweaver/cli 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 +64 -11
- package/package.json +1 -1
package/dist/main.mjs
CHANGED
|
@@ -837,7 +837,7 @@ function pause(): Promise<void> {
|
|
|
837
837
|
}
|
|
838
838
|
|
|
839
839
|
// ../devkit/src/recipes/angular-weaver/agent-files.ts
|
|
840
|
-
var AG_UI_ADAPTER_VERSION = "0.
|
|
840
|
+
var AG_UI_ADAPTER_VERSION = "0.12.0";
|
|
841
841
|
var AG_UI_PROTOCOL_VERSION = "0.0.x";
|
|
842
842
|
function connectionFile(w) {
|
|
843
843
|
return `import { signal } from '@angular/core';
|
|
@@ -849,11 +849,6 @@ import {
|
|
|
849
849
|
} from '@loomweaver/ag-ui';
|
|
850
850
|
import type { PluginContext } from '@loomweaver/plugin-sdk';
|
|
851
851
|
|
|
852
|
-
// Commands an agent may not run on its own word. Each one asks the person at the keyboard first, and
|
|
853
|
-
// declining stops it: the workbench never sees the call. This weaver's own command is listed as an
|
|
854
|
-
// example \u2014 replace it with the ones that actually cost something.
|
|
855
|
-
const CONSEQUENTIAL = new Set(['${w.id}.hello']);
|
|
856
|
-
|
|
857
852
|
// A factory, not a module-level connection: everything a run needs lives in the closure, so a second
|
|
858
853
|
// one never shares state with the first.
|
|
859
854
|
export function ${w.propertyName}Connection(ctx: PluginContext): CommandTools {
|
|
@@ -864,11 +859,21 @@ export function ${w.propertyName}Connection(ctx: PluginContext): CommandTools {
|
|
|
864
859
|
// deactivate(), so the panel renders an honest empty state either side of that.
|
|
865
860
|
export const ${w.propertyName}Agent = signal<CommandTools | null>(null);
|
|
866
861
|
|
|
862
|
+
// What an agent's word is enough for is the command's own statement, declared where the command is
|
|
863
|
+
// registered and read off the call here. No list of ids lives beside the commands: a list drifts from
|
|
864
|
+
// what it describes, and it cannot speak for a command another plugin registered. Acting on the
|
|
865
|
+
// statement is this weaver's half: the workbench states it and enforces nothing.
|
|
867
866
|
async function decide(
|
|
868
867
|
ctx: PluginContext,
|
|
869
868
|
call: PendingToolCall,
|
|
870
869
|
): Promise<ToolDecision> {
|
|
871
|
-
if (
|
|
870
|
+
if (call.agentConsent === 'never') {
|
|
871
|
+
return {
|
|
872
|
+
decision: 'decline',
|
|
873
|
+
reason: 'an agent may not run this one on its own word.',
|
|
874
|
+
};
|
|
875
|
+
}
|
|
876
|
+
if (call.agentConsent !== 'ask' && call.agentConsent !== 'ask-always') {
|
|
872
877
|
return { decision: 'run' };
|
|
873
878
|
}
|
|
874
879
|
const yes = await ctx.ui.confirm({
|
|
@@ -899,7 +904,8 @@ interface Asked {
|
|
|
899
904
|
function contextThat(confirms: boolean, ran: Asked[]): PluginContext {
|
|
900
905
|
return {
|
|
901
906
|
invocableCommands: () => [
|
|
902
|
-
|
|
907
|
+
// agentConsent travels with the command, which is what the connection reads off the call.
|
|
908
|
+
{ id: '${w.id}.hello', title: '${w.name} action', description: 'Shows a short message.', agentConsent: 'ask' },
|
|
903
909
|
],
|
|
904
910
|
invokeCommand: (id: string, args?: CommandArguments) => {
|
|
905
911
|
ran.push({ id, args });
|
|
@@ -1185,6 +1191,11 @@ function commandBlock(w) {
|
|
|
1185
1191
|
` answers: '${w.id}.actionAnswers',`,
|
|
1186
1192
|
` shortcut: '${w.features.shortcut}',`,
|
|
1187
1193
|
" callable: true,",
|
|
1194
|
+
...w.features.agent ? [
|
|
1195
|
+
" // What an agent's word is enough for. The platform states it and enforces nothing:",
|
|
1196
|
+
" // the asking is the connection's half, which reads this off the call.",
|
|
1197
|
+
" agentConsent: 'ask',"
|
|
1198
|
+
] : [],
|
|
1188
1199
|
" run: (_context, args) => {",
|
|
1189
1200
|
" const tone = toneOf(args?.['tone']);",
|
|
1190
1201
|
` ctx.ui.toast({ message: '${w.id}.action', kind: tone });`,
|
|
@@ -1832,7 +1843,7 @@ var framePlugin = {
|
|
|
1832
1843
|
};
|
|
1833
1844
|
|
|
1834
1845
|
// ../devkit/src/recipes/platform-version.ts
|
|
1835
|
-
var PLATFORM_VERSION = "0.
|
|
1846
|
+
var PLATFORM_VERSION = "0.12.0";
|
|
1836
1847
|
|
|
1837
1848
|
// ../devkit/src/recipes/angular-distribution/amendments.ts
|
|
1838
1849
|
var DISTRIBUTION_INITIAL_BUDGET = {
|
|
@@ -2091,6 +2102,10 @@ function readme2(d) {
|
|
|
2091
2102
|
"",
|
|
2092
2103
|
"A switch takes the **affordance and the gesture**: turning `splitRight` off removes the toolbar",
|
|
2093
2104
|
"button, the drop edges *and* `mod+\\`, so the capability cannot come back through a second door.",
|
|
2105
|
+
"Two switches are finer, and named for it: `splitRightButton` and `splitDownButton` leave out the",
|
|
2106
|
+
"pane toolbar's split button alone, for a product that offers splitting by dragging a tab to a",
|
|
2107
|
+
"pane's edge. The command and the tab menu's entry are removed by naming them in",
|
|
2108
|
+
"`provideShell({ omit })` instead, so each decision keeps one place.",
|
|
2094
2109
|
"Fields merge group by group, so name only what you turn off. The groups are `content`,",
|
|
2095
2110
|
"`sidebar`, `rail`, `workspaces`, `windows` and `commands`; everything is on by default except",
|
|
2096
2111
|
"`content.escalate`, the unlabelled double-click cycle on a tab.",
|
|
@@ -3586,6 +3601,7 @@ function read(ts, file, call) {
|
|
|
3586
3601
|
return { ...empty, unreadable: "its id is not a string literal" };
|
|
3587
3602
|
}
|
|
3588
3603
|
const callable = properties.get("callable");
|
|
3604
|
+
const consent = properties.get("agentConsent");
|
|
3589
3605
|
return {
|
|
3590
3606
|
at: at2,
|
|
3591
3607
|
id: id.text,
|
|
@@ -3593,9 +3609,40 @@ function read(ts, file, call) {
|
|
|
3593
3609
|
described: properties.has("description"),
|
|
3594
3610
|
answers: properties.has("answers"),
|
|
3595
3611
|
returnsValue: returnsValue(ts, properties.get("run")),
|
|
3596
|
-
arguments: readArguments(ts, properties.get("arguments"))
|
|
3612
|
+
arguments: readArguments(ts, properties.get("arguments")),
|
|
3613
|
+
...consentOf(ts, consent)
|
|
3597
3614
|
};
|
|
3598
3615
|
}
|
|
3616
|
+
function consentOf(ts, declared) {
|
|
3617
|
+
const value = unwrapped(ts, declared);
|
|
3618
|
+
return value && ts.isStringLiteral(value) ? { agentConsent: value.text } : {};
|
|
3619
|
+
}
|
|
3620
|
+
function unwrapped(ts, value) {
|
|
3621
|
+
if (!value) {
|
|
3622
|
+
return void 0;
|
|
3623
|
+
}
|
|
3624
|
+
return ts.isAsExpression(value) || ts.isSatisfiesExpression(value) || ts.isParenthesizedExpression(value) ? unwrapped(ts, value.expression) : value;
|
|
3625
|
+
}
|
|
3626
|
+
var STATED = ["allow", "ask", "ask-always", "never"];
|
|
3627
|
+
function consentLine(consent) {
|
|
3628
|
+
switch (consent) {
|
|
3629
|
+
case "allow": {
|
|
3630
|
+
return "says an agent's word is enough to run it.";
|
|
3631
|
+
}
|
|
3632
|
+
case "ask": {
|
|
3633
|
+
return "says the person is asked first; whoever runs it on an agent's behalf does the asking.";
|
|
3634
|
+
}
|
|
3635
|
+
case "ask-always": {
|
|
3636
|
+
return "says the person is asked every time; whoever runs it on an agent's behalf does the asking.";
|
|
3637
|
+
}
|
|
3638
|
+
case "never": {
|
|
3639
|
+
return "says it is not to be run on an agent's word; closing it to other callers is what enforces that.";
|
|
3640
|
+
}
|
|
3641
|
+
default: {
|
|
3642
|
+
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.`;
|
|
3643
|
+
}
|
|
3644
|
+
}
|
|
3645
|
+
}
|
|
3599
3646
|
function readArguments(ts, value) {
|
|
3600
3647
|
if (!value || !ts.isArrayLiteralExpression(value)) {
|
|
3601
3648
|
return [];
|
|
@@ -3699,6 +3746,12 @@ function judge(registration) {
|
|
|
3699
3746
|
message: `${id}: offered to an agent, with ${count} described argument${count === 1 ? "" : "s"}${registration.answers ? " and a declared answer" : ""}.`
|
|
3700
3747
|
});
|
|
3701
3748
|
}
|
|
3749
|
+
findings.push({
|
|
3750
|
+
level: "info",
|
|
3751
|
+
code: "command.consent",
|
|
3752
|
+
path: at2,
|
|
3753
|
+
message: `${id}: ${consentLine(registration.agentConsent)}`
|
|
3754
|
+
});
|
|
3702
3755
|
return findings;
|
|
3703
3756
|
}
|
|
3704
3757
|
|
|
@@ -4733,7 +4786,7 @@ function replaceSymlinkEntry(absolute) {
|
|
|
4733
4786
|
}
|
|
4734
4787
|
|
|
4735
4788
|
// src/lib/run.ts
|
|
4736
|
-
var VERSION = "0.
|
|
4789
|
+
var VERSION = "0.12.0";
|
|
4737
4790
|
function help() {
|
|
4738
4791
|
const commands = SCAFFOLDS.map((s) => ` ${s.name.padEnd(16)}${s.summary}`);
|
|
4739
4792
|
return [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@loomweaver/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "LoomWeaver: open-source plugin platform for Angular workbenches. The scaffolding CLI: generates weavers, distributions and integrations into any project, with no Nx workspace and no checkout required.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"loomweaver",
|