@pellux/goodvibes-agent 0.1.70 → 0.1.72

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.
Files changed (78) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +3 -3
  3. package/docs/README.md +2 -2
  4. package/docs/getting-started.md +1 -1
  5. package/docs/runtime-connection.md +37 -0
  6. package/package.json +43 -2
  7. package/src/agent/skill-discovery.ts +119 -0
  8. package/src/cli/config-overrides.ts +1 -5
  9. package/src/cli/entrypoint.ts +0 -6
  10. package/src/cli/help.ts +0 -43
  11. package/src/cli/index.ts +0 -2
  12. package/src/cli/management-commands.ts +1 -109
  13. package/src/cli/management.ts +1 -32
  14. package/src/cli/package-verification.ts +12 -4
  15. package/src/cli/parser.ts +0 -16
  16. package/src/cli/status.ts +1 -1
  17. package/src/cli/types.ts +0 -8
  18. package/src/input/commands/delegation-runtime.ts +0 -8
  19. package/src/input/commands/experience-runtime.ts +0 -177
  20. package/src/input/commands/guidance-runtime.ts +0 -69
  21. package/src/input/commands/local-runtime.ts +1 -57
  22. package/src/input/commands/local-setup-review.ts +1 -1
  23. package/src/input/commands/operator-runtime.ts +1 -145
  24. package/src/input/commands/platform-access-runtime.ts +2 -195
  25. package/src/input/commands/product-runtime.ts +0 -116
  26. package/src/input/commands/security-runtime.ts +88 -0
  27. package/src/input/commands/session-content.ts +0 -97
  28. package/src/input/commands/shell-core.ts +0 -13
  29. package/src/input/commands.ts +2 -95
  30. package/src/panels/builtin/operations.ts +3 -184
  31. package/src/panels/confirm-state.ts +1 -1
  32. package/src/panels/index.ts +0 -11
  33. package/src/version.ts +1 -1
  34. package/docs/deployment-and-services.md +0 -52
  35. package/src/cli/service-command.ts +0 -26
  36. package/src/cli/surface-command.ts +0 -247
  37. package/src/input/commands/branch-runtime.ts +0 -72
  38. package/src/input/commands/control-room-runtime.ts +0 -234
  39. package/src/input/commands/discovery-runtime.ts +0 -61
  40. package/src/input/commands/hooks-runtime.ts +0 -207
  41. package/src/input/commands/incident-runtime.ts +0 -106
  42. package/src/input/commands/integration-runtime.ts +0 -437
  43. package/src/input/commands/local-setup.ts +0 -288
  44. package/src/input/commands/managed-runtime.ts +0 -240
  45. package/src/input/commands/marketplace-runtime.ts +0 -305
  46. package/src/input/commands/memory-product-runtime.ts +0 -148
  47. package/src/input/commands/operator-panel-runtime.ts +0 -146
  48. package/src/input/commands/platform-services-runtime.ts +0 -271
  49. package/src/input/commands/profile-sync-runtime.ts +0 -110
  50. package/src/input/commands/provider.ts +0 -363
  51. package/src/input/commands/remote-runtime-pool.ts +0 -89
  52. package/src/input/commands/remote-runtime-setup.ts +0 -226
  53. package/src/input/commands/remote-runtime.ts +0 -432
  54. package/src/input/commands/replay-runtime.ts +0 -25
  55. package/src/input/commands/services-runtime.ts +0 -220
  56. package/src/input/commands/settings-sync-runtime.ts +0 -197
  57. package/src/input/commands/share-runtime.ts +0 -127
  58. package/src/input/commands/skills-runtime.ts +0 -226
  59. package/src/input/commands/teleport-runtime.ts +0 -68
  60. package/src/panels/cockpit-panel.ts +0 -183
  61. package/src/panels/communication-panel.ts +0 -153
  62. package/src/panels/control-plane-panel.ts +0 -211
  63. package/src/panels/forensics-panel.ts +0 -364
  64. package/src/panels/hooks-panel.ts +0 -239
  65. package/src/panels/incident-review-panel.ts +0 -197
  66. package/src/panels/marketplace-panel.ts +0 -212
  67. package/src/panels/ops-control-panel.ts +0 -150
  68. package/src/panels/ops-strategy-panel.ts +0 -235
  69. package/src/panels/orchestration-panel.ts +0 -272
  70. package/src/panels/plugins-panel.ts +0 -178
  71. package/src/panels/remote-panel.ts +0 -449
  72. package/src/panels/routes-panel.ts +0 -178
  73. package/src/panels/services-panel.ts +0 -231
  74. package/src/panels/settings-sync-panel.ts +0 -120
  75. package/src/panels/skills-panel.ts +0 -431
  76. package/src/panels/watchers-panel.ts +0 -193
  77. package/src/verification/live-verifier.ts +0 -588
  78. package/src/verification/verification-ledger.ts +0 -239
