@untitled-devs/wasla 1.0.1 → 1.1.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 +59 -67
- package/dist/apps/cli/src/cli-output.js +5 -5
- package/dist/apps/cli/src/commands/config.js +1 -1
- package/dist/apps/cli/src/commands/install.js +6 -6
- package/dist/apps/cli/src/commands/register.js +1 -1
- package/dist/apps/cli/src/commands/status.js +1 -1
- package/dist/apps/cli/src/commands/sync-to.js +2 -2
- package/dist/apps/cli/src/commands/watch.js +1 -1
- package/dist/apps/cli/src/index.js +4 -4
- package/dist/apps/cli/src/server/visualizer-server.js +13 -14
- package/dist/packages/adapters/src/base.d.ts +2 -2
- package/dist/packages/adapters/src/claude.js +9 -9
- package/dist/packages/adapters/src/factory.d.ts +4 -4
- package/dist/packages/adapters/src/gemini.js +10 -10
- package/dist/packages/core/src/types.d.ts +1 -1
- package/dist/packages/shared/src/config.js +3 -3
- package/dist/packages/shared/src/paths.js +4 -4
- package/dist/packages/sync/src/index.js +2 -2
- package/dist/packages/sync/src/scanner.js +3 -3
- package/dist/visualizer/assets/index-BwXGlw7v.js +9 -0
- package/dist/visualizer/assets/index-DcQscgvu.css +1 -0
- package/dist/visualizer/favicon.png +0 -0
- package/dist/visualizer/img/claude.png +0 -0
- package/dist/visualizer/img/copilot-cli.png +0 -0
- package/dist/visualizer/img/copilot.png +0 -0
- package/dist/visualizer/img/cursor.png +0 -0
- package/dist/visualizer/img/gemini.png +0 -0
- package/dist/visualizer/img/openclaw.png +0 -0
- package/dist/visualizer/img/opencode.png +0 -0
- package/dist/visualizer/index.html +4 -2
- package/dist/visualizer/logo.png +0 -0
- package/package.json +10 -7
- package/dist/visualizer/assets/index-cU_xphSj.js +0 -144
package/README.md
CHANGED
|
@@ -1,25 +1,19 @@
|
|
|
1
1
|
|
|
2
|
-
```
|
|
3
|
-
██╗ ██╗ █████╗ ███████╗██╗ █████╗ ██████╗ ███████╗███╗ ██╗██╗███████╗
|
|
4
|
-
██║ ██║██╔══██╗██╔════╝██║ ██╔══██╗ ██╔════╝ ██╔════╝████╗ ██║██║██╔════╝
|
|
5
|
-
██║ █╗ ██║███████║███████╗██║ ███████║ ██║ ███╗█████╗ ██╔██╗ ██║██║█████╗
|
|
6
|
-
██║███╗██║██╔══██║╚════██║██║ ██╔══██║ ██║ ██║██╔══╝ ██║╚██╗██║██║██╔══╝
|
|
7
|
-
╚███╔███╔╝██║ ██║███████║███████╗██║ ██║ ╚██████╔╝███████╗██║ ╚████║██║███████╗
|
|
8
|
-
╚══╝╚══╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═══╝╚═╝╚══════╝
|
|
9
|
-
```
|
|
10
2
|
<div align="center">
|
|
11
3
|
|
|
12
|
-
|
|
4
|
+
<img src="apps/docs/static/img/logo-wordmark.png" alt="Wasla" width="640" />
|
|
5
|
+
|
|
6
|
+
**وصلة** — *One skill layer. Every AI orchestrator. Zero duplication.*
|
|
13
7
|
|
|
14
8
|
[](LICENSE)
|
|
15
|
-
[](https://github.com/The-Untitled-Org/wasla
|
|
9
|
+
[](https://github.com/The-Untitled-Org/wasla)
|
|
16
10
|
[](https://www.npmjs.com/package/@untitled-devs/wasla)
|
|
17
11
|
[](https://www.npmjs.com/package/@untitled-devs/wasla)
|
|
18
|
-
[](https://github.com/The-Untitled-Org/wasla/releases)
|
|
13
|
+
[](https://github.com/The-Untitled-Org/wasla/actions/workflows/ci-docs.yml)
|
|
14
|
+
[](https://codecov.io/gh/The-Untitled-Org/wasla)
|
|
21
15
|
[]()
|
|
22
|
-
[](https://github.com/The-Untitled-Org/wasla/graphs/contributors)
|
|
23
17
|
|
|
24
18
|
</div>
|
|
25
19
|
|
|
@@ -49,11 +43,11 @@ You end up **copy-pasting configs, duplicating agent definitions, and maintainin
|
|
|
49
43
|
|
|
50
44
|
---
|
|
51
45
|
|
|
52
|
-
## ✨ What
|
|
46
|
+
## ✨ What Wasla Does
|
|
53
47
|
|
|
54
|
-
|
|
48
|
+
Wasla syncs assets across orchestrators from the CLI. Helper skill registration is optional.
|
|
55
49
|
|
|
56
|
-
When sync is triggered — manually (`sync`) or continuously (`watch`) —
|
|
50
|
+
When sync is triggered — manually (`sync`) or continuously (`watch`) — Wasla:
|
|
57
51
|
|
|
58
52
|
1. **Scans** the known config directories of every supported orchestrator on your machine
|
|
59
53
|
(`~/.claude/`, `~/.gemini/`, `~/.openclaw/`)
|
|
@@ -74,12 +68,12 @@ Say you create an agent inside Gemini CLI:
|
|
|
74
68
|
~/.gemini/agents/researcher.md ← original, owned by Gemini
|
|
75
69
|
```
|
|
76
70
|
|
|
77
|
-
After `
|
|
71
|
+
After `wasla sync`, Wasla writes a minimal stub into every other tool:
|
|
78
72
|
|
|
79
73
|
```
|
|
80
|
-
~/.claude/agents/researcher.md ← stub, written by
|
|
81
|
-
~/.codex/agents/researcher.md ← stub, written by
|
|
82
|
-
~/.openclaw/agents/researcher.md ← stub, written by
|
|
74
|
+
~/.claude/agents/researcher.md ← stub, written by Wasla
|
|
75
|
+
~/.codex/agents/researcher.md ← stub, written by Wasla
|
|
76
|
+
~/.openclaw/agents/researcher.md ← stub, written by Wasla
|
|
83
77
|
```
|
|
84
78
|
|
|
85
79
|
Each stub contains only the minimum that native tool needs to load the original:
|
|
@@ -87,7 +81,7 @@ Each stub contains only the minimum that native tool needs to load the original:
|
|
|
87
81
|
```markdown
|
|
88
82
|
---
|
|
89
83
|
# researcher
|
|
90
|
-
|
|
84
|
+
wasla_ref: ~/.gemini/agents/researcher.md
|
|
91
85
|
origin: gemini
|
|
92
86
|
---
|
|
93
87
|
Refer to source definition at ~/.gemini/agents/researcher.md
|
|
@@ -125,8 +119,8 @@ The same pattern applies across every asset type:
|
|
|
125
119
|
|
|
126
120
|
```bash
|
|
127
121
|
npm i -g @untitled-devs/wasla
|
|
128
|
-
|
|
129
|
-
|
|
122
|
+
wasla config --scope workspace
|
|
123
|
+
wasla sync
|
|
130
124
|
```
|
|
131
125
|
|
|
132
126
|
Choose `workspace` or `user` once before running operational commands.
|
|
@@ -141,11 +135,11 @@ npx @untitled-devs/wasla sync
|
|
|
141
135
|
Optional helper registration:
|
|
142
136
|
|
|
143
137
|
```bash
|
|
144
|
-
|
|
138
|
+
wasla register
|
|
145
139
|
```
|
|
146
140
|
|
|
147
|
-
`register` detects supported orchestrators and adds the
|
|
148
|
-
Use `
|
|
141
|
+
`register` detects supported orchestrators and adds the Wasla helper skill inside each one.
|
|
142
|
+
Use `wasla register --to claude` (or comma-separated targets) to install only specific providers.
|
|
149
143
|
|
|
150
144
|
---
|
|
151
145
|
|
|
@@ -155,19 +149,19 @@ Use `waslagenie register --to claude` (or comma-separated targets) to install on
|
|
|
155
149
|
|
|
156
150
|
```bash
|
|
157
151
|
# Run once on demand
|
|
158
|
-
|
|
152
|
+
wasla sync
|
|
159
153
|
|
|
160
154
|
# Keep syncing while you work
|
|
161
|
-
|
|
155
|
+
wasla watch
|
|
162
156
|
|
|
163
157
|
# Open the visualizer dashboard
|
|
164
|
-
|
|
158
|
+
wasla visualizer
|
|
165
159
|
|
|
166
160
|
# Optional: install helper skill in all detected providers
|
|
167
|
-
|
|
161
|
+
wasla register
|
|
168
162
|
|
|
169
163
|
# Optional: install helper skill in specific providers only
|
|
170
|
-
|
|
164
|
+
wasla register --to claude,gemini
|
|
171
165
|
```
|
|
172
166
|
|
|
173
167
|
You can also run without global install:
|
|
@@ -202,10 +196,10 @@ For local development without repeated global installs:
|
|
|
202
196
|
|
|
203
197
|
```bash
|
|
204
198
|
npm link
|
|
205
|
-
|
|
199
|
+
wasla sync
|
|
206
200
|
```
|
|
207
201
|
|
|
208
|
-
Then after code changes, run `npm run build` (or any script that builds) and use `
|
|
202
|
+
Then after code changes, run `npm run build` (or any script that builds) and use `wasla` again.
|
|
209
203
|
|
|
210
204
|
---
|
|
211
205
|
|
|
@@ -214,7 +208,7 @@ Then after code changes, run `npm run build` (or any script that builds) and use
|
|
|
214
208
|
### One-time sync
|
|
215
209
|
|
|
216
210
|
```bash
|
|
217
|
-
|
|
211
|
+
wasla sync
|
|
218
212
|
```
|
|
219
213
|
|
|
220
214
|
```
|
|
@@ -237,16 +231,16 @@ waslagenie sync
|
|
|
237
231
|
|
|
238
232
|
### Automatic background sync — watch mode
|
|
239
233
|
|
|
240
|
-
`
|
|
234
|
+
`wasla watch` is the background sync process. It watches for file changes across all tool directories while the command is running.
|
|
241
235
|
|
|
242
236
|
```
|
|
243
|
-
[watch starts] →
|
|
244
|
-
[File changes] →
|
|
245
|
-
[watch stops] →
|
|
237
|
+
[watch starts] → Wasla process launched
|
|
238
|
+
[File changes] → Wasla detects change and syncs immediately
|
|
239
|
+
[watch stops] → Wasla process exits cleanly
|
|
246
240
|
```
|
|
247
241
|
|
|
248
242
|
```
|
|
249
|
-
👁
|
|
243
|
+
👁 Wasla active (session: Claude Code)
|
|
250
244
|
Monitoring: ~/.claude ~/.gemini ~/.codex ~/.openclaw
|
|
251
245
|
|
|
252
246
|
[14:32:01] New agent detected → ~/.gemini/agents/planner.md
|
|
@@ -266,10 +260,10 @@ Choose the active scope before running sync, watch, status, or the visualizer:
|
|
|
266
260
|
|
|
267
261
|
```bash
|
|
268
262
|
# Use the current project workspace registry
|
|
269
|
-
|
|
263
|
+
wasla config --scope workspace
|
|
270
264
|
|
|
271
265
|
# Use the user-level registry across projects
|
|
272
|
-
|
|
266
|
+
wasla config --scope user
|
|
273
267
|
```
|
|
274
268
|
|
|
275
269
|
All other commands use the saved scope automatically. They do not accept `--scope`.
|
|
@@ -279,7 +273,7 @@ All other commands use the saved scope automatically. They do not accept `--scop
|
|
|
279
273
|
### Status — see everything and where it lives
|
|
280
274
|
|
|
281
275
|
```bash
|
|
282
|
-
|
|
276
|
+
wasla status
|
|
283
277
|
```
|
|
284
278
|
|
|
285
279
|
```
|
|
@@ -321,55 +315,55 @@ review-pr command openclaw claude ✔ gemini ✔ codex ✔ her
|
|
|
321
315
|
|
|
322
316
|
## 🗃️ Registry Storage
|
|
323
317
|
|
|
324
|
-
|
|
318
|
+
Wasla keeps its own state separately from all orchestrators. You choose the active scope explicitly before the first sync:
|
|
325
319
|
|
|
326
320
|
**User-level** (available across all your projects):
|
|
327
321
|
```
|
|
328
|
-
~/.
|
|
322
|
+
~/.wasla/
|
|
329
323
|
├── registry.json ← user-scope assets and stub locations
|
|
330
324
|
└── config.json ← active scope preference
|
|
331
325
|
```
|
|
332
326
|
|
|
333
327
|
**Workspace-level** (scoped to current project only):
|
|
334
328
|
```
|
|
335
|
-
.
|
|
329
|
+
.wasla/
|
|
336
330
|
└── registry.json ← workspace-scope assets and stub locations
|
|
337
331
|
```
|
|
338
332
|
|
|
339
333
|
Switch anytime:
|
|
340
334
|
```bash
|
|
341
|
-
|
|
342
|
-
|
|
335
|
+
wasla config --scope workspace
|
|
336
|
+
wasla config --scope user
|
|
343
337
|
```
|
|
344
338
|
|
|
345
339
|
---
|
|
346
340
|
|
|
347
341
|
## 🌱 Gradual Centralization
|
|
348
342
|
|
|
349
|
-
|
|
343
|
+
Wasla respects the **zero-friction promise**: your agents live where they were born. You don't need to learn a new canonical location on day one.
|
|
350
344
|
|
|
351
|
-
But over time,
|
|
345
|
+
But over time, Wasla offers a path toward centralization — for portability, backup, and eventually team sharing.
|
|
352
346
|
|
|
353
347
|
```
|
|
354
348
|
Day 1 — Agents live in ~/.claude/, ~/.gemini/, ~/.codex/
|
|
355
|
-
|
|
349
|
+
Wasla syncs them via stubs. You don't change anything.
|
|
356
350
|
|
|
357
351
|
Over time — You discover agents scattered across 5 tool directories.
|
|
358
|
-
You run:
|
|
359
|
-
Now researcher lives in ~/.
|
|
352
|
+
You run: wasla migrate researcher --to ~/.wasla/
|
|
353
|
+
Now researcher lives in ~/.wasla/ and stubs point there.
|
|
360
354
|
|
|
361
|
-
Later — All your agents are in ~/.
|
|
362
|
-
Backup is:
|
|
363
|
-
New machine is:
|
|
355
|
+
Later — All your agents are in ~/.wasla/.
|
|
356
|
+
Backup is: wasla export
|
|
357
|
+
New machine is: wasla import backup.tar
|
|
364
358
|
```
|
|
365
359
|
|
|
366
360
|
**Commands:**
|
|
367
361
|
|
|
368
362
|
```bash
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
363
|
+
wasla status # see where every asset lives today
|
|
364
|
+
wasla migrate <name> --to ~/.wasla/ # optionally move an asset to central location
|
|
365
|
+
wasla export # bundle everything for backup or new machine
|
|
366
|
+
wasla import backup.tar # restore on a new machine
|
|
373
367
|
```
|
|
374
368
|
|
|
375
369
|
Nothing is forced. Centralization is a convenience, not a requirement.
|
|
@@ -379,7 +373,7 @@ Nothing is forced. Centralization is a convenience, not a requirement.
|
|
|
379
373
|
## 🏗️ Project Structure
|
|
380
374
|
|
|
381
375
|
```
|
|
382
|
-
wasla
|
|
376
|
+
wasla/
|
|
383
377
|
├── apps/
|
|
384
378
|
│ ├── cli/src/ # CLI commands and visualizer server
|
|
385
379
|
│ └── visualizer/src/ # React visualizer
|
|
@@ -397,12 +391,10 @@ wasla-genie/
|
|
|
397
391
|
|
|
398
392
|
---
|
|
399
393
|
|
|
400
|
-
## 🌍 Why "
|
|
394
|
+
## 🌍 Why "Wasla"?
|
|
401
395
|
|
|
402
396
|
**Wasla (وصلة)** is Arabic for *connection* — the act of joining what was always separate.
|
|
403
397
|
|
|
404
|
-
**Genie** — it appears when summoned, connects what you need, and watches quietly in the background until called again.
|
|
405
|
-
|
|
406
398
|
Your agents live where they were born.
|
|
407
399
|
Your tools see everything.
|
|
408
400
|
Nothing is ever duplicated.
|
|
@@ -412,8 +404,8 @@ Nothing is ever duplicated.
|
|
|
412
404
|
## 🤝 Contributing
|
|
413
405
|
|
|
414
406
|
```bash
|
|
415
|
-
git clone https://github.com/The-Untitled-Org/wasla
|
|
416
|
-
cd wasla
|
|
407
|
+
git clone https://github.com/The-Untitled-Org/wasla
|
|
408
|
+
cd wasla
|
|
417
409
|
npm install
|
|
418
410
|
npm run visualizer:install
|
|
419
411
|
npm run dev
|
|
@@ -434,7 +426,7 @@ MIT © [The Untitled Org](https://github.com/The-Untitled-Org)
|
|
|
434
426
|
<div align="center">
|
|
435
427
|
|
|
436
428
|
**Your agents live where they were born.**
|
|
437
|
-
**
|
|
429
|
+
**Wasla makes sure every tool can find them.**
|
|
438
430
|
|
|
439
431
|
⭐ Star this repo if you are tired of copy-pasting the same config into five different tools.
|
|
440
432
|
|
|
@@ -13,11 +13,11 @@ function color(text, ...codes) {
|
|
|
13
13
|
}
|
|
14
14
|
export function banner() {
|
|
15
15
|
console.log(color(`
|
|
16
|
-
__ __ _
|
|
17
|
-
\\ \\ / /_ _ ___| | __ _
|
|
18
|
-
\\ \\ /\\ / / _\` / __| |/ _\` |
|
|
19
|
-
\\ V V / (_| \\__ \\ | (_| |
|
|
20
|
-
\\_/\\_/ \\__,_|___/_|\\__,_
|
|
16
|
+
__ __ _
|
|
17
|
+
\\ \\ / /_ _ ___| | __ _
|
|
18
|
+
\\ \\ /\\ / / _\` / __| |/ _\` |
|
|
19
|
+
\\ V V / (_| \\__ \\ | (_| |
|
|
20
|
+
\\_/\\_/ \\__,_|___/_|\\__,_|
|
|
21
21
|
`, ansi.bold, ansi.cyan));
|
|
22
22
|
}
|
|
23
23
|
export function success(message) {
|
|
@@ -27,7 +27,7 @@ export async function configCommand(options) {
|
|
|
27
27
|
const response = await prompts({
|
|
28
28
|
type: 'select',
|
|
29
29
|
name: 'scope',
|
|
30
|
-
message: 'Where should
|
|
30
|
+
message: 'Where should Wasla store and sync assets?',
|
|
31
31
|
choices: [
|
|
32
32
|
{ title: 'Workspace - current project only', value: 'workspace' },
|
|
33
33
|
{ title: 'User - available across all projects', value: 'user' },
|
|
@@ -2,7 +2,7 @@ import { section, success, error, highlight, spacer } from '../cli-output.js';
|
|
|
2
2
|
import { readConfiguredScope } from '#shared/config.js';
|
|
3
3
|
export async function installCommand() {
|
|
4
4
|
try {
|
|
5
|
-
section('Preparing
|
|
5
|
+
section('Preparing Wasla CLI...');
|
|
6
6
|
spacer();
|
|
7
7
|
const scope = await readConfiguredScope();
|
|
8
8
|
if (scope) {
|
|
@@ -10,8 +10,8 @@ export async function installCommand() {
|
|
|
10
10
|
}
|
|
11
11
|
else {
|
|
12
12
|
console.log('Choose a scope before running sync:');
|
|
13
|
-
console.log('
|
|
14
|
-
console.log('
|
|
13
|
+
console.log(' wasla config --scope user');
|
|
14
|
+
console.log(' wasla config --scope workspace');
|
|
15
15
|
}
|
|
16
16
|
spacer();
|
|
17
17
|
highlight('CLI setup complete!');
|
|
@@ -19,9 +19,9 @@ export async function installCommand() {
|
|
|
19
19
|
console.log('This command does not write skills into Claude, Gemini, or other tools.');
|
|
20
20
|
console.log('');
|
|
21
21
|
console.log('Common commands:');
|
|
22
|
-
console.log('
|
|
23
|
-
console.log('
|
|
24
|
-
console.log('
|
|
22
|
+
console.log(' wasla sync');
|
|
23
|
+
console.log(' wasla sync-to --from gemini --to claude');
|
|
24
|
+
console.log(' wasla register # optional: add Wasla helper skills to tools');
|
|
25
25
|
console.log('');
|
|
26
26
|
}
|
|
27
27
|
catch (err) {
|
|
@@ -35,7 +35,7 @@ export async function registerCommand(options = {}) {
|
|
|
35
35
|
targets = requested.map((name) => installedByName.get(name));
|
|
36
36
|
}
|
|
37
37
|
spacer();
|
|
38
|
-
section('Registering
|
|
38
|
+
section('Registering Wasla helper skills...');
|
|
39
39
|
spacer();
|
|
40
40
|
await ensureDir(getRegistryDir(scope));
|
|
41
41
|
for (const adapter of targets) {
|
|
@@ -9,7 +9,7 @@ export async function statusCommand() {
|
|
|
9
9
|
const scope = await requireConfiguredScope();
|
|
10
10
|
const registryPath = getRegistryPath(scope);
|
|
11
11
|
if (!(await fileExists(registryPath))) {
|
|
12
|
-
error('Registry not found. Run:
|
|
12
|
+
error('Registry not found. Run: wasla sync');
|
|
13
13
|
process.exit(1);
|
|
14
14
|
}
|
|
15
15
|
const registry = new RegistryManager(scope);
|
|
@@ -10,8 +10,8 @@ export async function syncToCommand(options) {
|
|
|
10
10
|
const to = options.to;
|
|
11
11
|
if (!from || !to) {
|
|
12
12
|
error('Error: --from and --to are required');
|
|
13
|
-
console.log('Usage:
|
|
14
|
-
console.log('Example:
|
|
13
|
+
console.log('Usage: wasla sync-to --from <source> --to <target>');
|
|
14
|
+
console.log('Example: wasla sync-to --from gemini --to claude');
|
|
15
15
|
process.exit(1);
|
|
16
16
|
}
|
|
17
17
|
const targets = to.split(',').map((t) => t.trim());
|
|
@@ -24,7 +24,7 @@ export async function watchCommand() {
|
|
|
24
24
|
ignored: [
|
|
25
25
|
/(^|[\/\\])node_modules([\/\\]|$)/,
|
|
26
26
|
/(^|[\/\\])\.git([\/\\]|$)/,
|
|
27
|
-
/(^|[\/\\])\.
|
|
27
|
+
/(^|[\/\\])\.wasla([\/\\]|$)/,
|
|
28
28
|
/(^|[\/\\])dist([\/\\]|$)/,
|
|
29
29
|
/(^|[\/\\])output([\/\\]|$)/,
|
|
30
30
|
],
|
|
@@ -27,13 +27,13 @@ function readPackageVersion(moduleUrl) {
|
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
program
|
|
30
|
-
.name('
|
|
30
|
+
.name('wasla')
|
|
31
31
|
.description('Universal synchronization layer for AI agent orchestrators')
|
|
32
32
|
.version(readPackageVersion(import.meta.url));
|
|
33
|
-
program.addCommand(new Command('install').description('Prepare
|
|
33
|
+
program.addCommand(new Command('install').description('Prepare Wasla CLI state').action(installCommand));
|
|
34
34
|
program.addCommand(new Command('register')
|
|
35
35
|
.option('--to <targets>', 'Target provider(s), comma-separated. Example: claude,gemini')
|
|
36
|
-
.description('Register
|
|
36
|
+
.description('Register Wasla helper skills inside installed AI tools')
|
|
37
37
|
.action((options) => registerCommand(options)));
|
|
38
38
|
program.addCommand(new Command('sync')
|
|
39
39
|
.description('Scan and sync agents/MCPs across tools')
|
|
@@ -49,7 +49,7 @@ program.addCommand(new Command('status')
|
|
|
49
49
|
program.addCommand(new Command('config')
|
|
50
50
|
.option('--scope <scope>', 'Set scope to user or workspace')
|
|
51
51
|
.option('--show', 'Show current config')
|
|
52
|
-
.description('Configure
|
|
52
|
+
.description('Configure Wasla settings')
|
|
53
53
|
.action(async (options) => {
|
|
54
54
|
await configCommand(options);
|
|
55
55
|
}));
|
|
@@ -18,7 +18,7 @@ async function getEntityContent(scope, type, name, providerId) {
|
|
|
18
18
|
const scanner = new Scanner(scope);
|
|
19
19
|
await scanner.initialize();
|
|
20
20
|
const assetType = mapEntityType(type);
|
|
21
|
-
const discovered = providerId === '
|
|
21
|
+
const discovered = providerId === 'wasla'
|
|
22
22
|
? await scanner.scanAllTools([assetType])
|
|
23
23
|
: await scanner.scanTool(providerId, [assetType]);
|
|
24
24
|
const target = discovered
|
|
@@ -49,8 +49,7 @@ function isAllowedOrigin(origin, port) {
|
|
|
49
49
|
return origin === `http://127.0.0.1:${port}` || origin === `http://localhost:${port}`;
|
|
50
50
|
}
|
|
51
51
|
function isKnownProvider(scope, providerId) {
|
|
52
|
-
return (providerId === '
|
|
53
|
-
getAllAdapters(scope).some((adapter) => adapter.name === providerId));
|
|
52
|
+
return (providerId === 'wasla' || getAllAdapters(scope).some((adapter) => adapter.name === providerId));
|
|
54
53
|
}
|
|
55
54
|
function mapEntityType(type) {
|
|
56
55
|
if (type === 'instruction')
|
|
@@ -88,14 +87,14 @@ function openBrowser(url) {
|
|
|
88
87
|
exec(`xdg-open "${url}"`);
|
|
89
88
|
}
|
|
90
89
|
export const PROVIDER_ICONS = {
|
|
91
|
-
|
|
92
|
-
claude: '
|
|
93
|
-
gemini: '
|
|
94
|
-
cursor: '
|
|
95
|
-
opencode: '
|
|
96
|
-
openclaw: '
|
|
97
|
-
'github-copilot': '
|
|
98
|
-
'github-copilot-cli': '
|
|
90
|
+
wasla: '/logo.png',
|
|
91
|
+
claude: '/img/claude.png',
|
|
92
|
+
gemini: '/img/gemini.png',
|
|
93
|
+
cursor: '/img/cursor.png',
|
|
94
|
+
opencode: '/img/opencode.png',
|
|
95
|
+
openclaw: '/img/openclaw.png',
|
|
96
|
+
'github-copilot': '/img/copilot.png',
|
|
97
|
+
'github-copilot-cli': '/img/copilot-cli.png',
|
|
99
98
|
};
|
|
100
99
|
async function buildConfig(scope) {
|
|
101
100
|
const scanner = new Scanner(scope);
|
|
@@ -105,9 +104,9 @@ async function buildConfig(scope) {
|
|
|
105
104
|
const installedNames = new Set(installed.map((adapter) => adapter.name));
|
|
106
105
|
const providers = [
|
|
107
106
|
{
|
|
108
|
-
id: '
|
|
109
|
-
title: '
|
|
110
|
-
iconUrl: PROVIDER_ICONS.
|
|
107
|
+
id: 'wasla',
|
|
108
|
+
title: 'Wasla',
|
|
109
|
+
iconUrl: PROVIDER_ICONS.wasla,
|
|
111
110
|
isHub: true,
|
|
112
111
|
isInstalled: true,
|
|
113
112
|
},
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export declare abstract class BaseAdapter implements
|
|
1
|
+
import { WaslaAdapter, Asset, AssetFormat } from '#core/types.js';
|
|
2
|
+
export declare abstract class BaseAdapter implements WaslaAdapter {
|
|
3
3
|
abstract name: string;
|
|
4
4
|
abstract displayName: string;
|
|
5
5
|
abstract mcpKey: string;
|
|
@@ -65,9 +65,9 @@ export class ClaudeAdapter extends BaseAdapter {
|
|
|
65
65
|
await writeText(targetPath, content);
|
|
66
66
|
}
|
|
67
67
|
async installSkill() {
|
|
68
|
-
// Write a
|
|
68
|
+
// Write a Wasla skill into Claude's native skills directory.
|
|
69
69
|
// We do NOT touch CLAUDE.md — that file belongs to the user.
|
|
70
|
-
const skillDir = join(this.paths.skill, '
|
|
70
|
+
const skillDir = join(this.paths.skill, 'wasla');
|
|
71
71
|
await ensureDir(skillDir);
|
|
72
72
|
const skillPath = join(skillDir, 'SKILL.md');
|
|
73
73
|
if (await fileExists(skillPath)) {
|
|
@@ -75,19 +75,19 @@ export class ClaudeAdapter extends BaseAdapter {
|
|
|
75
75
|
}
|
|
76
76
|
const skillContent = `---
|
|
77
77
|
description: >
|
|
78
|
-
Runs
|
|
78
|
+
Runs Wasla CLI commands to sync, inspect, or manage agents and MCPs
|
|
79
79
|
across AI orchestrators. Use when asked to sync tools, check sync status,
|
|
80
|
-
install
|
|
80
|
+
install Wasla, or troubleshoot why an agent isn't appearing in a tool.
|
|
81
81
|
---
|
|
82
82
|
|
|
83
|
-
#
|
|
83
|
+
# Wasla Operator
|
|
84
84
|
|
|
85
|
-
Use the \`
|
|
85
|
+
Use the \`wasla\` CLI to sync agents and MCPs across all installed AI tools.
|
|
86
86
|
|
|
87
87
|
\`\`\`bash
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
88
|
+
wasla sync # Mirror agents across all tools
|
|
89
|
+
wasla status # Show registry state
|
|
90
|
+
wasla watch # Auto-sync on file changes
|
|
91
91
|
\`\`\`
|
|
92
92
|
`;
|
|
93
93
|
await writeText(skillPath, skillContent);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export declare function getAdapter(toolName: string, scope?: 'user' | 'workspace'):
|
|
3
|
-
export declare function getInstalledAdapters(scope?: 'user' | 'workspace'): Promise<
|
|
4
|
-
export declare function getAllAdapters(scope?: 'user' | 'workspace'):
|
|
1
|
+
import { WaslaAdapter } from '#core/types.js';
|
|
2
|
+
export declare function getAdapter(toolName: string, scope?: 'user' | 'workspace'): WaslaAdapter;
|
|
3
|
+
export declare function getInstalledAdapters(scope?: 'user' | 'workspace'): Promise<WaslaAdapter[]>;
|
|
4
|
+
export declare function getAllAdapters(scope?: 'user' | 'workspace'): WaslaAdapter[];
|
|
@@ -64,30 +64,30 @@ export class GeminiAdapter extends BaseAdapter {
|
|
|
64
64
|
}
|
|
65
65
|
async installSkill() {
|
|
66
66
|
// Create the skills/ directory (Gemini CLI's native skill location) and
|
|
67
|
-
// write a
|
|
67
|
+
// write a Wasla skill file so Gemini knows how to run sync commands.
|
|
68
68
|
// We do NOT touch GEMINI.md — that file belongs to the user.
|
|
69
|
-
const skillDir = join(this.paths.skill, '
|
|
69
|
+
const skillDir = join(this.paths.skill, 'wasla');
|
|
70
70
|
await ensureDir(skillDir);
|
|
71
71
|
const skillPath = join(skillDir, 'SKILL.md');
|
|
72
72
|
if (await fileExists(skillPath)) {
|
|
73
73
|
return; // already installed, idempotent
|
|
74
74
|
}
|
|
75
75
|
const skillContent = `---
|
|
76
|
-
name:
|
|
76
|
+
name: wasla
|
|
77
77
|
description: >
|
|
78
|
-
Runs
|
|
78
|
+
Runs Wasla CLI commands to sync, inspect, or manage agents and MCPs
|
|
79
79
|
across AI orchestrators. Use when asked to sync tools, check sync status,
|
|
80
|
-
install
|
|
80
|
+
install Wasla, or troubleshoot why an agent isn't appearing in a tool.
|
|
81
81
|
---
|
|
82
82
|
|
|
83
|
-
#
|
|
83
|
+
# Wasla Operator
|
|
84
84
|
|
|
85
|
-
Use the \`
|
|
85
|
+
Use the \`wasla\` CLI to sync agents and MCPs across all installed AI tools.
|
|
86
86
|
|
|
87
87
|
\`\`\`bash
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
88
|
+
wasla sync # Mirror agents across all tools
|
|
89
|
+
wasla status # Show registry state
|
|
90
|
+
wasla watch # Auto-sync on file changes
|
|
91
91
|
\`\`\`
|
|
92
92
|
`;
|
|
93
93
|
await writeText(skillPath, skillContent);
|
|
@@ -10,17 +10,17 @@ export async function readConfiguredScope() {
|
|
|
10
10
|
return null;
|
|
11
11
|
const config = await readJSON(configPath);
|
|
12
12
|
if (typeof config !== 'object' || config === null || typeof config.scope !== 'string') {
|
|
13
|
-
throw new Error(`Invalid scope in ${configPath}. Run:
|
|
13
|
+
throw new Error(`Invalid scope in ${configPath}. Run: wasla config --scope <scope>`);
|
|
14
14
|
}
|
|
15
15
|
if (config.scope !== 'user' && config.scope !== 'workspace') {
|
|
16
|
-
throw new Error(`Invalid scope in ${configPath}. Run:
|
|
16
|
+
throw new Error(`Invalid scope in ${configPath}. Run: wasla config --scope <scope>`);
|
|
17
17
|
}
|
|
18
18
|
return config.scope;
|
|
19
19
|
}
|
|
20
20
|
export async function requireConfiguredScope() {
|
|
21
21
|
const scope = await readConfiguredScope();
|
|
22
22
|
if (!scope) {
|
|
23
|
-
throw new Error('Scope is not configured. Run:
|
|
23
|
+
throw new Error('Scope is not configured. Run: wasla config --scope <user|workspace>');
|
|
24
24
|
}
|
|
25
25
|
return scope;
|
|
26
26
|
}
|
|
@@ -11,18 +11,18 @@ export function getRegistryPath(scope) {
|
|
|
11
11
|
return resolve(`output/tests/${scope}-registry.json`);
|
|
12
12
|
}
|
|
13
13
|
if (scope === 'user') {
|
|
14
|
-
return expandTilde('~/.
|
|
14
|
+
return expandTilde('~/.wasla/registry.json');
|
|
15
15
|
}
|
|
16
|
-
return resolve('.
|
|
16
|
+
return resolve('.wasla/registry.json');
|
|
17
17
|
}
|
|
18
18
|
export function getRegistryDir(scope) {
|
|
19
19
|
if (process.env.NODE_ENV === 'test') {
|
|
20
20
|
return resolve('output/tests');
|
|
21
21
|
}
|
|
22
22
|
if (scope === 'user') {
|
|
23
|
-
return expandTilde('~/.
|
|
23
|
+
return expandTilde('~/.wasla');
|
|
24
24
|
}
|
|
25
|
-
return resolve('.
|
|
25
|
+
return resolve('.wasla');
|
|
26
26
|
}
|
|
27
27
|
export function getToolMarkers(scope = 'user') {
|
|
28
28
|
if (scope === 'workspace') {
|