@untitled-devs/wasla 0.1.3 → 1.0.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/README.md +14 -15
- package/dist/{utils → apps/cli/src}/cli-output.d.ts +1 -1
- package/dist/{cli → apps/cli/src}/commands/config.js +2 -2
- package/dist/{cli → apps/cli/src}/commands/install.js +2 -2
- package/dist/{cli → apps/cli/src}/commands/register.js +5 -5
- package/dist/{cli → apps/cli/src}/commands/status.js +6 -6
- package/dist/{cli → apps/cli/src}/commands/sync-to.js +5 -5
- package/dist/{cli → apps/cli/src}/commands/sync.js +5 -5
- package/dist/{cli → apps/cli/src}/commands/watch.js +6 -6
- package/dist/{cli → apps/cli/src}/index.js +19 -7
- package/dist/{cli/commands/visualizer.d.ts → apps/cli/src/server/visualizer-server.d.ts} +0 -1
- package/dist/{cli/commands/visualizer.js → apps/cli/src/server/visualizer-server.js} +85 -31
- package/dist/{adapters → packages/adapters/src}/base.d.ts +1 -1
- package/dist/{adapters → packages/adapters/src}/claude.d.ts +1 -1
- package/dist/{adapters → packages/adapters/src}/claude.js +2 -2
- package/dist/{adapters → packages/adapters/src}/cursor.d.ts +1 -1
- package/dist/{adapters → packages/adapters/src}/cursor.js +2 -2
- package/dist/{adapters → packages/adapters/src}/factory.d.ts +1 -1
- package/dist/{adapters → packages/adapters/src}/gemini.d.ts +1 -1
- package/dist/{adapters → packages/adapters/src}/gemini.js +2 -2
- package/dist/{adapters → packages/adapters/src}/github-copilot-cli.d.ts +1 -1
- package/dist/{adapters → packages/adapters/src}/github-copilot-cli.js +2 -2
- package/dist/{adapters → packages/adapters/src}/github-copilot.d.ts +1 -1
- package/dist/{adapters → packages/adapters/src}/github-copilot.js +2 -2
- package/dist/{adapters → packages/adapters/src}/openclaw.d.ts +1 -1
- package/dist/{adapters → packages/adapters/src}/openclaw.js +2 -2
- package/dist/{adapters → packages/adapters/src}/opencode.d.ts +1 -1
- package/dist/{adapters → packages/adapters/src}/opencode.js +2 -2
- package/dist/{core → packages/core/src}/registry.d.ts +1 -1
- package/dist/{core → packages/core/src}/registry.js +2 -2
- package/dist/{core → packages/core/src}/visualizer-types.d.ts +8 -0
- package/dist/{syncer → packages/sync/src}/index.d.ts +3 -3
- package/dist/{syncer → packages/sync/src}/index.js +4 -4
- package/dist/{core → packages/sync/src}/scanner.d.ts +1 -1
- package/dist/{core → packages/sync/src}/scanner.js +3 -3
- package/dist/visualizer/assets/index-cU_xphSj.js +144 -0
- package/{src/visualizer/dist → dist/visualizer}/index.html +1 -1
- package/package.json +73 -62
- package/src/visualizer/dist/assets/index-C6aJB2Yl.js +0 -144
- /package/dist/{utils → apps/cli/src}/cli-output.js +0 -0
- /package/dist/{cli → apps/cli/src}/commands/config.d.ts +0 -0
- /package/dist/{cli → apps/cli/src}/commands/install.d.ts +0 -0
- /package/dist/{cli → apps/cli/src}/commands/register.d.ts +0 -0
- /package/dist/{cli → apps/cli/src}/commands/status.d.ts +0 -0
- /package/dist/{cli → apps/cli/src}/commands/sync-to.d.ts +0 -0
- /package/dist/{cli → apps/cli/src}/commands/sync.d.ts +0 -0
- /package/dist/{cli → apps/cli/src}/commands/watch.d.ts +0 -0
- /package/dist/{cli → apps/cli/src}/index.d.ts +0 -0
- /package/dist/{adapters → packages/adapters/src}/base.js +0 -0
- /package/dist/{adapters → packages/adapters/src}/factory.js +0 -0
- /package/dist/{core → packages/core/src}/types.d.ts +0 -0
- /package/dist/{core → packages/core/src}/types.js +0 -0
- /package/dist/{core → packages/core/src}/visualizer-types.js +0 -0
- /package/dist/{utils → packages/shared/src}/config.d.ts +0 -0
- /package/dist/{utils → packages/shared/src}/config.js +0 -0
- /package/dist/{utils → packages/shared/src}/fs.d.ts +0 -0
- /package/dist/{utils → packages/shared/src}/fs.js +0 -0
- /package/dist/{utils → packages/shared/src}/paths.d.ts +0 -0
- /package/dist/{utils → packages/shared/src}/paths.js +0 -0
- /package/{src/visualizer/dist → dist/visualizer}/logo.png +0 -0
package/README.md
CHANGED
|
@@ -13,6 +13,9 @@
|
|
|
13
13
|
|
|
14
14
|
[](LICENSE)
|
|
15
15
|
[](https://github.com/The-Untitled-Org/wasla-genie)
|
|
16
|
+
[](https://www.npmjs.com/package/@untitled-devs/wasla)
|
|
17
|
+
[](https://www.npmjs.com/package/@untitled-devs/wasla)
|
|
18
|
+
[](https://github.com/The-Untitled-Org/wasla-genie/releases)
|
|
16
19
|
[](https://github.com/The-Untitled-Org/wasla-genie/actions/workflows/ci-docs.yml)
|
|
17
20
|
[](https://codecov.io/gh/The-Untitled-Org/wasla-genie)
|
|
18
21
|
[]()
|
|
@@ -378,22 +381,17 @@ Nothing is forced. Centralization is a convenience, not a requirement.
|
|
|
378
381
|
|
|
379
382
|
```
|
|
380
383
|
wasla-genie/
|
|
381
|
-
├──
|
|
382
|
-
│ ├── cli/
|
|
383
|
-
│
|
|
384
|
-
|
|
385
|
-
│ ├──
|
|
386
|
-
│ ├──
|
|
387
|
-
│
|
|
388
|
-
│
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
│ ├── openclaw.js
|
|
392
|
-
│ └── hermes.js
|
|
384
|
+
├── apps/
|
|
385
|
+
│ ├── cli/src/ # CLI commands and visualizer server
|
|
386
|
+
│ └── visualizer/src/ # React visualizer
|
|
387
|
+
├── packages/
|
|
388
|
+
│ ├── adapters/src/ # Per-tool directory knowledge + stub format
|
|
389
|
+
│ ├── core/src/ # Registry, scanner, and shared types
|
|
390
|
+
│ ├── shared/src/ # Shared config, filesystem, and path helpers
|
|
391
|
+
│ └── sync/src/ # Sync orchestration and filesystem watcher
|
|
392
|
+
├── tests/
|
|
393
|
+
├── scripts/
|
|
393
394
|
├── docs/
|
|
394
|
-
│ ├── how-stubs-work.md
|
|
395
|
-
│ ├── adapters.md
|
|
396
|
-
│ └── roadmap.md
|
|
397
395
|
├── package.json
|
|
398
396
|
└── README.md
|
|
399
397
|
```
|
|
@@ -418,6 +416,7 @@ Nothing is ever duplicated.
|
|
|
418
416
|
git clone https://github.com/The-Untitled-Org/wasla-genie
|
|
419
417
|
cd wasla-genie
|
|
420
418
|
npm install
|
|
419
|
+
npm run visualizer:install
|
|
421
420
|
npm run dev
|
|
422
421
|
```
|
|
423
422
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { section, success, error, spacer, info } from '
|
|
1
|
+
import { section, success, error, spacer, info } from '../cli-output.js';
|
|
2
2
|
import prompts from 'prompts';
|
|
3
|
-
import { getConfigPath, getConfiguredRegistryPath, readConfiguredScope, writeConfiguredScope, } from '
|
|
3
|
+
import { getConfigPath, getConfiguredRegistryPath, readConfiguredScope, writeConfiguredScope, } from '#shared/config.js';
|
|
4
4
|
export async function configCommand(options) {
|
|
5
5
|
try {
|
|
6
6
|
const currentScope = await readConfiguredScope();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { section, success, error, highlight, spacer } from '
|
|
2
|
-
import { readConfiguredScope } from '
|
|
1
|
+
import { section, success, error, highlight, spacer } from '../cli-output.js';
|
|
2
|
+
import { readConfiguredScope } from '#shared/config.js';
|
|
3
3
|
export async function installCommand() {
|
|
4
4
|
try {
|
|
5
5
|
section('Preparing WaslaGenie CLI...');
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { getInstalledAdapters } from '
|
|
2
|
-
import { section, success, error, warning, highlight, spacer } from '
|
|
3
|
-
import { getRegistryDir } from '
|
|
4
|
-
import { ensureDir } from '
|
|
5
|
-
import { requireConfiguredScope } from '
|
|
1
|
+
import { getInstalledAdapters } from '#adapters/factory.js';
|
|
2
|
+
import { section, success, error, warning, highlight, spacer } from '../cli-output.js';
|
|
3
|
+
import { getRegistryDir } from '#shared/paths.js';
|
|
4
|
+
import { ensureDir } from '#shared/fs.js';
|
|
5
|
+
import { requireConfiguredScope } from '#shared/config.js';
|
|
6
6
|
export async function registerCommand(options = {}) {
|
|
7
7
|
try {
|
|
8
8
|
section('Detecting installed orchestrators...');
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { RegistryManager } from '
|
|
2
|
-
import { Scanner } from '
|
|
3
|
-
import { assetList, section, error, info, metric, spacer } from '
|
|
4
|
-
import { fileExists } from '
|
|
5
|
-
import { getRegistryPath } from '
|
|
6
|
-
import { requireConfiguredScope } from '
|
|
1
|
+
import { RegistryManager } from '#core/registry.js';
|
|
2
|
+
import { Scanner } from '#sync/scanner.js';
|
|
3
|
+
import { assetList, section, error, info, metric, spacer } from '../cli-output.js';
|
|
4
|
+
import { fileExists } from '#shared/fs.js';
|
|
5
|
+
import { getRegistryPath } from '#shared/paths.js';
|
|
6
|
+
import { requireConfiguredScope } from '#shared/config.js';
|
|
7
7
|
export async function statusCommand() {
|
|
8
8
|
try {
|
|
9
9
|
const scope = await requireConfiguredScope();
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { RegistryManager } from '
|
|
2
|
-
import { Scanner } from '
|
|
3
|
-
import { Syncer } from '
|
|
4
|
-
import { section, error, highlight, spacer } from '
|
|
5
|
-
import { requireConfiguredScope } from '
|
|
1
|
+
import { RegistryManager } from '#core/registry.js';
|
|
2
|
+
import { Scanner } from '#sync/scanner.js';
|
|
3
|
+
import { Syncer } from '#sync/index.js';
|
|
4
|
+
import { section, error, highlight, spacer } from '../cli-output.js';
|
|
5
|
+
import { requireConfiguredScope } from '#shared/config.js';
|
|
6
6
|
export async function syncToCommand(options) {
|
|
7
7
|
try {
|
|
8
8
|
const scope = await requireConfiguredScope();
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { RegistryManager } from '
|
|
2
|
-
import { Scanner } from '
|
|
3
|
-
import { Syncer } from '
|
|
4
|
-
import { assetList, bulletPoint, section, error, highlight, info, metric, spacer, } from '
|
|
5
|
-
import { getConfiguredRegistryPath, requireConfiguredScope } from '
|
|
1
|
+
import { RegistryManager } from '#core/registry.js';
|
|
2
|
+
import { Scanner } from '#sync/scanner.js';
|
|
3
|
+
import { Syncer } from '#sync/index.js';
|
|
4
|
+
import { assetList, bulletPoint, section, error, highlight, info, metric, spacer, } from '../cli-output.js';
|
|
5
|
+
import { getConfiguredRegistryPath, requireConfiguredScope } from '#shared/config.js';
|
|
6
6
|
import { configCommand } from './config.js';
|
|
7
7
|
export async function syncCommand(options = {}) {
|
|
8
8
|
try {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import chokidar from 'chokidar';
|
|
2
|
-
import { RegistryManager } from '
|
|
3
|
-
import { Scanner } from '
|
|
4
|
-
import { Syncer } from '
|
|
5
|
-
import { getAllAdapters } from '
|
|
6
|
-
import { section, success, error, info, spacer } from '
|
|
7
|
-
import { requireConfiguredScope } from '
|
|
2
|
+
import { RegistryManager } from '#core/registry.js';
|
|
3
|
+
import { Scanner } from '#sync/scanner.js';
|
|
4
|
+
import { Syncer } from '#sync/index.js';
|
|
5
|
+
import { getAllAdapters } from '#adapters/factory.js';
|
|
6
|
+
import { section, success, error, info, spacer } from '../cli-output.js';
|
|
7
|
+
import { requireConfiguredScope } from '#shared/config.js';
|
|
8
8
|
export async function watchCommand() {
|
|
9
9
|
try {
|
|
10
10
|
const scope = await requireConfiguredScope();
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from 'commander';
|
|
3
|
-
import { readFileSync } from 'fs';
|
|
3
|
+
import { existsSync, readFileSync } from 'fs';
|
|
4
|
+
import { dirname, join } from 'path';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
4
6
|
import { installCommand } from './commands/install.js';
|
|
5
7
|
import { registerCommand } from './commands/register.js';
|
|
6
8
|
import { syncCommand } from './commands/sync.js';
|
|
@@ -8,14 +10,26 @@ import { syncToCommand } from './commands/sync-to.js';
|
|
|
8
10
|
import { statusCommand } from './commands/status.js';
|
|
9
11
|
import { configCommand } from './commands/config.js';
|
|
10
12
|
import { watchCommand } from './commands/watch.js';
|
|
11
|
-
import { visualizerCommand } from './
|
|
12
|
-
import { banner } from '
|
|
13
|
+
import { visualizerCommand } from './server/visualizer-server.js';
|
|
14
|
+
import { banner } from './cli-output.js';
|
|
13
15
|
const program = new Command();
|
|
14
|
-
|
|
16
|
+
function readPackageVersion(moduleUrl) {
|
|
17
|
+
let directory = dirname(fileURLToPath(moduleUrl));
|
|
18
|
+
while (true) {
|
|
19
|
+
const packagePath = join(directory, 'package.json');
|
|
20
|
+
if (existsSync(packagePath)) {
|
|
21
|
+
return JSON.parse(readFileSync(packagePath, 'utf-8')).version;
|
|
22
|
+
}
|
|
23
|
+
const parent = dirname(directory);
|
|
24
|
+
if (parent === directory)
|
|
25
|
+
throw new Error('Cannot find package.json');
|
|
26
|
+
directory = parent;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
15
29
|
program
|
|
16
30
|
.name('waslagenie')
|
|
17
31
|
.description('Universal synchronization layer for AI agent orchestrators')
|
|
18
|
-
.version(
|
|
32
|
+
.version(readPackageVersion(import.meta.url));
|
|
19
33
|
program.addCommand(new Command('install').description('Prepare WaslaGenie CLI state').action(installCommand));
|
|
20
34
|
program.addCommand(new Command('register')
|
|
21
35
|
.option('--to <targets>', 'Target provider(s), comma-separated. Example: claude,gemini')
|
|
@@ -41,13 +55,11 @@ program.addCommand(new Command('config')
|
|
|
41
55
|
}));
|
|
42
56
|
program.addCommand(new Command('watch').description('Watch for changes and auto-sync').action(() => watchCommand()));
|
|
43
57
|
program.addCommand(new Command('visualizer')
|
|
44
|
-
.option('--host <host>', 'Host to bind', '127.0.0.1')
|
|
45
58
|
.option('--port <port>', 'Port to bind', '4072')
|
|
46
59
|
.option('--no-open', 'Do not open browser automatically')
|
|
47
60
|
.description('Open interactive sync visualizer with built-in backend')
|
|
48
61
|
.action((options) => visualizerCommand(options)));
|
|
49
62
|
program.addCommand(new Command('ui')
|
|
50
|
-
.option('--host <host>', 'Host to bind', '127.0.0.1')
|
|
51
63
|
.option('--port <port>', 'Port to bind', '4072')
|
|
52
64
|
.option('--no-open', 'Do not open browser automatically')
|
|
53
65
|
.description('Alias for `visualizer`')
|
|
@@ -5,20 +5,25 @@ import { readFile } from 'fs/promises';
|
|
|
5
5
|
import { existsSync } from 'fs';
|
|
6
6
|
import { exec } from 'child_process';
|
|
7
7
|
import { WebSocketServer } from 'ws';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import { requireConfiguredScope } from '
|
|
8
|
+
import { RegistryManager } from '#core/registry.js';
|
|
9
|
+
import { getAllAdapters, getInstalledAdapters } from '#adapters/factory.js';
|
|
10
|
+
import { error, highlight, info, section, spacer } from '../cli-output.js';
|
|
11
|
+
import { Syncer } from '#sync/index.js';
|
|
12
|
+
import { Scanner } from '#sync/scanner.js';
|
|
13
|
+
import { requireConfiguredScope } from '#shared/config.js';
|
|
14
14
|
export function resolveVisualizerDist(moduleUrl) {
|
|
15
|
-
return resolve(dirname(fileURLToPath(moduleUrl)), '
|
|
15
|
+
return resolve(dirname(fileURLToPath(moduleUrl)), '../../../../visualizer');
|
|
16
16
|
}
|
|
17
|
-
async function getEntityContent(scope, type, name) {
|
|
17
|
+
async function getEntityContent(scope, type, name, providerId) {
|
|
18
18
|
const scanner = new Scanner(scope);
|
|
19
19
|
await scanner.initialize();
|
|
20
|
-
const
|
|
21
|
-
const
|
|
20
|
+
const assetType = mapEntityType(type);
|
|
21
|
+
const discovered = providerId === 'waslagenie'
|
|
22
|
+
? await scanner.scanAllTools([assetType])
|
|
23
|
+
: await scanner.scanTool(providerId, [assetType]);
|
|
24
|
+
const target = discovered
|
|
25
|
+
.filter((item) => mapType(item.type) === type && item.name === name)
|
|
26
|
+
.sort((a, b) => b.modifiedAt - a.modifiedAt)[0];
|
|
22
27
|
if (!target)
|
|
23
28
|
return null;
|
|
24
29
|
if (target.content)
|
|
@@ -30,11 +35,23 @@ async function getEntityContent(scope, type, name) {
|
|
|
30
35
|
return null;
|
|
31
36
|
}
|
|
32
37
|
}
|
|
38
|
+
function isVisualizerEntityType(type) {
|
|
39
|
+
return type === 'instruction' || type === 'agent' || type === 'skill' || type === 'mcp';
|
|
40
|
+
}
|
|
33
41
|
function mapType(type) {
|
|
34
42
|
if (type === 'context')
|
|
35
43
|
return 'instruction';
|
|
36
44
|
return type;
|
|
37
45
|
}
|
|
46
|
+
function isAllowedOrigin(origin, port) {
|
|
47
|
+
if (!origin)
|
|
48
|
+
return true;
|
|
49
|
+
return origin === `http://127.0.0.1:${port}` || origin === `http://localhost:${port}`;
|
|
50
|
+
}
|
|
51
|
+
function isKnownProvider(scope, providerId) {
|
|
52
|
+
return (providerId === 'waslagenie' ||
|
|
53
|
+
getAllAdapters(scope).some((adapter) => adapter.name === providerId));
|
|
54
|
+
}
|
|
38
55
|
function mapEntityType(type) {
|
|
39
56
|
if (type === 'instruction')
|
|
40
57
|
return 'context';
|
|
@@ -85,12 +102,20 @@ async function buildConfig(scope) {
|
|
|
85
102
|
await scanner.initialize();
|
|
86
103
|
const discovered = await scanner.scanAllTools();
|
|
87
104
|
const installed = await getInstalledAdapters(scope);
|
|
105
|
+
const installedNames = new Set(installed.map((adapter) => adapter.name));
|
|
88
106
|
const providers = [
|
|
89
|
-
{
|
|
90
|
-
|
|
107
|
+
{
|
|
108
|
+
id: 'waslagenie',
|
|
109
|
+
title: 'WaslaGenie',
|
|
110
|
+
iconUrl: PROVIDER_ICONS.waslagenie,
|
|
111
|
+
isHub: true,
|
|
112
|
+
isInstalled: true,
|
|
113
|
+
},
|
|
114
|
+
...getAllAdapters(scope).map((adapter) => ({
|
|
91
115
|
id: adapter.name,
|
|
92
116
|
title: adapter.displayName,
|
|
93
117
|
iconUrl: PROVIDER_ICONS[adapter.name],
|
|
118
|
+
isInstalled: installedNames.has(adapter.name),
|
|
94
119
|
})),
|
|
95
120
|
];
|
|
96
121
|
const entityMap = new Map();
|
|
@@ -129,7 +154,6 @@ async function buildConfig(scope) {
|
|
|
129
154
|
providers,
|
|
130
155
|
entities: grouped,
|
|
131
156
|
connections: Array.from(connectionMap.values()),
|
|
132
|
-
websocketUrl: '',
|
|
133
157
|
};
|
|
134
158
|
}
|
|
135
159
|
function sendJson(res, statusCode, body) {
|
|
@@ -140,7 +164,7 @@ function sendJson(res, statusCode, body) {
|
|
|
140
164
|
export async function visualizerCommand(options) {
|
|
141
165
|
try {
|
|
142
166
|
const scope = await requireConfiguredScope();
|
|
143
|
-
const host =
|
|
167
|
+
const host = '127.0.0.1';
|
|
144
168
|
const port = Number(options.port || 4072);
|
|
145
169
|
const shouldOpen = options.noOpen !== true;
|
|
146
170
|
section('Starting visualizer...');
|
|
@@ -161,36 +185,43 @@ export async function visualizerCommand(options) {
|
|
|
161
185
|
};
|
|
162
186
|
const server = createServer(async (req, res) => {
|
|
163
187
|
const url = req.url || '/';
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
sendJson(res,
|
|
188
|
+
const parsed = new URL(`http://${host}:${port}${url}`);
|
|
189
|
+
const pathname = parsed.pathname;
|
|
190
|
+
if (!isAllowedOrigin(req.headers.origin, port)) {
|
|
191
|
+
sendJson(res, 403, { error: 'Forbidden origin' });
|
|
168
192
|
return;
|
|
169
193
|
}
|
|
170
|
-
if (req.method === 'GET' &&
|
|
171
|
-
|
|
194
|
+
if (req.method === 'GET' && pathname === '/api/config') {
|
|
195
|
+
sendJson(res, 200, await buildConfig(scope));
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
if (req.method === 'GET' && pathname === '/api/entity-content') {
|
|
172
199
|
const type = parsed.searchParams.get('type');
|
|
173
200
|
const name = parsed.searchParams.get('name');
|
|
174
|
-
|
|
175
|
-
|
|
201
|
+
const providerId = parsed.searchParams.get('provider');
|
|
202
|
+
if (!isVisualizerEntityType(type) ||
|
|
203
|
+
!name ||
|
|
204
|
+
!providerId ||
|
|
205
|
+
!isKnownProvider(scope, providerId)) {
|
|
206
|
+
sendJson(res, 400, { error: 'valid type, name, and provider are required' });
|
|
176
207
|
return;
|
|
177
208
|
}
|
|
178
|
-
const content = await getEntityContent(scope, type, name);
|
|
209
|
+
const content = await getEntityContent(scope, type, name, providerId);
|
|
179
210
|
sendJson(res, 200, { content: content ?? '' });
|
|
180
211
|
return;
|
|
181
212
|
}
|
|
182
|
-
if (req.method === 'POST' &&
|
|
213
|
+
if (req.method === 'POST' && pathname === '/api/shutdown') {
|
|
183
214
|
sendJson(res, 200, { ok: true });
|
|
184
215
|
setTimeout(shutdown, 50);
|
|
185
216
|
return;
|
|
186
217
|
}
|
|
187
|
-
if (
|
|
218
|
+
if (pathname === '/' || pathname === '/index.html') {
|
|
188
219
|
const html = await readFile(join(visualizerDist, 'index.html'));
|
|
189
220
|
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
190
221
|
res.end(html);
|
|
191
222
|
return;
|
|
192
223
|
}
|
|
193
|
-
const staticPath = join(visualizerDist,
|
|
224
|
+
const staticPath = join(visualizerDist, pathname.replace(/^\//, ''));
|
|
194
225
|
if (!staticPath.startsWith(visualizerDist) || !existsSync(staticPath)) {
|
|
195
226
|
res.writeHead(404);
|
|
196
227
|
res.end('Not Found');
|
|
@@ -200,15 +231,24 @@ export async function visualizerCommand(options) {
|
|
|
200
231
|
res.writeHead(200, { 'Content-Type': mimeType(staticPath) });
|
|
201
232
|
res.end(payload);
|
|
202
233
|
});
|
|
203
|
-
const wss = new WebSocketServer({
|
|
234
|
+
const wss = new WebSocketServer({
|
|
235
|
+
server,
|
|
236
|
+
verifyClient: ({ origin }) => isAllowedOrigin(origin, port),
|
|
237
|
+
});
|
|
204
238
|
wss.on('connection', (socket) => {
|
|
205
239
|
socket.on('message', async (raw) => {
|
|
240
|
+
let requestId = '';
|
|
206
241
|
try {
|
|
207
242
|
const data = JSON.parse(raw.toString());
|
|
208
|
-
if (data.type !== 'CONNECTION_CHANGED' || !data.payload)
|
|
243
|
+
if (data.type !== 'CONNECTION_CHANGED' || !data.requestId || !data.payload)
|
|
209
244
|
return;
|
|
245
|
+
requestId = data.requestId;
|
|
210
246
|
const { sourceEntity, entityType, sourceProvider, targetProvider, action } = data.payload;
|
|
211
|
-
if (!sourceEntity ||
|
|
247
|
+
if (!sourceEntity ||
|
|
248
|
+
!isVisualizerEntityType(entityType) ||
|
|
249
|
+
!sourceProvider ||
|
|
250
|
+
!targetProvider ||
|
|
251
|
+
(action !== 'ATTACH' && action !== 'DETACH')) {
|
|
212
252
|
return;
|
|
213
253
|
}
|
|
214
254
|
info(`[Visualizer] ${action} ${entityType}:${sourceEntity} ${action === 'ATTACH' ? 'to' : 'from'} ${targetProvider}`);
|
|
@@ -218,9 +258,23 @@ export async function visualizerCommand(options) {
|
|
|
218
258
|
else {
|
|
219
259
|
await syncer.detachAssetFromTool(sourceEntity, mapEntityType(entityType), targetProvider);
|
|
220
260
|
}
|
|
261
|
+
const result = {
|
|
262
|
+
type: 'CONNECTION_CHANGED_RESULT',
|
|
263
|
+
requestId,
|
|
264
|
+
ok: true,
|
|
265
|
+
};
|
|
266
|
+
socket.send(JSON.stringify(result));
|
|
221
267
|
}
|
|
222
|
-
catch {
|
|
223
|
-
|
|
268
|
+
catch (err) {
|
|
269
|
+
if (!requestId)
|
|
270
|
+
return;
|
|
271
|
+
const result = {
|
|
272
|
+
type: 'CONNECTION_CHANGED_RESULT',
|
|
273
|
+
requestId,
|
|
274
|
+
ok: false,
|
|
275
|
+
error: err instanceof Error ? err.message : String(err),
|
|
276
|
+
};
|
|
277
|
+
socket.send(JSON.stringify(result));
|
|
224
278
|
}
|
|
225
279
|
});
|
|
226
280
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { WaslaGenieAdapter, Asset, AssetFormat } from '
|
|
1
|
+
import { WaslaGenieAdapter, Asset, AssetFormat } from '#core/types.js';
|
|
2
2
|
export declare abstract class BaseAdapter implements WaslaGenieAdapter {
|
|
3
3
|
abstract name: string;
|
|
4
4
|
abstract displayName: string;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { BaseAdapter } from './base.js';
|
|
2
|
-
import { fileExists, writeText, ensureDir } from '
|
|
2
|
+
import { fileExists, writeText, ensureDir } from '#shared/fs.js';
|
|
3
3
|
import { join } from 'path';
|
|
4
|
-
import { getToolMarkers } from '
|
|
4
|
+
import { getToolMarkers } from '#shared/paths.js';
|
|
5
5
|
export class ClaudeAdapter extends BaseAdapter {
|
|
6
6
|
constructor(scope = 'workspace') {
|
|
7
7
|
super();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { BaseAdapter } from './base.js';
|
|
2
|
-
import { fileExists, writeText, ensureDir } from '
|
|
2
|
+
import { fileExists, writeText, ensureDir } from '#shared/fs.js';
|
|
3
3
|
import { dirname, join } from 'path';
|
|
4
|
-
import { getToolMarkers } from '
|
|
4
|
+
import { getToolMarkers } from '#shared/paths.js';
|
|
5
5
|
export class CursorAdapter extends BaseAdapter {
|
|
6
6
|
constructor(scope = 'workspace') {
|
|
7
7
|
super();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { WaslaGenieAdapter } from '
|
|
1
|
+
import { WaslaGenieAdapter } from '#core/types.js';
|
|
2
2
|
export declare function getAdapter(toolName: string, scope?: 'user' | 'workspace'): WaslaGenieAdapter;
|
|
3
3
|
export declare function getInstalledAdapters(scope?: 'user' | 'workspace'): Promise<WaslaGenieAdapter[]>;
|
|
4
4
|
export declare function getAllAdapters(scope?: 'user' | 'workspace'): WaslaGenieAdapter[];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { BaseAdapter } from './base.js';
|
|
2
|
-
import { fileExists, writeText, ensureDir } from '
|
|
2
|
+
import { fileExists, writeText, ensureDir } from '#shared/fs.js';
|
|
3
3
|
import { dirname, join } from 'path';
|
|
4
|
-
import { getToolMarkers } from '
|
|
4
|
+
import { getToolMarkers } from '#shared/paths.js';
|
|
5
5
|
export class GeminiAdapter extends BaseAdapter {
|
|
6
6
|
constructor(scope = 'workspace') {
|
|
7
7
|
super();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { BaseAdapter } from './base.js';
|
|
2
|
-
import { fileExists, writeText, ensureDir } from '
|
|
2
|
+
import { fileExists, writeText, ensureDir } from '#shared/fs.js';
|
|
3
3
|
import { dirname, join } from 'path';
|
|
4
|
-
import { getToolMarkers } from '
|
|
4
|
+
import { getToolMarkers } from '#shared/paths.js';
|
|
5
5
|
export class GithubCopilotCliAdapter extends BaseAdapter {
|
|
6
6
|
constructor(scope = 'workspace') {
|
|
7
7
|
super();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { BaseAdapter } from './base.js';
|
|
2
|
-
import { fileExists, writeText, ensureDir } from '
|
|
2
|
+
import { fileExists, writeText, ensureDir } from '#shared/fs.js';
|
|
3
3
|
import { dirname, join } from 'path';
|
|
4
|
-
import { getToolMarkers } from '
|
|
4
|
+
import { getToolMarkers } from '#shared/paths.js';
|
|
5
5
|
export class GithubCopilotAdapter extends BaseAdapter {
|
|
6
6
|
constructor(scope = 'workspace') {
|
|
7
7
|
super();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { BaseAdapter } from './base.js';
|
|
2
|
-
import { fileExists, writeText, ensureDir } from '
|
|
2
|
+
import { fileExists, writeText, ensureDir } from '#shared/fs.js';
|
|
3
3
|
import { dirname, join } from 'path';
|
|
4
|
-
import { getToolMarkers } from '
|
|
4
|
+
import { getToolMarkers } from '#shared/paths.js';
|
|
5
5
|
export class OpenclawAdapter extends BaseAdapter {
|
|
6
6
|
constructor(scope = 'workspace') {
|
|
7
7
|
super();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { BaseAdapter } from './base.js';
|
|
2
|
-
import { fileExists, writeText, ensureDir } from '
|
|
2
|
+
import { fileExists, writeText, ensureDir } from '#shared/fs.js';
|
|
3
3
|
import { dirname, join } from 'path';
|
|
4
|
-
import { getToolMarkers } from '
|
|
4
|
+
import { getToolMarkers } from '#shared/paths.js';
|
|
5
5
|
export class OpenCodeAdapter extends BaseAdapter {
|
|
6
6
|
constructor(scope = 'workspace') {
|
|
7
7
|
super();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { readJSON, writeJSON, fileExists, ensureDir } from '
|
|
2
|
-
import { getRegistryPath, getRegistryDir } from '
|
|
1
|
+
import { readJSON, writeJSON, fileExists, ensureDir } from '#shared/fs.js';
|
|
2
|
+
import { getRegistryPath, getRegistryDir } from '#shared/paths.js';
|
|
3
3
|
import { randomUUID } from 'crypto';
|
|
4
4
|
export class RegistryManager {
|
|
5
5
|
constructor(scope = 'workspace') {
|
|
@@ -10,6 +10,7 @@ export interface VisualizerProvider {
|
|
|
10
10
|
title: string;
|
|
11
11
|
iconUrl?: string;
|
|
12
12
|
isHub?: boolean;
|
|
13
|
+
isInstalled?: boolean;
|
|
13
14
|
}
|
|
14
15
|
export interface VisualizerConnection {
|
|
15
16
|
entityId: string;
|
|
@@ -28,6 +29,7 @@ export interface VisualizerConfiguration {
|
|
|
28
29
|
}
|
|
29
30
|
export interface ConnectionChangedMessage {
|
|
30
31
|
type: 'CONNECTION_CHANGED';
|
|
32
|
+
requestId: string;
|
|
31
33
|
payload: {
|
|
32
34
|
sourceEntity: string;
|
|
33
35
|
entityType: VisualizerEntityType;
|
|
@@ -36,3 +38,9 @@ export interface ConnectionChangedMessage {
|
|
|
36
38
|
action: 'ATTACH' | 'DETACH';
|
|
37
39
|
};
|
|
38
40
|
}
|
|
41
|
+
export interface ConnectionChangedResultMessage {
|
|
42
|
+
type: 'CONNECTION_CHANGED_RESULT';
|
|
43
|
+
requestId: string;
|
|
44
|
+
ok: boolean;
|
|
45
|
+
error?: string;
|
|
46
|
+
}
|