@@ -1,305 +0,0 @@
1
- import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
- import { dirname, resolve } from 'node:path';
3
- import type { CommandRegistry } from '../command-registry.ts';
4
- import {
5
- exportEcosystemCatalogBundle,
6
- importEcosystemCatalogBundle,
7
- inspectEcosystemCatalogBundle,
8
- inspectInstalledEcosystemEntry,
9
- installEcosystemCatalogEntry,
10
- listEcosystemInstallBackups,
11
- listInstalledEcosystemEntries,
12
- loadEcosystemCatalog,
13
- rollbackInstalledEcosystemEntry,
14
- reviewEcosystemCatalogEntry,
15
- searchEcosystemCatalog,
16
- uninstallEcosystemCatalogEntry,
17
- updateInstalledEcosystemEntry,
18
- type EcosystemCatalogBundle,
19
- type EcosystemCatalogEntry,
20
- type EcosystemEntryKind,
21
- } from '@/runtime/index.ts';
22
- import { openCommandPanel, requireEcosystemCatalogPaths, requireReadModels, requireShellPaths } from './runtime-services.ts';
23
- import { requireYesFlag, stripYesFlag } from './confirmation.ts';
24
-
25
- function resolveMarketplaceEntry(
26
- kind: EcosystemEntryKind,
27
- entryId: string,
28
- options: Parameters<typeof loadEcosystemCatalog>[1],
29
- ): EcosystemCatalogEntry | null {
30
- return loadEcosystemCatalog(kind, options).find((candidate) => candidate.id === entryId) ?? null;
31
- }
32
-
33
- function formatCompatibility(review: ReturnType<typeof reviewEcosystemCatalogEntry>): string {
34
- if (review.compatibility.reasons.length === 0) return 'compatible with current runtime';
35
- return review.compatibility.reasons.join('; ');
36
- }
37
-
38
- export function registerMarketplaceRuntimeCommands(registry: CommandRegistry): void {
39
- registry.register({
40
- name: 'marketplace',
41
- aliases: ['catalog'],
42
- description: 'Browse the unified plugin and skill marketplace',
43
- usage: '[open|overview|recommend|browse [query]|review <plugin|skill|hook-pack|policy-pack> <id>|provenance <plugin|skill|hook-pack|policy-pack> <id>|install-hint <plugin|skill|hook-pack|policy-pack> <id>|install <plugin|skill|hook-pack|policy-pack> <id> [project|user] --yes|update <plugin|skill|hook-pack|policy-pack> <id> [project|user] --yes|rollback <plugin|skill|hook-pack|policy-pack> <id> [project|user] [backupId] --yes|history <plugin|skill|hook-pack|policy-pack> <id> [project|user]|uninstall <plugin|skill|hook-pack|policy-pack> <id> [project|user] --yes|receipt <plugin|skill|hook-pack|policy-pack> <id> [project|user]|bundle export <path> [project|user] --yes|bundle inspect <path>|bundle import <path> [project|user] --yes|installed]',
44
- handler(args, ctx) {
45
- const parsed = stripYesFlag(args);
46
- const commandArgs = [...parsed.rest];
47
- const shellPaths = requireShellPaths(ctx);
48
- const ecosystemPaths = requireEcosystemCatalogPaths(ctx);
49
- const sub = commandArgs[0] ?? 'open';
50
- if (sub === 'open' || sub === 'panel') {
51
- openCommandPanel(ctx, 'marketplace');
52
- return;
53
- }
54
- if (sub === 'overview') {
55
- const pluginCatalog = loadEcosystemCatalog('plugin', ecosystemPaths);
56
- const skillCatalog = loadEcosystemCatalog('skill', ecosystemPaths);
57
- const hookPackCatalog = loadEcosystemCatalog('hook-pack', ecosystemPaths);
58
- const policyPackCatalog = loadEcosystemCatalog('policy-pack', ecosystemPaths);
59
- const installedPlugins = listInstalledEcosystemEntries('plugin', ecosystemPaths);
60
- const installedSkills = listInstalledEcosystemEntries('skill', ecosystemPaths);
61
- const installedHookPacks = listInstalledEcosystemEntries('hook-pack', ecosystemPaths);
62
- const installedPolicyPacks = listInstalledEcosystemEntries('policy-pack', ecosystemPaths);
63
- ctx.print([
64
- 'Marketplace Overview',
65
- ` curated plugins: ${pluginCatalog.length}`,
66
- ` curated skills: ${skillCatalog.length}`,
67
- ` curated hook packs: ${hookPackCatalog.length}`,
68
- ` curated policy packs: ${policyPackCatalog.length}`,
69
- ` installed plugins: ${installedPlugins.length}`,
70
- ` installed skills: ${installedSkills.length}`,
71
- ` installed hook packs: ${installedHookPacks.length}`,
72
- ` installed policy packs: ${installedPolicyPacks.length}`,
73
- ].join('\n'));
74
- return;
75
- }
76
- if (sub === 'browse') {
77
- const query = commandArgs.slice(1).join(' ');
78
- const pluginEntries = query ? searchEcosystemCatalog('plugin', query, ecosystemPaths) : loadEcosystemCatalog('plugin', ecosystemPaths);
79
- const skillEntries = query ? searchEcosystemCatalog('skill', query, ecosystemPaths) : loadEcosystemCatalog('skill', ecosystemPaths);
80
- const hookPackEntries = query ? searchEcosystemCatalog('hook-pack', query, ecosystemPaths) : loadEcosystemCatalog('hook-pack', ecosystemPaths);
81
- const policyPackEntries = query ? searchEcosystemCatalog('policy-pack', query, ecosystemPaths) : loadEcosystemCatalog('policy-pack', ecosystemPaths);
82
- ctx.print([
83
- `Marketplace Browse${query ? ` (${query})` : ''}`,
84
- ` plugins: ${pluginEntries.length}`,
85
- ...pluginEntries.map((entry) => ` plugin ${entry.id} ${entry.name} ${entry.summary}`),
86
- ` skills: ${skillEntries.length}`,
87
- ...skillEntries.map((entry) => ` skill ${entry.id} ${entry.name} ${entry.summary}`),
88
- ` hook packs: ${hookPackEntries.length}`,
89
- ...hookPackEntries.map((entry) => ` hook-pack ${entry.id} ${entry.name} ${entry.summary}`),
90
- ` policy packs: ${policyPackEntries.length}`,
91
- ...policyPackEntries.map((entry) => ` policy-pack ${entry.id} ${entry.name} ${entry.summary}`),
92
- ].join('\n'));
93
- return;
94
- }
95
- if (sub === 'recommend') {
96
- const recommendations = requireReadModels(ctx).marketplace.getSnapshot().recommendations;
97
- ctx.print(recommendations.length > 0
98
- ? [
99
- 'Marketplace Recommendations',
100
- ...recommendations.map((recommendation) => ` ${recommendation.kind} ${recommendation.entry.id} ${recommendation.title}`),
101
- ...recommendations.map((recommendation) => ` ${recommendation.reason} next=${recommendation.command}`),
102
- ].join('\n')
103
- : 'Marketplace Recommendations\n No contextual recommendations right now.');
104
- return;
105
- }
106
- if (sub === 'installed') {
107
- const receipts = [
108
- ...listInstalledEcosystemEntries('plugin', ecosystemPaths).map((receipt) => ` plugin ${receipt.entry.id} ${receipt.scope} ${receipt.targetPath}`),
109
- ...listInstalledEcosystemEntries('skill', ecosystemPaths).map((receipt) => ` skill ${receipt.entry.id} ${receipt.scope} ${receipt.targetPath}`),
110
- ...listInstalledEcosystemEntries('hook-pack', ecosystemPaths).map((receipt) => ` hook-pack ${receipt.entry.id} ${receipt.scope} ${receipt.targetPath}`),
111
- ...listInstalledEcosystemEntries('policy-pack', ecosystemPaths).map((receipt) => ` policy-pack ${receipt.entry.id} ${receipt.scope} ${receipt.targetPath}`),
112
- ];
113
- ctx.print(receipts.length > 0
114
- ? ['Marketplace Installs', ...receipts].join('\n')
115
- : 'Marketplace Installs\n No curated plugins or skills installed yet.');
116
- return;
117
- }
118
- if (sub === 'bundle') {
119
- const mode = commandArgs[1];
120
- const target = commandArgs[2];
121
- const scope = commandArgs[3] === 'user' ? 'user' : 'project';
122
- if ((mode === 'export' || mode === 'inspect' || mode === 'import') && !target) {
123
- ctx.print(`Usage: /marketplace bundle ${mode} <path>${mode === 'export' || mode === 'import' ? ' [project|user] --yes' : ''}`);
124
- return;
125
- }
126
- if (mode === 'export') {
127
- if (!parsed.yes) {
128
- requireYesFlag(ctx, `export marketplace bundle to ${target}`, '/marketplace bundle export <path> [project|user] --yes');
129
- return;
130
- }
131
- const bundle = exportEcosystemCatalogBundle(scope, ecosystemPaths);
132
- const targetPath = shellPaths.resolveWorkspacePath(target!);
133
- mkdirSync(dirname(targetPath), { recursive: true });
134
- writeFileSync(targetPath, `${JSON.stringify(bundle, null, 2)}\n`, 'utf-8');
135
- ctx.print(`Marketplace bundle exported to ${targetPath}`);
136
- return;
137
- }
138
- if (mode === 'inspect') {
139
- const bundle = JSON.parse(readFileSync(shellPaths.resolveWorkspacePath(target!), 'utf-8')) as EcosystemCatalogBundle;
140
- const summary = inspectEcosystemCatalogBundle(bundle);
141
- ctx.print([
142
- 'Marketplace Bundle Review',
143
- ` exportedAt: ${new Date(summary.exportedAt).toISOString()}`,
144
- ` scope: ${summary.scope}`,
145
- ` plugins: ${summary.counts.plugin}`,
146
- ` skills: ${summary.counts.skill}`,
147
- ].join('\n'));
148
- return;
149
- }
150
- if (mode === 'import') {
151
- if (!parsed.yes) {
152
- requireYesFlag(ctx, `import marketplace bundle from ${target}`, '/marketplace bundle import <path> [project|user] --yes');
153
- return;
154
- }
155
- const bundle = JSON.parse(readFileSync(shellPaths.resolveWorkspacePath(target!), 'utf-8')) as EcosystemCatalogBundle;
156
- const result = importEcosystemCatalogBundle(bundle, { ...ecosystemPaths, scope });
157
- ctx.print([
158
- `Marketplace bundle imported from ${shellPaths.resolveWorkspacePath(target!)}`,
159
- ` entries: ${result.imported}`,
160
- ...Object.entries(result.pathByKind).map(([kind, path]) => ` ${kind}: ${path}`),
161
- ].join('\n'));
162
- return;
163
- }
164
- ctx.print('Usage: /marketplace bundle <export|inspect|import> <path> [project|user] --yes');
165
- return;
166
- }
167
-
168
- const kind = commandArgs[1] as EcosystemEntryKind | undefined;
169
- const entryId = commandArgs[2];
170
- if ((sub === 'review' || sub === 'provenance' || sub === 'install-hint' || sub === 'install' || sub === 'update' || sub === 'rollback' || sub === 'history' || sub === 'uninstall' || sub === 'receipt') && (!kind || !entryId || !['plugin', 'skill', 'hook-pack', 'policy-pack'].includes(kind))) {
171
- ctx.print(`Usage: /marketplace ${sub} <plugin|skill|hook-pack|policy-pack> <id>${sub === 'install' || sub === 'update' || sub === 'rollback' || sub === 'history' || sub === 'uninstall' || sub === 'receipt' ? ' [project|user]' : ''}${sub === 'install' || sub === 'update' || sub === 'rollback' || sub === 'uninstall' ? ' --yes' : ''}`);
172
- return;
173
- }
174
- if (sub === 'review') {
175
- const entry = resolveMarketplaceEntry(kind!, entryId!, ecosystemPaths);
176
- if (!entry) {
177
- ctx.print(`Unknown curated ${kind} entry: ${entryId}`);
178
- return;
179
- }
180
- const review = reviewEcosystemCatalogEntry(entry, ecosystemPaths);
181
- ctx.print([
182
- `Marketplace Review: ${entry.name}`,
183
- ` kind: ${kind}`,
184
- ` id: ${entry.id}`,
185
- ` source: ${entry.source}`,
186
- ` sourceKind: ${review.sourceKind}`,
187
- ` sourceExists: ${review.sourceExists ? 'yes' : 'no'}`,
188
- ` recommendedScope: ${review.recommendedScope}`,
189
- ` risk: ${review.riskLevel}`,
190
- ` compatibility: ${review.compatibility.status}`,
191
- ` notes: ${formatCompatibility(review)}`,
192
- ].join('\n'));
193
- return;
194
- }
195
- if (sub === 'provenance') {
196
- const entry = resolveMarketplaceEntry(kind!, entryId!, ecosystemPaths);
197
- if (!entry) {
198
- ctx.print(`Unknown curated ${kind} entry: ${entryId}`);
199
- return;
200
- }
201
- const review = reviewEcosystemCatalogEntry(entry, ecosystemPaths);
202
- ctx.print([
203
- `Marketplace Provenance: ${entry.name}`,
204
- ` source: ${entry.source}`,
205
- ` provenance: ${entry.provenance ?? '(none declared)'}`,
206
- ` version: ${entry.version ?? '(unspecified)'}`,
207
- ` author: ${entry.author ?? '(unspecified)'}`,
208
- ` signature: ${entry.signature ?? '(none declared)'}`,
209
- ` compatibility: ${formatCompatibility(review)}`,
210
- ` trust notes: ${entry.trustNotes ?? '(none)'}`,
211
- ].join('\n'));
212
- return;
213
- }
214
- if (sub === 'install-hint') {
215
- const entry = resolveMarketplaceEntry(kind!, entryId!, ecosystemPaths);
216
- if (!entry) {
217
- ctx.print(`Unknown curated ${kind} entry: ${entryId}`);
218
- return;
219
- }
220
- ctx.print([
221
- `Marketplace Install Guidance: ${entry.name}`,
222
- ` kind: ${kind}`,
223
- ` source: ${entry.source}`,
224
- ` install hint: ${entry.installHint ?? 'Install from a local curated source with explicit scope.'}`,
225
- ` trust notes: ${entry.trustNotes ?? '(none)'}`,
226
- ].join('\n'));
227
- return;
228
- }
229
- if (sub === 'receipt') {
230
- const scope = commandArgs[3] === 'user' ? 'user' : 'project';
231
- const result = inspectInstalledEcosystemEntry(kind!, entryId!, { ...ecosystemPaths, scope });
232
- if (!result.ok) {
233
- ctx.print(`Error: ${result.error}`);
234
- return;
235
- }
236
- const { receipt } = result;
237
- ctx.print([
238
- `Marketplace Receipt: ${receipt.entry.name}`,
239
- ` installedAt: ${new Date(receipt.installedAt).toISOString()}`,
240
- ` scope: ${receipt.scope}`,
241
- ` targetPath: ${receipt.targetPath}`,
242
- ` fingerprint: ${receipt.fingerprint}`,
243
- ` provenance: ${receipt.provenanceSummary}`,
244
- ` compatibility: ${receipt.compatibility.status}`,
245
- ...receipt.compatibility.reasons.map((reason) => ` note: ${reason}`),
246
- ].join('\n'));
247
- return;
248
- }
249
- if (sub === 'history') {
250
- const scope = commandArgs[3] === 'user' ? 'user' : 'project';
251
- const backups = listEcosystemInstallBackups(kind!, entryId!, { ...ecosystemPaths, scope });
252
- ctx.print(backups.length > 0
253
- ? [
254
- `Marketplace Rollback History: ${kind} ${entryId}`,
255
- ...backups.map((backup) => ` ${backup.id} ${new Date(backup.createdAt).toISOString()} ${backup.reason} ${backup.receipt.entry.version ?? 'n/a'}`),
256
- ].join('\n')
257
- : `Marketplace Rollback History: ${kind} ${entryId}\n No rollback backups recorded.`);
258
- return;
259
- }
260
- if (sub === 'install' || sub === 'update' || sub === 'rollback' || sub === 'uninstall') {
261
- const scope = commandArgs[3] === 'user' ? 'user' : 'project';
262
- if (!parsed.yes) {
263
- requireYesFlag(ctx, `${sub} curated ${kind} ${entryId}`, `/marketplace ${sub} <plugin|skill|hook-pack|policy-pack> <id> [project|user]${sub === 'rollback' ? ' [backupId]' : ''} --yes`);
264
- return;
265
- }
266
- if (sub === 'install') {
267
- const result = installEcosystemCatalogEntry(kind!, entryId!, { ...ecosystemPaths, scope });
268
- if (!result.ok) {
269
- ctx.print(`Error: ${result.error}`);
270
- return;
271
- }
272
- ctx.print(`Installed curated ${kind} ${entryId} into ${result.receipt.targetPath}`);
273
- return;
274
- }
275
- if (sub === 'update') {
276
- const result = updateInstalledEcosystemEntry(kind!, entryId!, { ...ecosystemPaths, scope });
277
- if (!result.ok) {
278
- ctx.print(`Error: ${result.error}`);
279
- return;
280
- }
281
- ctx.print(`Updated curated ${kind} ${entryId} in ${result.receipt.targetPath}`);
282
- return;
283
- }
284
- if (sub === 'rollback') {
285
- const backupId = commandArgs[4];
286
- const result = rollbackInstalledEcosystemEntry(kind!, entryId!, { ...ecosystemPaths, scope, backupId });
287
- if (!result.ok) {
288
- ctx.print(`Error: ${result.error}`);
289
- return;
290
- }
291
- ctx.print(`Rolled back curated ${kind} ${entryId} in ${result.receipt.targetPath} using backup ${result.restoredFrom.id}`);
292
- return;
293
- }
294
- const result = uninstallEcosystemCatalogEntry(kind!, entryId!, { ...ecosystemPaths, scope });
295
- if (!result.ok) {
296
- ctx.print(`Error: ${result.error}`);
297
- return;
298
- }
299
- ctx.print(`Uninstalled curated ${kind} ${entryId} from ${result.removedPath}`);
300
- return;
301
- }
302
- ctx.print('Usage: /marketplace [open|overview|recommend|browse [query]|review <plugin|skill|hook-pack|policy-pack> <id>|provenance <plugin|skill|hook-pack|policy-pack> <id>|install-hint <plugin|skill|hook-pack|policy-pack> <id>|install <plugin|skill|hook-pack|policy-pack> <id> [project|user] --yes|update <plugin|skill|hook-pack|policy-pack> <id> [project|user] --yes|rollback <plugin|skill|hook-pack|policy-pack> <id> [project|user] [backupId] --yes|history <plugin|skill|hook-pack|policy-pack> <id> [project|user]|uninstall <plugin|skill|hook-pack|policy-pack> <id> [project|user] --yes|receipt <plugin|skill|hook-pack|policy-pack> <id> [project|user]|bundle export <path> [project|user] --yes|bundle inspect <path>|bundle import <path> [project|user] --yes|installed]');
303
- },
304
- });
305
- }
@@ -1,148 +0,0 @@
1
- import type { CommandRegistry } from '../command-registry.ts';
2
- import { requireYesFlag, stripYesFlag } from './confirmation.ts';
3
-
4
- export function registerMemoryProductRuntimeCommands(registry: CommandRegistry): void {
5
- registry.register({
6
- name: 'memory-sync',
7
- aliases: ['memsync'],
8
- description: 'Dedicated front-door for durable memory export/import and bundle exchange',
9
- usage: '[export <path> [scope] --yes | import <path> --yes]',
10
- async handler(args, ctx) {
11
- const parsed = stripYesFlag(args);
12
- const commandArgs = [...parsed.rest];
13
- const sub = (commandArgs[0] ?? '').toLowerCase();
14
- if (!ctx.executeCommand) {
15
- ctx.print('Memory sync controls are not available in this runtime.');
16
- return;
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'];
25
- await ctx.executeCommand('recall', recallArgs);
26
- return;
27
- }
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']);
34
- return;
35
- }
36
- ctx.print('Usage: /memory-sync [export <path> [scope] --yes | import <path> --yes]');
37
- },
38
- });
39
-
40
- registry.register({
41
- name: 'handoff',
42
- description: 'Dedicated front-door for reviewable memory handoff bundles',
43
- usage: '[export <path> [scope] --yes | inspect <path> | import <path> --yes]',
44
- async handler(args, ctx) {
45
- const parsed = stripYesFlag(args);
46
- const commandArgs = [...parsed.rest];
47
- const sub = (commandArgs[0] ?? '').toLowerCase();
48
- if (!ctx.executeCommand) {
49
- ctx.print('Handoff controls are not available in this runtime.');
50
- return;
51
- }
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']);
59
- return;
60
- }
61
- if (sub === 'inspect' && commandArgs[1]) {
62
- await ctx.executeCommand('recall', ['handoff-inspect', commandArgs[1]]);
63
- return;
64
- }
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']);
71
- return;
72
- }
73
- ctx.print('Usage: /handoff [export <path> [scope] --yes | inspect <path> | import <path> --yes]');
74
- },
75
- });
76
-
77
- registry.register({
78
- name: 'session-memory',
79
- description: 'Dedicated front-door for session-scoped memory capture and review',
80
- usage: '[queue [limit] | export <path> --yes | add <class> <summary...>]',
81
- async handler(args, ctx) {
82
- const parsed = stripYesFlag(args);
83
- const commandArgs = [...parsed.rest];
84
- const sub = (commandArgs[0] ?? 'queue').toLowerCase();
85
- if (!ctx.executeCommand) {
86
- ctx.print('Session memory controls are not available in this runtime.');
87
- return;
88
- }
89
- if (sub === 'queue') {
90
- await ctx.executeCommand('recall', ['queue', ...(commandArgs[1] ? [commandArgs[1]] : [])]);
91
- return;
92
- }
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']);
99
- return;
100
- }
101
- if (sub === 'add' && commandArgs.length >= 3) {
102
- await ctx.executeCommand('recall', ['add', commandArgs[1], ...commandArgs.slice(2), '--scope', 'session']);
103
- return;
104
- }
105
- ctx.print('Usage: /session-memory [queue [limit] | export <path> --yes | add <class> <summary...>]');
106
- },
107
- });
108
-
109
- registry.register({
110
- name: 'team-memory',
111
- description: 'Dedicated front-door for team/shared memory review and exchange',
112
- usage: '[queue [limit] | export <path> --yes | import <path> --yes | capture policy]',
113
- async handler(args, ctx) {
114
- const parsed = stripYesFlag(args);
115
- const commandArgs = [...parsed.rest];
116
- const sub = (commandArgs[0] ?? 'queue').toLowerCase();
117
- if (!ctx.executeCommand) {
118
- ctx.print('Team memory controls are not available in this runtime.');
119
- return;
120
- }
121
- if (sub === 'queue') {
122
- await ctx.executeCommand('recall', ['queue', ...(commandArgs[1] ? [commandArgs[1]] : [])]);
123
- return;
124
- }
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']);
131
- return;
132
- }
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']);
139
- return;
140
- }
141
- if (sub === 'capture' && commandArgs[1]?.toLowerCase() === 'policy') {
142
- await ctx.executeCommand('recall', ['capture', 'policy']);
143
- return;
144
- }
145
- ctx.print('Usage: /team-memory [queue [limit] | export <path> --yes | import <path> --yes | capture policy]');
146
- },
147
- });
148
- }
@@ -1,146 +0,0 @@
1
- import type { CommandRegistry } from '../command-registry.ts';
2
- import { requirePanelManager } from './runtime-services.ts';
3
- import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
4
-
5
- export function registerOperatorPanelCommand(registry: CommandRegistry): void {
6
- registry.register({
7
- name: 'panel',
8
- aliases: ['panels', 'p'],
9
- description: 'Open, place, resize, or list panels. Usage: /panel [open <id> [top|bottom]|close <id>|list|toggle|move|focus|split|width|height]',
10
- usage: '[open <id> [top|bottom]|close <id>|list|toggle|move <top|bottom|other> [id]|focus <top|bottom|toggle>|split [show|hide|toggle]|width <left|right|reset>|height <up|down|reset>]',
11
- argsHint: '<open|close|list|toggle|move|focus|split|width|height> [id]',
12
- handler(args, ctx) {
13
- const pm = requirePanelManager(ctx);
14
- const sub = args[0]?.toLowerCase() ?? '';
15
- if (!sub || sub === 'toggle') {
16
- try {
17
- if (ctx.showPanel) ctx.showPanel('panel-list');
18
- else {
19
- pm.open('panel-list');
20
- pm.show();
21
- ctx.focusPanels?.();
22
- ctx.renderRequest();
23
- }
24
- } catch {
25
- pm.toggle();
26
- ctx.renderRequest();
27
- }
28
- } else if (sub === 'list') {
29
- try {
30
- if (ctx.showPanel) ctx.showPanel('panel-list');
31
- else {
32
- pm.open('panel-list');
33
- pm.show();
34
- ctx.focusPanels?.();
35
- ctx.renderRequest();
36
- }
37
- } catch {
38
- pm.show();
39
- ctx.renderRequest();
40
- }
41
- } else if (sub === 'open') {
42
- const id = args[1];
43
- const pane = args[2]?.toLowerCase();
44
- if (!id) { ctx.print('Usage: /panel open <panel-id>'); return; }
45
- if (pane && pane !== 'top' && pane !== 'bottom') {
46
- ctx.print('Usage: /panel open <panel-id> [top|bottom]');
47
- return;
48
- }
49
- try {
50
- if (ctx.showPanel) ctx.showPanel(id, pane as 'top' | 'bottom' | undefined);
51
- else {
52
- pm.open(id, pane as 'top' | 'bottom' | undefined);
53
- pm.show();
54
- ctx.focusPanels?.();
55
- ctx.renderRequest();
56
- }
57
- ctx.print(`Panel opened: ${id}${pane ? ` (${pane} pane)` : ''}`);
58
- } catch (e) {
59
- ctx.print(`Error: ${summarizeError(e)}`);
60
- }
61
- } else if (sub === 'close') {
62
- const id = args[1];
63
- if (!id) { ctx.print('Usage: /panel close <panel-id>'); return; }
64
- try {
65
- pm.close(id);
66
- ctx.focusPrompt?.();
67
- ctx.renderRequest();
68
- ctx.print(`Panel closed: ${id}`);
69
- } catch (e) {
70
- ctx.print(`Error: ${summarizeError(e)}`);
71
- }
72
- } else if (sub === 'move') {
73
- const dest = args[1]?.toLowerCase();
74
- if (dest !== 'top' && dest !== 'bottom' && dest !== 'other') {
75
- ctx.print('Usage: /panel move <top|bottom|other> [panel-id]');
76
- return;
77
- }
78
- const panelId = args[2];
79
- try {
80
- if (dest === 'other') pm.moveToOtherPane(panelId);
81
- else pm.moveToPane(dest, panelId);
82
- ctx.renderRequest();
83
- ctx.print(`Panel moved to ${dest} pane`);
84
- } catch (e) {
85
- ctx.print(`Error: ${summarizeError(e)}`);
86
- }
87
- } else if (sub === 'focus') {
88
- const pane = args[1]?.toLowerCase();
89
- if (pane !== 'top' && pane !== 'bottom' && pane !== 'toggle') {
90
- ctx.print('Usage: /panel focus <top|bottom|toggle>');
91
- return;
92
- }
93
- if (pane === 'toggle') pm.togglePaneFocus();
94
- else pm.focusPane(pane);
95
- ctx.renderRequest();
96
- ctx.print(`Focused ${pm.getFocusedPane()} pane`);
97
- } else if (sub === 'split') {
98
- const mode = args[1]?.toLowerCase() ?? 'toggle';
99
- if (mode !== 'toggle' && mode !== 'show' && mode !== 'hide') {
100
- ctx.print('Usage: /panel split [show|hide|toggle]');
101
- return;
102
- }
103
- if (mode === 'show' && !pm.isBottomPaneVisible()) pm.toggleBottomPane();
104
- if (mode === 'hide' && pm.isBottomPaneVisible()) pm.toggleBottomPane();
105
- if (mode === 'toggle') pm.toggleBottomPane();
106
- ctx.renderRequest();
107
- ctx.print(pm.isBottomPaneVisible() ? 'Bottom pane visible' : 'Bottom pane hidden');
108
- } else if (sub === 'width') {
109
- const dir = args[1]?.toLowerCase();
110
- if (dir !== 'left' && dir !== 'right' && dir !== 'reset') {
111
- ctx.print('Usage: /panel width <left|right|reset>');
112
- return;
113
- }
114
- if (dir === 'left') pm.widenLeft();
115
- else if (dir === 'right') pm.widenRight();
116
- else pm.setSplitRatio(0.6);
117
- ctx.renderRequest();
118
- ctx.print(`Panel width ratio: ${pm.getSplitRatio().toFixed(2)}`);
119
- } else if (sub === 'height') {
120
- const dir = args[1]?.toLowerCase();
121
- if (dir !== 'up' && dir !== 'down' && dir !== 'reset') {
122
- ctx.print('Usage: /panel height <up|down|reset>');
123
- return;
124
- }
125
- if (dir === 'up') pm.setVerticalSplitRatio(pm.getVerticalSplitRatio() - 0.05);
126
- else if (dir === 'down') pm.setVerticalSplitRatio(pm.getVerticalSplitRatio() + 0.05);
127
- else pm.setVerticalSplitRatio(0.5);
128
- ctx.renderRequest();
129
- ctx.print(`Panel height ratio: ${pm.getVerticalSplitRatio().toFixed(2)}`);
130
- } else {
131
- const id = args[0]!;
132
- try {
133
- if (ctx.showPanel) ctx.showPanel(id);
134
- else {
135
- pm.open(id);
136
- pm.show();
137
- ctx.focusPanels?.();
138
- ctx.renderRequest();
139
- }
140
- } catch {
141
- ctx.print(`Unknown panel "${id}". Use /panel list to see available panels.`);
142
- }
143
- }
144
- },
145
- });
146
- }