@pellux/goodvibes-agent 0.1.10 → 0.1.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/CHANGELOG.md +27 -0
- package/package.json +1 -1
- package/src/cli/agent-knowledge-command.ts +30 -3
- package/src/cli/help.ts +2 -2
- package/src/input/commands/cloudflare-runtime.ts +20 -5
- package/src/input/commands/confirmation.ts +24 -0
- package/src/input/commands/discovery-runtime.ts +16 -7
- package/src/input/commands/eval.ts +27 -14
- package/src/input/commands/experience-runtime.ts +65 -26
- package/src/input/commands/health-runtime.ts +1 -1
- package/src/input/commands/hooks-runtime.ts +50 -19
- package/src/input/commands/incident-runtime.ts +17 -6
- package/src/input/commands/integration-runtime.ts +93 -50
- package/src/input/commands/knowledge.ts +38 -12
- package/src/input/commands/local-auth-runtime.ts +36 -13
- package/src/input/commands/local-provider-runtime.ts +22 -11
- package/src/input/commands/local-runtime.ts +21 -11
- package/src/input/commands/local-setup.ts +35 -16
- package/src/input/commands/managed-runtime.ts +51 -20
- package/src/input/commands/marketplace-runtime.ts +31 -16
- package/src/input/commands/mcp-runtime.ts +65 -34
- package/src/input/commands/memory-product-runtime.ts +72 -35
- package/src/input/commands/memory.ts +9 -9
- package/src/input/commands/notify-runtime.ts +27 -8
- package/src/input/commands/operator-runtime.ts +85 -17
- package/src/input/commands/planning-runtime.ts +14 -2
- package/src/input/commands/platform-access-runtime.ts +88 -45
- package/src/input/commands/platform-services-runtime.ts +51 -25
- package/src/input/commands/product-runtime.ts +54 -27
- package/src/input/commands/profile-sync-runtime.ts +17 -6
- package/src/input/commands/recall-bundle.ts +38 -17
- package/src/input/commands/recall-query.ts +15 -4
- package/src/input/commands/recall-review.ts +9 -3
- package/src/input/commands/remote-runtime-setup.ts +45 -18
- package/src/input/commands/remote-runtime.ts +25 -9
- package/src/input/commands/replay-runtime.ts +9 -2
- package/src/input/commands/services-runtime.ts +21 -10
- package/src/input/commands/session-content.ts +53 -51
- package/src/input/commands/session-workflow.ts +10 -4
- package/src/input/commands/session.ts +1 -1
- package/src/input/commands/settings-sync-runtime.ts +40 -17
- package/src/input/commands/share-runtime.ts +12 -4
- package/src/input/commands/shell-core.ts +3 -3
- package/src/input/commands/subscription-runtime.ts +35 -20
- package/src/input/commands/teleport-runtime.ts +16 -5
- package/src/input/commands/work-plan-runtime.ts +23 -12
- package/src/input/handler-content-actions.ts +11 -62
- package/src/input/handler-interactions.ts +1 -1
- package/src/input/handler-onboarding-cloudflare.ts +48 -117
- package/src/input/keybindings.ts +1 -1
- package/src/input/mcp-workspace.ts +25 -49
- package/src/input/onboarding/onboarding-wizard-cloudflare-step.ts +8 -8
- package/src/input/onboarding/onboarding-wizard-cloudflare.ts +1 -6
- package/src/input/profile-picker-modal.ts +13 -31
- package/src/input/session-picker-modal.ts +4 -30
- package/src/input/settings-modal-subscriptions.ts +3 -3
- package/src/panels/incident-review-panel.ts +1 -1
- package/src/panels/local-auth-panel.ts +4 -4
- package/src/panels/provider-account-snapshot.ts +1 -1
- package/src/panels/provider-health-domains.ts +2 -2
- package/src/panels/settings-sync-panel.ts +2 -2
- package/src/panels/subscription-panel.ts +7 -7
- package/src/renderer/block-actions.ts +1 -1
- package/src/renderer/help-overlay.ts +2 -2
- package/src/renderer/mcp-workspace.ts +12 -12
- package/src/renderer/profile-picker-modal.ts +3 -11
- package/src/renderer/session-picker-modal.ts +2 -10
- package/src/version.ts +1 -1
|
@@ -1,111 +1,148 @@
|
|
|
1
1
|
import type { CommandRegistry } from '../command-registry.ts';
|
|
2
|
+
import { requireYesFlag, stripYesFlag } from './confirmation.ts';
|
|
2
3
|
|
|
3
4
|
export function registerMemoryProductRuntimeCommands(registry: CommandRegistry): void {
|
|
4
5
|
registry.register({
|
|
5
6
|
name: 'memory-sync',
|
|
6
7
|
aliases: ['memsync'],
|
|
7
8
|
description: 'Dedicated front-door for durable memory export/import and bundle exchange',
|
|
8
|
-
usage: '[export <path> [scope] | import <path>]',
|
|
9
|
+
usage: '[export <path> [scope] --yes | import <path> --yes]',
|
|
9
10
|
async handler(args, ctx) {
|
|
10
|
-
const
|
|
11
|
+
const parsed = stripYesFlag(args);
|
|
12
|
+
const commandArgs = [...parsed.rest];
|
|
13
|
+
const sub = (commandArgs[0] ?? '').toLowerCase();
|
|
11
14
|
if (!ctx.executeCommand) {
|
|
12
15
|
ctx.print('Memory sync controls are not available in this runtime.');
|
|
13
16
|
return;
|
|
14
17
|
}
|
|
15
|
-
if (sub === 'export' &&
|
|
16
|
-
|
|
17
|
-
|
|
18
|
+
if (sub === 'export' && commandArgs[1]) {
|
|
19
|
+
if (!parsed.yes) {
|
|
20
|
+
requireYesFlag(ctx, `export durable memory bundle to ${commandArgs[1]}`, '/memory-sync export <path> [scope] --yes');
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const scope = commandArgs[2];
|
|
24
|
+
const recallArgs = ['export', commandArgs[1], ...(scope ? ['--scope', scope] : []), '--yes'];
|
|
18
25
|
await ctx.executeCommand('recall', recallArgs);
|
|
19
26
|
return;
|
|
20
27
|
}
|
|
21
|
-
if (sub === 'import' &&
|
|
22
|
-
|
|
28
|
+
if (sub === 'import' && commandArgs[1]) {
|
|
29
|
+
if (!parsed.yes) {
|
|
30
|
+
requireYesFlag(ctx, `import durable memory bundle from ${commandArgs[1]}`, '/memory-sync import <path> --yes');
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
await ctx.executeCommand('recall', ['import', commandArgs[1], '--yes']);
|
|
23
34
|
return;
|
|
24
35
|
}
|
|
25
|
-
ctx.print('Usage: /memory-sync [export <path> [scope] | import <path>]');
|
|
36
|
+
ctx.print('Usage: /memory-sync [export <path> [scope] --yes | import <path> --yes]');
|
|
26
37
|
},
|
|
27
38
|
});
|
|
28
39
|
|
|
29
40
|
registry.register({
|
|
30
41
|
name: 'handoff',
|
|
31
42
|
description: 'Dedicated front-door for reviewable memory handoff bundles',
|
|
32
|
-
usage: '[export <path> [scope] | inspect <path> | import <path>]',
|
|
43
|
+
usage: '[export <path> [scope] --yes | inspect <path> | import <path> --yes]',
|
|
33
44
|
async handler(args, ctx) {
|
|
34
|
-
const
|
|
45
|
+
const parsed = stripYesFlag(args);
|
|
46
|
+
const commandArgs = [...parsed.rest];
|
|
47
|
+
const sub = (commandArgs[0] ?? '').toLowerCase();
|
|
35
48
|
if (!ctx.executeCommand) {
|
|
36
49
|
ctx.print('Handoff controls are not available in this runtime.');
|
|
37
50
|
return;
|
|
38
51
|
}
|
|
39
|
-
if (sub === 'export' &&
|
|
40
|
-
|
|
41
|
-
|
|
52
|
+
if (sub === 'export' && commandArgs[1]) {
|
|
53
|
+
if (!parsed.yes) {
|
|
54
|
+
requireYesFlag(ctx, `export memory handoff bundle to ${commandArgs[1]}`, '/handoff export <path> [scope] --yes');
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const scope = commandArgs[2];
|
|
58
|
+
await ctx.executeCommand('recall', ['handoff-export', commandArgs[1], ...(scope ? ['--scope', scope] : []), '--yes']);
|
|
42
59
|
return;
|
|
43
60
|
}
|
|
44
|
-
if (sub === 'inspect' &&
|
|
45
|
-
await ctx.executeCommand('recall', ['handoff-inspect',
|
|
61
|
+
if (sub === 'inspect' && commandArgs[1]) {
|
|
62
|
+
await ctx.executeCommand('recall', ['handoff-inspect', commandArgs[1]]);
|
|
46
63
|
return;
|
|
47
64
|
}
|
|
48
|
-
if (sub === 'import' &&
|
|
49
|
-
|
|
65
|
+
if (sub === 'import' && commandArgs[1]) {
|
|
66
|
+
if (!parsed.yes) {
|
|
67
|
+
requireYesFlag(ctx, `import memory handoff bundle from ${commandArgs[1]}`, '/handoff import <path> --yes');
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
await ctx.executeCommand('recall', ['handoff-import', commandArgs[1], '--yes']);
|
|
50
71
|
return;
|
|
51
72
|
}
|
|
52
|
-
ctx.print('Usage: /handoff [export <path> [scope] | inspect <path> | import <path>]');
|
|
73
|
+
ctx.print('Usage: /handoff [export <path> [scope] --yes | inspect <path> | import <path> --yes]');
|
|
53
74
|
},
|
|
54
75
|
});
|
|
55
76
|
|
|
56
77
|
registry.register({
|
|
57
78
|
name: 'session-memory',
|
|
58
79
|
description: 'Dedicated front-door for session-scoped memory capture and review',
|
|
59
|
-
usage: '[queue [limit] | export <path> | add <class> <summary...>]',
|
|
80
|
+
usage: '[queue [limit] | export <path> --yes | add <class> <summary...>]',
|
|
60
81
|
async handler(args, ctx) {
|
|
61
|
-
const
|
|
82
|
+
const parsed = stripYesFlag(args);
|
|
83
|
+
const commandArgs = [...parsed.rest];
|
|
84
|
+
const sub = (commandArgs[0] ?? 'queue').toLowerCase();
|
|
62
85
|
if (!ctx.executeCommand) {
|
|
63
86
|
ctx.print('Session memory controls are not available in this runtime.');
|
|
64
87
|
return;
|
|
65
88
|
}
|
|
66
89
|
if (sub === 'queue') {
|
|
67
|
-
await ctx.executeCommand('recall', ['queue', ...(
|
|
90
|
+
await ctx.executeCommand('recall', ['queue', ...(commandArgs[1] ? [commandArgs[1]] : [])]);
|
|
68
91
|
return;
|
|
69
92
|
}
|
|
70
|
-
if (sub === 'export' &&
|
|
71
|
-
|
|
93
|
+
if (sub === 'export' && commandArgs[1]) {
|
|
94
|
+
if (!parsed.yes) {
|
|
95
|
+
requireYesFlag(ctx, `export session memory bundle to ${commandArgs[1]}`, '/session-memory export <path> --yes');
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
await ctx.executeCommand('recall', ['export', commandArgs[1], '--scope', 'session', '--yes']);
|
|
72
99
|
return;
|
|
73
100
|
}
|
|
74
|
-
if (sub === 'add' &&
|
|
75
|
-
await ctx.executeCommand('recall', ['add',
|
|
101
|
+
if (sub === 'add' && commandArgs.length >= 3) {
|
|
102
|
+
await ctx.executeCommand('recall', ['add', commandArgs[1], ...commandArgs.slice(2), '--scope', 'session']);
|
|
76
103
|
return;
|
|
77
104
|
}
|
|
78
|
-
ctx.print('Usage: /session-memory [queue [limit] | export <path> | add <class> <summary...>]');
|
|
105
|
+
ctx.print('Usage: /session-memory [queue [limit] | export <path> --yes | add <class> <summary...>]');
|
|
79
106
|
},
|
|
80
107
|
});
|
|
81
108
|
|
|
82
109
|
registry.register({
|
|
83
110
|
name: 'team-memory',
|
|
84
111
|
description: 'Dedicated front-door for team/shared memory review and exchange',
|
|
85
|
-
usage: '[queue [limit] | export <path> | import <path> | capture policy]',
|
|
112
|
+
usage: '[queue [limit] | export <path> --yes | import <path> --yes | capture policy]',
|
|
86
113
|
async handler(args, ctx) {
|
|
87
|
-
const
|
|
114
|
+
const parsed = stripYesFlag(args);
|
|
115
|
+
const commandArgs = [...parsed.rest];
|
|
116
|
+
const sub = (commandArgs[0] ?? 'queue').toLowerCase();
|
|
88
117
|
if (!ctx.executeCommand) {
|
|
89
118
|
ctx.print('Team memory controls are not available in this runtime.');
|
|
90
119
|
return;
|
|
91
120
|
}
|
|
92
121
|
if (sub === 'queue') {
|
|
93
|
-
await ctx.executeCommand('recall', ['queue', ...(
|
|
122
|
+
await ctx.executeCommand('recall', ['queue', ...(commandArgs[1] ? [commandArgs[1]] : [])]);
|
|
94
123
|
return;
|
|
95
124
|
}
|
|
96
|
-
if (sub === 'export' &&
|
|
97
|
-
|
|
125
|
+
if (sub === 'export' && commandArgs[1]) {
|
|
126
|
+
if (!parsed.yes) {
|
|
127
|
+
requireYesFlag(ctx, `export team memory handoff bundle to ${commandArgs[1]}`, '/team-memory export <path> --yes');
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
await ctx.executeCommand('recall', ['handoff-export', commandArgs[1], '--scope', 'team', '--yes']);
|
|
98
131
|
return;
|
|
99
132
|
}
|
|
100
|
-
if (sub === 'import' &&
|
|
101
|
-
|
|
133
|
+
if (sub === 'import' && commandArgs[1]) {
|
|
134
|
+
if (!parsed.yes) {
|
|
135
|
+
requireYesFlag(ctx, `import team memory handoff bundle from ${commandArgs[1]}`, '/team-memory import <path> --yes');
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
await ctx.executeCommand('recall', ['handoff-import', commandArgs[1], '--yes']);
|
|
102
139
|
return;
|
|
103
140
|
}
|
|
104
|
-
if (sub === 'capture' &&
|
|
141
|
+
if (sub === 'capture' && commandArgs[1]?.toLowerCase() === 'policy') {
|
|
105
142
|
await ctx.executeCommand('recall', ['capture', 'policy']);
|
|
106
143
|
return;
|
|
107
144
|
}
|
|
108
|
-
ctx.print('Usage: /team-memory [queue [limit] | export <path> | import <path> | capture policy]');
|
|
145
|
+
ctx.print('Usage: /team-memory [queue [limit] | export <path> --yes | import <path> --yes | capture policy]');
|
|
109
146
|
},
|
|
110
147
|
});
|
|
111
148
|
}
|
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
* /recall add <class> <summary> --detail <text> --tags <tag,tag>
|
|
8
8
|
* /recall search [query] — Search memory records
|
|
9
9
|
* /recall search --cls <class> — Filter by class
|
|
10
|
-
* /recall link <fromId> <toId> <relation> — Link two records
|
|
10
|
+
* /recall link <fromId> <toId> <relation> --yes — Link two records
|
|
11
11
|
* /recall get <id> — Show a single record with provenance
|
|
12
12
|
* /recall list [class] — List all records (optionally by class)
|
|
13
|
-
* /recall remove <id>
|
|
13
|
+
* /recall remove <id> --yes — Delete a record
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import type { SlashCommand, CommandContext } from '../command-registry.ts';
|
|
@@ -128,20 +128,20 @@ export const recallCommand: SlashCommand = {
|
|
|
128
128
|
' search [query] [--semantic] [--cls <class>] [--scope <scope>] [--limit <n>] — Full-text or sqlite-vec semantic search',
|
|
129
129
|
' vector [status|doctor|rebuild] — Inspect or rebuild the sqlite-vec memory index',
|
|
130
130
|
' get <id> — Show record with provenance + links',
|
|
131
|
-
' link <fromId> <toId> <relation>
|
|
131
|
+
' link <fromId> <toId> <relation> --yes — Create a directed relation between records',
|
|
132
132
|
' queue [limit] — Show the operator review queue',
|
|
133
133
|
' review <id> <state> [--confidence <n>] [--by <name>] [--reason <text>]',
|
|
134
134
|
' stale <id> [reason...] — Mark a record stale with an operator reason',
|
|
135
135
|
' contradict <id> [reason...] — Mark a record contradicted with an operator reason',
|
|
136
136
|
' explain <task...> [--scope <path> ...] — Show the knowledge records that would be injected for a task',
|
|
137
|
-
' promote <id> <scope>
|
|
138
|
-
' export <path> [--scope <scope>] [--cls <class>] — Export a durable knowledge bundle',
|
|
139
|
-
' import <path>
|
|
140
|
-
' handoff-export <path> [--scope <scope>]
|
|
137
|
+
' promote <id> <scope> --yes — Promote a memory record into session|project|team scope',
|
|
138
|
+
' export <path> [--scope <scope>] [--cls <class>] --yes — Export a durable knowledge bundle',
|
|
139
|
+
' import <path> --yes — Import a durable knowledge bundle',
|
|
140
|
+
' handoff-export <path> [--scope <scope>] --yes — Export a reviewable handoff bundle for team/shared use',
|
|
141
141
|
' handoff-inspect <path> — Inspect a handoff bundle before import',
|
|
142
|
-
' handoff-import <path>
|
|
142
|
+
' handoff-import <path> --yes — Import a handoff bundle into durable memory',
|
|
143
143
|
' list [class] [--scope <scope>] — List all records grouped by class',
|
|
144
|
-
' remove <id>
|
|
144
|
+
' remove <id> --yes — Delete a record',
|
|
145
145
|
].join('\n');
|
|
146
146
|
context.print(usage);
|
|
147
147
|
break;
|
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
import type { CommandRegistry } from '../command-registry.ts';
|
|
2
2
|
import { requireWebhookNotifier } from './runtime-services.ts';
|
|
3
|
+
import { requireYesFlag, stripYesFlag } from './confirmation.ts';
|
|
3
4
|
|
|
4
5
|
export function registerNotifyRuntimeCommands(registry: CommandRegistry): void {
|
|
5
6
|
registry.register({
|
|
6
7
|
name: 'notify',
|
|
7
8
|
aliases: [],
|
|
8
9
|
description: 'Manage webhook notification URLs (ntfy.sh format)',
|
|
9
|
-
usage: 'add <url> | remove <url> | list | clear | test',
|
|
10
|
-
argsHint: 'add|remove|
|
|
10
|
+
usage: 'add <url> --yes | remove <url> --yes | list | clear --yes | test --yes',
|
|
11
|
+
argsHint: 'list|add --yes|remove --yes|test --yes',
|
|
11
12
|
async handler(args, ctx) {
|
|
13
|
+
const parsed = stripYesFlag(args);
|
|
14
|
+
const commandArgs = [...parsed.rest];
|
|
12
15
|
const notifications = ctx.platform.configManager.getCategory('notifications');
|
|
13
16
|
const urls: string[] = Array.isArray(notifications.webhookUrls) ? [...notifications.webhookUrls] : [];
|
|
14
17
|
const notifier = requireWebhookNotifier(ctx);
|
|
15
|
-
const sub =
|
|
18
|
+
const sub = commandArgs[0];
|
|
16
19
|
|
|
17
20
|
if (!sub || sub === 'list') {
|
|
18
21
|
if (urls.length === 0) ctx.print('No webhook URLs configured.\nUse: /notify add <url>');
|
|
@@ -21,9 +24,13 @@ export function registerNotifyRuntimeCommands(registry: CommandRegistry): void {
|
|
|
21
24
|
}
|
|
22
25
|
|
|
23
26
|
if (sub === 'add') {
|
|
24
|
-
const url =
|
|
27
|
+
const url = commandArgs[1];
|
|
25
28
|
if (!url) {
|
|
26
|
-
ctx.print('Usage: /notify add <url
|
|
29
|
+
ctx.print('Usage: /notify add <url> --yes\nExample: /notify add https://ntfy.sh/my-topic --yes');
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (!parsed.yes) {
|
|
33
|
+
requireYesFlag(ctx, `add webhook notification URL ${url}`, '/notify add <url> --yes');
|
|
27
34
|
return;
|
|
28
35
|
}
|
|
29
36
|
try { new URL(url); } catch {
|
|
@@ -42,9 +49,13 @@ export function registerNotifyRuntimeCommands(registry: CommandRegistry): void {
|
|
|
42
49
|
}
|
|
43
50
|
|
|
44
51
|
if (sub === 'remove') {
|
|
45
|
-
const url =
|
|
52
|
+
const url = commandArgs[1];
|
|
46
53
|
if (!url) {
|
|
47
|
-
ctx.print('Usage: /notify remove <url>');
|
|
54
|
+
ctx.print('Usage: /notify remove <url> --yes');
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (!parsed.yes) {
|
|
58
|
+
requireYesFlag(ctx, `remove webhook notification URL ${url}`, '/notify remove <url> --yes');
|
|
48
59
|
return;
|
|
49
60
|
}
|
|
50
61
|
const next = urls.filter((u) => u !== url);
|
|
@@ -59,6 +70,10 @@ export function registerNotifyRuntimeCommands(registry: CommandRegistry): void {
|
|
|
59
70
|
}
|
|
60
71
|
|
|
61
72
|
if (sub === 'clear') {
|
|
73
|
+
if (!parsed.yes) {
|
|
74
|
+
requireYesFlag(ctx, 'clear all webhook notification URLs', '/notify clear --yes');
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
62
77
|
ctx.platform.configManager.mergeCategory('notifications', { webhookUrls: [] });
|
|
63
78
|
notifier.setUrls([]);
|
|
64
79
|
ctx.print('All webhook URLs cleared.');
|
|
@@ -66,6 +81,10 @@ export function registerNotifyRuntimeCommands(registry: CommandRegistry): void {
|
|
|
66
81
|
}
|
|
67
82
|
|
|
68
83
|
if (sub === 'test') {
|
|
84
|
+
if (!parsed.yes) {
|
|
85
|
+
requireYesFlag(ctx, 'send webhook notification test requests', '/notify test --yes');
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
69
88
|
if (urls.length === 0) {
|
|
70
89
|
ctx.print('No webhook URLs configured. Use: /notify add <url>');
|
|
71
90
|
return;
|
|
@@ -77,7 +96,7 @@ export function registerNotifyRuntimeCommands(registry: CommandRegistry): void {
|
|
|
77
96
|
return;
|
|
78
97
|
}
|
|
79
98
|
|
|
80
|
-
ctx.print('Usage: /notify add <url> | remove <url> | list | clear | test');
|
|
99
|
+
ctx.print('Usage: /notify add <url> --yes | remove <url> --yes | list | clear --yes | test --yes');
|
|
81
100
|
},
|
|
82
101
|
});
|
|
83
102
|
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import type { CommandRegistry } from '../command-registry.ts';
|
|
2
|
+
import type { ProfileData } from '@pellux/goodvibes-sdk/platform/profiles';
|
|
2
3
|
import { ToolContractVerifier } from '@/runtime/index.ts';
|
|
3
4
|
import type { ReplaySnapshotInput } from '@/runtime/index.ts';
|
|
4
5
|
import { logger } from '@pellux/goodvibes-sdk/platform/utils';
|
|
5
6
|
import { registerOperatorPanelCommand } from './operator-panel-runtime.ts';
|
|
6
7
|
import { requireProfileManager, requireReplayEngine } from './runtime-services.ts';
|
|
7
8
|
import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
|
|
9
|
+
import { requireYesFlag, stripYesFlag } from './confirmation.ts';
|
|
8
10
|
|
|
9
11
|
function printOpsMutationBlocked(print: (text: string) => void, target: string): void {
|
|
10
12
|
print([
|
|
@@ -76,15 +78,71 @@ export function registerOperatorRuntimeCommands(registry: CommandRegistry): void
|
|
|
76
78
|
registry.register({
|
|
77
79
|
name: 'profiles',
|
|
78
80
|
aliases: ['profile'],
|
|
79
|
-
description: 'Browse and
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
81
|
+
description: 'Browse, save, and delete config profiles',
|
|
82
|
+
usage: '[list|open|save <name> --yes|delete <name> --yes]',
|
|
83
|
+
argsHint: '[list|open|save --yes|delete --yes]',
|
|
84
|
+
handler(args, ctx) {
|
|
85
|
+
const parsed = stripYesFlag(args);
|
|
86
|
+
const sub = parsed.rest[0] ?? 'open';
|
|
87
|
+
const profileManager = requireProfileManager(ctx);
|
|
88
|
+
if (sub === 'open') {
|
|
89
|
+
if (ctx.openProfilePicker) {
|
|
90
|
+
ctx.openProfilePicker();
|
|
91
|
+
} else {
|
|
92
|
+
const profiles = profileManager.list();
|
|
93
|
+
if (profiles.length === 0) ctx.print('No profiles saved. Use /profiles save <name> --yes to save the current settings as a profile.');
|
|
94
|
+
else ctx.print(['Saved profiles:', ...profiles.map(p => ` ${p.name}`)].join('\n'));
|
|
95
|
+
}
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (sub === 'list') {
|
|
99
|
+
const profiles = profileManager.list();
|
|
100
|
+
if (profiles.length === 0) ctx.print('No profiles saved. Use /profiles save <name> --yes to save the current settings as a profile.');
|
|
86
101
|
else ctx.print(['Saved profiles:', ...profiles.map(p => ` ${p.name}`)].join('\n'));
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
if (sub === 'save') {
|
|
105
|
+
const name = parsed.rest[1];
|
|
106
|
+
if (!name) {
|
|
107
|
+
ctx.print('Usage: /profiles save <name> --yes');
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
if (!parsed.yes) {
|
|
111
|
+
requireYesFlag(ctx, `save config profile ${name}`, '/profiles save <name> --yes');
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const all = ctx.platform.configManager.getAll();
|
|
115
|
+
const data: ProfileData = {
|
|
116
|
+
display: { ...all.display },
|
|
117
|
+
provider: {
|
|
118
|
+
model: all.provider.model,
|
|
119
|
+
reasoningEffort: all.provider.reasoningEffort,
|
|
120
|
+
},
|
|
121
|
+
behavior: { ...all.behavior },
|
|
122
|
+
};
|
|
123
|
+
profileManager.save(name, data);
|
|
124
|
+
ctx.print(`Profile saved: ${name}`);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
if (sub === 'delete' || sub === 'remove') {
|
|
128
|
+
const name = parsed.rest[1];
|
|
129
|
+
if (!name) {
|
|
130
|
+
ctx.print('Usage: /profiles delete <name> --yes');
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
if (!parsed.yes) {
|
|
134
|
+
requireYesFlag(ctx, `delete config profile ${name}`, '/profiles delete <name> --yes');
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
const deleted = profileManager.delete(name);
|
|
138
|
+
ctx.print(deleted ? `Profile deleted: ${name}` : `Profile not found: ${name}`);
|
|
139
|
+
return;
|
|
87
140
|
}
|
|
141
|
+
if (args.length === 0 && ctx.openProfilePicker) {
|
|
142
|
+
ctx.openProfilePicker();
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
ctx.print('Usage: /profiles [list|open|save <name> --yes|delete <name> --yes]');
|
|
88
146
|
},
|
|
89
147
|
});
|
|
90
148
|
|
|
@@ -103,7 +161,7 @@ export function registerOperatorRuntimeCommands(registry: CommandRegistry): void
|
|
|
103
161
|
name: 'mode',
|
|
104
162
|
aliases: ['hitl'],
|
|
105
163
|
description: 'Manage HITL UX notification mode (quiet/balanced/operator)',
|
|
106
|
-
usage: '[quiet|balanced|operator|show|set-domain <domain> <verbosity>]',
|
|
164
|
+
usage: '[quiet|balanced|operator --yes|show|set-domain <domain> <verbosity> --yes]',
|
|
107
165
|
argsHint: '[preset|show|set-domain]',
|
|
108
166
|
handler(args, ctx) {
|
|
109
167
|
const mgr = ctx.ops.modeManager;
|
|
@@ -111,9 +169,15 @@ export function registerOperatorRuntimeCommands(registry: CommandRegistry): void
|
|
|
111
169
|
ctx.print('Interaction mode manager is not available in this runtime.');
|
|
112
170
|
return;
|
|
113
171
|
}
|
|
114
|
-
const
|
|
172
|
+
const parsed = stripYesFlag(args);
|
|
173
|
+
const commandArgs = [...parsed.rest];
|
|
174
|
+
const sub = commandArgs[0] ?? 'show';
|
|
115
175
|
|
|
116
176
|
if (sub === 'quiet' || sub === 'balanced' || sub === 'operator') {
|
|
177
|
+
if (!parsed.yes) {
|
|
178
|
+
requireYesFlag(ctx, `set HITL mode to ${sub}`, '/mode <quiet|balanced|operator> --yes');
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
117
181
|
const newMode = sub as 'quiet' | 'balanced' | 'operator';
|
|
118
182
|
mgr.setHITLMode(newMode);
|
|
119
183
|
try {
|
|
@@ -156,29 +220,33 @@ export function registerOperatorRuntimeCommands(registry: CommandRegistry): void
|
|
|
156
220
|
}
|
|
157
221
|
|
|
158
222
|
if (sub === 'set-domain') {
|
|
159
|
-
const domain =
|
|
160
|
-
const verbosity =
|
|
223
|
+
const domain = commandArgs[1];
|
|
224
|
+
const verbosity = commandArgs[2];
|
|
161
225
|
if (!domain || !verbosity) {
|
|
162
|
-
ctx.print('Usage: /mode set-domain <domain> <minimal|normal|verbose>');
|
|
226
|
+
ctx.print('Usage: /mode set-domain <domain> <minimal|normal|verbose> --yes');
|
|
163
227
|
return;
|
|
164
228
|
}
|
|
165
229
|
if (verbosity !== 'minimal' && verbosity !== 'normal' && verbosity !== 'verbose') {
|
|
166
230
|
ctx.print(`Invalid verbosity "${verbosity}". Valid values: minimal, normal, verbose`);
|
|
167
231
|
return;
|
|
168
232
|
}
|
|
233
|
+
if (!parsed.yes) {
|
|
234
|
+
requireYesFlag(ctx, `set HITL verbosity for ${domain}`, '/mode set-domain <domain> <minimal|normal|verbose> --yes');
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
169
237
|
mgr.setDomainVerbosity(domain, verbosity as 'minimal' | 'normal' | 'verbose');
|
|
170
238
|
ctx.print(`Domain "${domain}" verbosity set to: ${verbosity}`);
|
|
171
239
|
return;
|
|
172
240
|
}
|
|
173
241
|
|
|
174
242
|
ctx.print(
|
|
175
|
-
'Usage: /mode [quiet|balanced|operator|show|set-domain <domain> <verbosity>]\n'
|
|
243
|
+
'Usage: /mode [quiet|balanced|operator --yes|show|set-domain <domain> <verbosity> --yes]\n'
|
|
176
244
|
+ ' /mode — show current mode and settings\n'
|
|
177
245
|
+ ' /mode show — show current mode and settings\n'
|
|
178
|
-
+ ' /mode quiet
|
|
179
|
-
+ ' /mode balanced
|
|
180
|
-
+ ' /mode operator
|
|
181
|
-
+ ' /mode set-domain <d> <v>
|
|
246
|
+
+ ' /mode quiet --yes — suppress all non-critical notifications\n'
|
|
247
|
+
+ ' /mode balanced --yes — surface warnings, batch info noise (default)\n'
|
|
248
|
+
+ ' /mode operator --yes — full verbosity, no suppression\n'
|
|
249
|
+
+ ' /mode set-domain <d> <v> --yes — per-domain verbosity override (minimal|normal|verbose)'
|
|
182
250
|
);
|
|
183
251
|
},
|
|
184
252
|
});
|
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
} from '@pellux/goodvibes-sdk/platform/knowledge';
|
|
7
7
|
import type { CommandRegistry } from '../command-registry.ts';
|
|
8
8
|
import { requirePlanManager, requireSessionLineageTracker } from './runtime-services.ts';
|
|
9
|
+
import { requireYesFlag, stripYesFlag } from './confirmation.ts';
|
|
9
10
|
|
|
10
11
|
function recordNextQuestion(
|
|
11
12
|
state: Partial<ProjectPlanningState>,
|
|
@@ -51,15 +52,21 @@ export function registerPlanningRuntimeCommands(registry: CommandRegistry): void
|
|
|
51
52
|
registry.register({
|
|
52
53
|
name: 'plan',
|
|
53
54
|
description: 'Inspect or seed Agent workspace planning state',
|
|
54
|
-
usage: '[panel | approve | list | show <id> | mode | explain | override <strategy> | status | clear | <planning goal>]',
|
|
55
|
+
usage: '[panel | approve --yes | list | show <id> | mode | explain | override <strategy> --yes | status | clear --yes | <planning goal>]',
|
|
55
56
|
argsHint: '[panel|approve|status|<goal>]',
|
|
56
57
|
async handler(args, ctx) {
|
|
57
58
|
const planManager = requirePlanManager(ctx);
|
|
58
59
|
const sessionLineageTracker = requireSessionLineageTracker(ctx);
|
|
59
60
|
const plannerSubs = ['mode', 'explain', 'override', 'status', 'clear'];
|
|
60
61
|
if (args.length > 0 && plannerSubs.includes(args[0].toLowerCase())) {
|
|
62
|
+
const parsed = stripYesFlag(args);
|
|
63
|
+
const subcommand = parsed.rest[0]?.toLowerCase() ?? '';
|
|
64
|
+
if ((subcommand === 'override' || subcommand === 'clear') && !parsed.yes) {
|
|
65
|
+
requireYesFlag(ctx, `${subcommand} planner runtime state`, `/plan ${subcommand}${subcommand === 'override' ? ' <strategy>' : ''} --yes`);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
61
68
|
const result = ctx.ops.planRuntime
|
|
62
|
-
? ctx.ops.planRuntime(args[0],
|
|
69
|
+
? ctx.ops.planRuntime(parsed.rest[0] ?? args[0], parsed.rest.slice(1))
|
|
63
70
|
: { ok: false, output: 'Plan runtime bridge is not available in this runtime.' };
|
|
64
71
|
ctx.print(result.output);
|
|
65
72
|
return;
|
|
@@ -109,6 +116,11 @@ export function registerPlanningRuntimeCommands(registry: CommandRegistry): void
|
|
|
109
116
|
}
|
|
110
117
|
|
|
111
118
|
if (args[0] === 'approve') {
|
|
119
|
+
const parsed = stripYesFlag(args);
|
|
120
|
+
if (!parsed.yes) {
|
|
121
|
+
requireYesFlag(ctx, 'approve project planning state for execution', '/plan approve --yes');
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
112
124
|
if (!projectPlanningService || !projectId) {
|
|
113
125
|
ctx.print('Project planning service is not available in this runtime.');
|
|
114
126
|
return;
|