@untitled-devs/wasla 0.1.2 → 0.1.3
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 +20 -15
- package/dist/cli/commands/config.d.ts +1 -1
- package/dist/cli/commands/config.js +38 -41
- package/dist/cli/commands/install.js +10 -5
- package/dist/cli/commands/register.js +4 -2
- package/dist/cli/commands/status.d.ts +1 -5
- package/dist/cli/commands/status.js +15 -12
- package/dist/cli/commands/sync-to.d.ts +0 -1
- package/dist/cli/commands/sync-to.js +3 -2
- package/dist/cli/commands/sync.d.ts +2 -2
- package/dist/cli/commands/sync.js +33 -10
- package/dist/cli/commands/visualizer.d.ts +0 -1
- package/dist/cli/commands/visualizer.js +2 -1
- package/dist/cli/commands/watch.d.ts +1 -5
- package/dist/cli/commands/watch.js +3 -2
- package/dist/cli/index.js +11 -13
- package/dist/core/scanner.js +8 -3
- package/dist/core/types.d.ts +0 -1
- package/dist/utils/cli-output.d.ts +4 -0
- package/dist/utils/cli-output.js +60 -6
- package/dist/utils/config.d.ts +6 -0
- package/dist/utils/config.js +34 -0
- package/dist/utils/fs.js +13 -7
- package/package.json +49 -46
package/README.md
CHANGED
|
@@ -121,15 +121,18 @@ The same pattern applies across every asset type:
|
|
|
121
121
|
WaslaGenie is cross-platform via `npx` — no global install required:
|
|
122
122
|
|
|
123
123
|
```bash
|
|
124
|
+
npx @untitled-devs/wasla config --scope workspace
|
|
124
125
|
npx @untitled-devs/wasla sync
|
|
125
126
|
```
|
|
126
127
|
|
|
127
|
-
|
|
128
|
+
Choose `workspace` or `user` once before running operational commands. This runs the CLI directly.
|
|
129
|
+
It does not register helper skills inside Claude, Gemini, or other tools.
|
|
128
130
|
|
|
129
131
|
**Or install globally:**
|
|
130
132
|
|
|
131
133
|
```bash
|
|
132
134
|
npm install -g @untitled-devs/wasla
|
|
135
|
+
waslagenie config --scope workspace
|
|
133
136
|
waslagenie sync
|
|
134
137
|
```
|
|
135
138
|
|
|
@@ -178,10 +181,10 @@ npx @untitled-devs/wasla visualizer
|
|
|
178
181
|
### You (developing this repo)
|
|
179
182
|
|
|
180
183
|
```bash
|
|
181
|
-
# Build + run sync
|
|
184
|
+
# Build + run sync using your configured scope
|
|
182
185
|
npm run sync
|
|
183
186
|
|
|
184
|
-
# Build + run watch
|
|
187
|
+
# Build + run watch using your configured scope
|
|
185
188
|
npm run watch
|
|
186
189
|
```
|
|
187
190
|
|
|
@@ -257,14 +260,18 @@ No restart. No manual trigger. The moment something changes — it's everywhere.
|
|
|
257
260
|
|
|
258
261
|
### Scope — workspace or user level
|
|
259
262
|
|
|
263
|
+
Choose the active scope before running sync, watch, status, or the visualizer:
|
|
264
|
+
|
|
260
265
|
```bash
|
|
261
|
-
#
|
|
262
|
-
waslagenie
|
|
266
|
+
# Use the current project workspace registry
|
|
267
|
+
waslagenie config --scope workspace
|
|
263
268
|
|
|
264
|
-
#
|
|
265
|
-
waslagenie
|
|
269
|
+
# Use the user-level registry across projects
|
|
270
|
+
waslagenie config --scope user
|
|
266
271
|
```
|
|
267
272
|
|
|
273
|
+
All other commands use the saved scope automatically. They do not accept `--scope`.
|
|
274
|
+
|
|
268
275
|
---
|
|
269
276
|
|
|
270
277
|
### Status — see everything and where it lives
|
|
@@ -312,22 +319,19 @@ review-pr command openclaw claude ✔ gemini ✔ codex ✔ her
|
|
|
312
319
|
|
|
313
320
|
## 🗃️ Registry Storage
|
|
314
321
|
|
|
315
|
-
WaslaGenie keeps its own state separately from all orchestrators. You choose the scope
|
|
322
|
+
WaslaGenie keeps its own state separately from all orchestrators. You choose the active scope explicitly before the first sync:
|
|
316
323
|
|
|
317
|
-
**User-level** (
|
|
324
|
+
**User-level** (available across all your projects):
|
|
318
325
|
```
|
|
319
326
|
~/.waslagenie/
|
|
320
|
-
├── registry.json ←
|
|
321
|
-
|
|
322
|
-
└── config.json ← your scope and preferences
|
|
327
|
+
├── registry.json ← user-scope assets and stub locations
|
|
328
|
+
└── config.json ← active scope preference
|
|
323
329
|
```
|
|
324
330
|
|
|
325
331
|
**Workspace-level** (scoped to current project only):
|
|
326
332
|
```
|
|
327
333
|
.waslagenie/
|
|
328
|
-
|
|
329
|
-
├── stubs/
|
|
330
|
-
└── config.json
|
|
334
|
+
└── registry.json ← workspace-scope assets and stub locations
|
|
331
335
|
```
|
|
332
336
|
|
|
333
337
|
Switch anytime:
|
|
@@ -419,6 +423,7 @@ npm run dev
|
|
|
419
423
|
|
|
420
424
|
- [Contributing Guide](CONTRIBUTING.md)
|
|
421
425
|
- [Architecture Docs](docs/docs/architecture/index.md)
|
|
426
|
+
- [Release Guide](RELEASING.md)
|
|
422
427
|
|
|
423
428
|
---
|
|
424
429
|
|
|
@@ -1,26 +1,16 @@
|
|
|
1
|
-
import { RegistryManager } from '../../core/registry.js';
|
|
2
1
|
import { section, success, error, spacer, info } from '../../utils/cli-output.js';
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
2
|
+
import prompts from 'prompts';
|
|
3
|
+
import { getConfigPath, getConfiguredRegistryPath, readConfiguredScope, writeConfiguredScope, } from '../../utils/config.js';
|
|
5
4
|
export async function configCommand(options) {
|
|
6
5
|
try {
|
|
7
|
-
|
|
8
|
-
const userPath = getRegistryPath('user');
|
|
9
|
-
const workspacePath = getRegistryPath('workspace');
|
|
10
|
-
const userExists = await fileExists(userPath);
|
|
11
|
-
const workspaceExists = await fileExists(workspacePath);
|
|
12
|
-
let currentScope = 'user';
|
|
13
|
-
if (workspaceExists && !userExists) {
|
|
14
|
-
currentScope = 'workspace';
|
|
15
|
-
}
|
|
6
|
+
const currentScope = await readConfiguredScope();
|
|
16
7
|
// Show current config
|
|
17
8
|
if (options.show) {
|
|
18
9
|
section('Current Configuration');
|
|
19
10
|
spacer();
|
|
20
|
-
|
|
21
|
-
info(`Registry: ${getRegistryPath(currentScope)}`);
|
|
11
|
+
showConfig(currentScope);
|
|
22
12
|
spacer();
|
|
23
|
-
return;
|
|
13
|
+
return true;
|
|
24
14
|
}
|
|
25
15
|
// Change scope if requested
|
|
26
16
|
if (options.scope) {
|
|
@@ -29,37 +19,44 @@ export async function configCommand(options) {
|
|
|
29
19
|
error('Invalid scope. Use: user or workspace');
|
|
30
20
|
process.exit(1);
|
|
31
21
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
if ((currentScope === 'user' && userExists) ||
|
|
35
|
-
(currentScope === 'workspace' && workspaceExists)) {
|
|
36
|
-
await registry.load();
|
|
37
|
-
}
|
|
38
|
-
else {
|
|
39
|
-
// Create empty registry
|
|
40
|
-
await registry.load();
|
|
41
|
-
}
|
|
42
|
-
// Change scope and save
|
|
43
|
-
registry.setScope(newScope);
|
|
44
|
-
await registry.save();
|
|
45
|
-
success(`Scope changed to: ${newScope}`);
|
|
46
|
-
info(`Registry: ${getRegistryPath(newScope)}`);
|
|
47
|
-
spacer();
|
|
48
|
-
return;
|
|
22
|
+
await saveScope(newScope);
|
|
23
|
+
return true;
|
|
49
24
|
}
|
|
50
|
-
|
|
51
|
-
section('Current Configuration');
|
|
25
|
+
section('Configure Scope');
|
|
52
26
|
spacer();
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
27
|
+
const response = await prompts({
|
|
28
|
+
type: 'select',
|
|
29
|
+
name: 'scope',
|
|
30
|
+
message: 'Where should WaslaGenie store and sync assets?',
|
|
31
|
+
choices: [
|
|
32
|
+
{ title: 'Workspace - current project only', value: 'workspace' },
|
|
33
|
+
{ title: 'User - available across all projects', value: 'user' },
|
|
34
|
+
],
|
|
35
|
+
initial: currentScope === 'user' ? 1 : 0,
|
|
36
|
+
});
|
|
37
|
+
const scope = response.scope;
|
|
38
|
+
if (!scope) {
|
|
39
|
+
info('Configuration cancelled');
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
await saveScope(scope);
|
|
43
|
+
return true;
|
|
60
44
|
}
|
|
61
45
|
catch (err) {
|
|
62
46
|
error(`Config failed: ${err}`);
|
|
63
47
|
process.exit(1);
|
|
64
48
|
}
|
|
65
49
|
}
|
|
50
|
+
async function saveScope(scope) {
|
|
51
|
+
await writeConfiguredScope(scope);
|
|
52
|
+
success(`Scope changed to: ${scope}`);
|
|
53
|
+
info(`Config: ${getConfigPath()}`);
|
|
54
|
+
info(`Registry: ${getConfiguredRegistryPath(scope)}`);
|
|
55
|
+
spacer();
|
|
56
|
+
}
|
|
57
|
+
function showConfig(scope) {
|
|
58
|
+
info(`Scope: ${scope ?? 'not configured'}`);
|
|
59
|
+
info(`Config: ${getConfigPath()}`);
|
|
60
|
+
if (scope)
|
|
61
|
+
info(`Registry: ${getConfiguredRegistryPath(scope)}`);
|
|
62
|
+
}
|
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
import { section, success, error, highlight, spacer } from '../../utils/cli-output.js';
|
|
2
|
-
import {
|
|
3
|
-
import { ensureDir } from '../../utils/fs.js';
|
|
2
|
+
import { readConfiguredScope } from '../../utils/config.js';
|
|
4
3
|
export async function installCommand() {
|
|
5
4
|
try {
|
|
6
5
|
section('Preparing WaslaGenie CLI...');
|
|
7
6
|
spacer();
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
const scope = await readConfiguredScope();
|
|
8
|
+
if (scope) {
|
|
9
|
+
success(`Scope configured: ${scope}`);
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
console.log('Choose a scope before running sync:');
|
|
13
|
+
console.log(' waslagenie config --scope user');
|
|
14
|
+
console.log(' waslagenie config --scope workspace');
|
|
15
|
+
}
|
|
11
16
|
spacer();
|
|
12
17
|
highlight('CLI setup complete!');
|
|
13
18
|
console.log('');
|
|
@@ -2,11 +2,13 @@ import { getInstalledAdapters } from '../../adapters/factory.js';
|
|
|
2
2
|
import { section, success, error, warning, highlight, spacer } from '../../utils/cli-output.js';
|
|
3
3
|
import { getRegistryDir } from '../../utils/paths.js';
|
|
4
4
|
import { ensureDir } from '../../utils/fs.js';
|
|
5
|
+
import { requireConfiguredScope } from '../../utils/config.js';
|
|
5
6
|
export async function registerCommand(options = {}) {
|
|
6
7
|
try {
|
|
7
8
|
section('Detecting installed orchestrators...');
|
|
8
9
|
spacer();
|
|
9
|
-
const
|
|
10
|
+
const scope = await requireConfiguredScope();
|
|
11
|
+
const adapters = await getInstalledAdapters(scope);
|
|
10
12
|
if (adapters.length === 0) {
|
|
11
13
|
error('No supported orchestrators found');
|
|
12
14
|
warning('Please install Claude Code, Gemini CLI, or OpenCode first');
|
|
@@ -35,7 +37,7 @@ export async function registerCommand(options = {}) {
|
|
|
35
37
|
spacer();
|
|
36
38
|
section('Registering WaslaGenie helper skills...');
|
|
37
39
|
spacer();
|
|
38
|
-
await ensureDir(getRegistryDir(
|
|
40
|
+
await ensureDir(getRegistryDir(scope));
|
|
39
41
|
for (const adapter of targets) {
|
|
40
42
|
try {
|
|
41
43
|
await adapter.installSkill();
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { RegistryManager } from '../../core/registry.js';
|
|
2
|
-
import {
|
|
2
|
+
import { Scanner } from '../../core/scanner.js';
|
|
3
|
+
import { assetList, section, error, info, metric, spacer } from '../../utils/cli-output.js';
|
|
3
4
|
import { fileExists } from '../../utils/fs.js';
|
|
4
5
|
import { getRegistryPath } from '../../utils/paths.js';
|
|
5
|
-
|
|
6
|
+
import { requireConfiguredScope } from '../../utils/config.js';
|
|
7
|
+
export async function statusCommand() {
|
|
6
8
|
try {
|
|
7
|
-
const scope = (
|
|
9
|
+
const scope = await requireConfiguredScope();
|
|
8
10
|
const registryPath = getRegistryPath(scope);
|
|
9
11
|
if (!(await fileExists(registryPath))) {
|
|
10
12
|
error('Registry not found. Run: waslagenie sync');
|
|
@@ -13,21 +15,22 @@ export async function statusCommand(options) {
|
|
|
13
15
|
const registry = new RegistryManager(scope);
|
|
14
16
|
await registry.load();
|
|
15
17
|
const registryData = registry.get();
|
|
18
|
+
const installedTools = await new Scanner(scope).detectInstalledTools();
|
|
19
|
+
section('Registry status');
|
|
20
|
+
info(`Scope: ${scope}`);
|
|
21
|
+
info(`Registry: ${registryPath}`);
|
|
22
|
+
spacer();
|
|
23
|
+
metric('Assets', registryData.assets.length);
|
|
24
|
+
metric('Conflicts', registryData.conflicts.length);
|
|
16
25
|
if (registryData.assets.length === 0) {
|
|
26
|
+
spacer();
|
|
17
27
|
section('No assets synced yet');
|
|
18
28
|
spacer();
|
|
19
29
|
return;
|
|
20
30
|
}
|
|
21
|
-
section('Synced
|
|
22
|
-
spacer();
|
|
23
|
-
const rows = registryData.assets.map((asset) => [
|
|
24
|
-
asset.name,
|
|
25
|
-
asset.type,
|
|
26
|
-
asset.stubs.map((s) => s.tool).join(', ') || 'none',
|
|
27
|
-
new Date(asset.last_modified_at).toLocaleString(),
|
|
28
|
-
]);
|
|
29
|
-
table([['ASSET', 'TYPE', 'STUBS', 'LAST MODIFIED'], ...rows.map((row) => row.map(String))], [20, 8, 20, 24]);
|
|
31
|
+
section('Synced assets');
|
|
30
32
|
spacer();
|
|
33
|
+
assetList(registryData.assets, true, installedTools);
|
|
31
34
|
}
|
|
32
35
|
catch (err) {
|
|
33
36
|
error(`Status check failed: ${err}`);
|
|
@@ -2,14 +2,15 @@ import { RegistryManager } from '../../core/registry.js';
|
|
|
2
2
|
import { Scanner } from '../../core/scanner.js';
|
|
3
3
|
import { Syncer } from '../../syncer/index.js';
|
|
4
4
|
import { section, error, highlight, spacer } from '../../utils/cli-output.js';
|
|
5
|
+
import { requireConfiguredScope } from '../../utils/config.js';
|
|
5
6
|
export async function syncToCommand(options) {
|
|
6
7
|
try {
|
|
7
|
-
const scope = (
|
|
8
|
+
const scope = await requireConfiguredScope();
|
|
8
9
|
const from = options.from;
|
|
9
10
|
const to = options.to;
|
|
10
11
|
if (!from || !to) {
|
|
11
12
|
error('Error: --from and --to are required');
|
|
12
|
-
console.log('Usage: waslagenie sync-to --from <source> --to <target>
|
|
13
|
+
console.log('Usage: waslagenie sync-to --from <source> --to <target>');
|
|
13
14
|
console.log('Example: waslagenie sync-to --from gemini --to claude');
|
|
14
15
|
process.exit(1);
|
|
15
16
|
}
|
|
@@ -1,23 +1,46 @@
|
|
|
1
1
|
import { RegistryManager } from '../../core/registry.js';
|
|
2
2
|
import { Scanner } from '../../core/scanner.js';
|
|
3
3
|
import { Syncer } from '../../syncer/index.js';
|
|
4
|
-
import { section, error, highlight, spacer } from '../../utils/cli-output.js';
|
|
5
|
-
|
|
4
|
+
import { assetList, bulletPoint, section, error, highlight, info, metric, spacer, } from '../../utils/cli-output.js';
|
|
5
|
+
import { getConfiguredRegistryPath, requireConfiguredScope } from '../../utils/config.js';
|
|
6
|
+
import { configCommand } from './config.js';
|
|
7
|
+
export async function syncCommand(options = {}) {
|
|
6
8
|
try {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
+
if (options.promptForScope !== false && !(await configCommand({}))) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
const scope = await requireConfiguredScope();
|
|
13
|
+
section('Syncing assets');
|
|
14
|
+
info(`Scope: ${scope}`);
|
|
15
|
+
info(`Registry: ${getConfiguredRegistryPath(scope)}`);
|
|
9
16
|
spacer();
|
|
17
|
+
section('Scanning providers');
|
|
10
18
|
const registry = new RegistryManager(scope);
|
|
11
19
|
await registry.load();
|
|
12
20
|
const scanner = new Scanner(scope);
|
|
21
|
+
const installedTools = await scanner.detectInstalledTools();
|
|
22
|
+
info(`${installedTools.length} providers detected`);
|
|
23
|
+
for (const tool of installedTools) {
|
|
24
|
+
bulletPoint(tool, 1);
|
|
25
|
+
}
|
|
26
|
+
spacer();
|
|
13
27
|
const syncer = new Syncer(registry, scanner, scope);
|
|
14
|
-
const result = await syncer.sync(
|
|
28
|
+
const result = await syncer.sync(false);
|
|
29
|
+
spacer();
|
|
30
|
+
highlight('Sync complete');
|
|
31
|
+
spacer();
|
|
32
|
+
metric('Assets discovered', result.assetsDiscovered);
|
|
33
|
+
metric('Stubs written', result.stubsWritten);
|
|
34
|
+
metric('Stubs deleted', result.stubsDeleted);
|
|
15
35
|
spacer();
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
36
|
+
if (registry.get().assets.length === 0) {
|
|
37
|
+
info('No assets discovered');
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
section('Discovered assets');
|
|
41
|
+
spacer();
|
|
42
|
+
assetList(registry.get().assets, false, installedTools);
|
|
43
|
+
}
|
|
21
44
|
}
|
|
22
45
|
catch (err) {
|
|
23
46
|
error(`Sync failed: ${err}`);
|
|
@@ -10,6 +10,7 @@ import { RegistryManager } from '../../core/registry.js';
|
|
|
10
10
|
import { getInstalledAdapters } from '../../adapters/factory.js';
|
|
11
11
|
import { error, highlight, info, section, spacer } from '../../utils/cli-output.js';
|
|
12
12
|
import { Syncer } from '../../syncer/index.js';
|
|
13
|
+
import { requireConfiguredScope } from '../../utils/config.js';
|
|
13
14
|
export function resolveVisualizerDist(moduleUrl) {
|
|
14
15
|
return resolve(dirname(fileURLToPath(moduleUrl)), '../../../src/visualizer/dist');
|
|
15
16
|
}
|
|
@@ -138,7 +139,7 @@ function sendJson(res, statusCode, body) {
|
|
|
138
139
|
}
|
|
139
140
|
export async function visualizerCommand(options) {
|
|
140
141
|
try {
|
|
141
|
-
const scope = (
|
|
142
|
+
const scope = await requireConfiguredScope();
|
|
142
143
|
const host = options.host || '127.0.0.1';
|
|
143
144
|
const port = Number(options.port || 4072);
|
|
144
145
|
const shouldOpen = options.noOpen !== true;
|
|
@@ -4,9 +4,10 @@ import { Scanner } from '../../core/scanner.js';
|
|
|
4
4
|
import { Syncer } from '../../syncer/index.js';
|
|
5
5
|
import { getAllAdapters } from '../../adapters/factory.js';
|
|
6
6
|
import { section, success, error, info, spacer } from '../../utils/cli-output.js';
|
|
7
|
-
|
|
7
|
+
import { requireConfiguredScope } from '../../utils/config.js';
|
|
8
|
+
export async function watchCommand() {
|
|
8
9
|
try {
|
|
9
|
-
const scope = (
|
|
10
|
+
const scope = await requireConfiguredScope();
|
|
10
11
|
section('Watching for changes...');
|
|
11
12
|
spacer();
|
|
12
13
|
const registry = new RegistryManager(scope);
|
package/dist/cli/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from 'commander';
|
|
3
|
+
import { readFileSync } from 'fs';
|
|
3
4
|
import { installCommand } from './commands/install.js';
|
|
4
5
|
import { registerCommand } from './commands/register.js';
|
|
5
6
|
import { syncCommand } from './commands/sync.js';
|
|
@@ -8,51 +9,48 @@ import { statusCommand } from './commands/status.js';
|
|
|
8
9
|
import { configCommand } from './commands/config.js';
|
|
9
10
|
import { watchCommand } from './commands/watch.js';
|
|
10
11
|
import { visualizerCommand } from './commands/visualizer.js';
|
|
12
|
+
import { banner } from '../utils/cli-output.js';
|
|
11
13
|
const program = new Command();
|
|
14
|
+
const packageVersion = JSON.parse(readFileSync(new URL('../../package.json', import.meta.url), 'utf-8'));
|
|
12
15
|
program
|
|
13
16
|
.name('waslagenie')
|
|
14
17
|
.description('Universal synchronization layer for AI agent orchestrators')
|
|
15
|
-
.version(
|
|
18
|
+
.version(packageVersion.version);
|
|
16
19
|
program.addCommand(new Command('install').description('Prepare WaslaGenie CLI state').action(installCommand));
|
|
17
20
|
program.addCommand(new Command('register')
|
|
18
21
|
.option('--to <targets>', 'Target provider(s), comma-separated. Example: claude,gemini')
|
|
19
22
|
.description('Register WaslaGenie helper skills inside installed AI tools')
|
|
20
23
|
.action((options) => registerCommand(options)));
|
|
21
24
|
program.addCommand(new Command('sync')
|
|
22
|
-
.option('--scope <scope>', 'user or workspace', 'workspace')
|
|
23
25
|
.description('Scan and sync agents/MCPs across tools')
|
|
24
|
-
.action((
|
|
26
|
+
.action(() => syncCommand()));
|
|
25
27
|
program.addCommand(new Command('sync-to')
|
|
26
28
|
.option('--from <source>', 'Source tool (gemini, claude, etc.)')
|
|
27
29
|
.option('--to <targets>', 'Target tool(s), comma-separated')
|
|
28
|
-
.option('--scope <scope>', 'user or workspace', 'workspace')
|
|
29
30
|
.description('Sync agents/MCPs from one tool to specific target(s)')
|
|
30
31
|
.action((options) => syncToCommand(options)));
|
|
31
32
|
program.addCommand(new Command('status')
|
|
32
|
-
.option('--scope <scope>', 'user or workspace', 'workspace')
|
|
33
33
|
.description('Show all discovered assets and their sync state')
|
|
34
|
-
.action((
|
|
34
|
+
.action(() => statusCommand()));
|
|
35
35
|
program.addCommand(new Command('config')
|
|
36
36
|
.option('--scope <scope>', 'Set scope to user or workspace')
|
|
37
37
|
.option('--show', 'Show current config')
|
|
38
38
|
.description('Configure WaslaGenie settings')
|
|
39
|
-
.action((options) =>
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
.action((options) => watchCommand(options)));
|
|
39
|
+
.action(async (options) => {
|
|
40
|
+
await configCommand(options);
|
|
41
|
+
}));
|
|
42
|
+
program.addCommand(new Command('watch').description('Watch for changes and auto-sync').action(() => watchCommand()));
|
|
44
43
|
program.addCommand(new Command('visualizer')
|
|
45
|
-
.option('--scope <scope>', 'user or workspace', 'workspace')
|
|
46
44
|
.option('--host <host>', 'Host to bind', '127.0.0.1')
|
|
47
45
|
.option('--port <port>', 'Port to bind', '4072')
|
|
48
46
|
.option('--no-open', 'Do not open browser automatically')
|
|
49
47
|
.description('Open interactive sync visualizer with built-in backend')
|
|
50
48
|
.action((options) => visualizerCommand(options)));
|
|
51
49
|
program.addCommand(new Command('ui')
|
|
52
|
-
.option('--scope <scope>', 'user or workspace', 'workspace')
|
|
53
50
|
.option('--host <host>', 'Host to bind', '127.0.0.1')
|
|
54
51
|
.option('--port <port>', 'Port to bind', '4072')
|
|
55
52
|
.option('--no-open', 'Do not open browser automatically')
|
|
56
53
|
.description('Alias for `visualizer`')
|
|
57
54
|
.action((options) => visualizerCommand(options)));
|
|
55
|
+
banner();
|
|
58
56
|
program.parse(process.argv);
|
package/dist/core/scanner.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { fileExists, isDirectory, readJSON } from '../utils/fs.js';
|
|
2
|
-
import { join, relative
|
|
2
|
+
import { join, relative } from 'path';
|
|
3
3
|
import { getToolMarkers, getRegistryPath } from '../utils/paths.js';
|
|
4
4
|
import { stat, readdir } from 'fs/promises';
|
|
5
5
|
import { getAdapter } from '../adapters/factory.js';
|
|
@@ -203,13 +203,18 @@ export class Scanner {
|
|
|
203
203
|
extractAssetName(relativePathOrFileName) {
|
|
204
204
|
// For nested paths: waslagenie/SKILL.md -> waslagenie
|
|
205
205
|
// For flat files: researcher.md -> researcher
|
|
206
|
-
const parts = relativePathOrFileName.split(
|
|
206
|
+
const parts = relativePathOrFileName.split(/[/\\]/);
|
|
207
207
|
if (parts.length > 1) {
|
|
208
208
|
// Nested: return first directory
|
|
209
209
|
return parts[0];
|
|
210
210
|
}
|
|
211
211
|
// Flat: remove extension
|
|
212
|
-
|
|
212
|
+
const fileName = parts[0];
|
|
213
|
+
const dotIndex = fileName.lastIndexOf('.');
|
|
214
|
+
if (dotIndex <= 0) {
|
|
215
|
+
return fileName;
|
|
216
|
+
}
|
|
217
|
+
return fileName.substring(0, dotIndex);
|
|
213
218
|
}
|
|
214
219
|
readNestedRecord(config, keyPath) {
|
|
215
220
|
let value = config;
|
package/dist/core/types.d.ts
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
import type { Asset } from '../core/types.js';
|
|
2
|
+
export declare function banner(): void;
|
|
1
3
|
export declare function success(message: string): void;
|
|
2
4
|
export declare function error(message: string): void;
|
|
3
5
|
export declare function info(message: string): void;
|
|
4
6
|
export declare function warning(message: string): void;
|
|
5
7
|
export declare function highlight(message: string): void;
|
|
8
|
+
export declare function metric(label: string, value: string | number): void;
|
|
9
|
+
export declare function assetList(assets: Asset[], includeModifiedAt?: boolean, activeProviders?: string[]): void;
|
|
6
10
|
export declare function step(title: string): void;
|
|
7
11
|
export declare function section(title: string): void;
|
|
8
12
|
export declare function table(rows: string[][], columnWidths?: number[]): void;
|
package/dist/utils/cli-output.js
CHANGED
|
@@ -1,23 +1,77 @@
|
|
|
1
|
+
const ansi = {
|
|
2
|
+
reset: '\u001b[0m',
|
|
3
|
+
bold: '\u001b[1m',
|
|
4
|
+
cyan: '\u001b[36m',
|
|
5
|
+
blue: '\u001b[34m',
|
|
6
|
+
green: '\u001b[32m',
|
|
7
|
+
red: '\u001b[31m',
|
|
8
|
+
yellow: '\u001b[33m',
|
|
9
|
+
magenta: '\u001b[35m',
|
|
10
|
+
};
|
|
11
|
+
function color(text, ...codes) {
|
|
12
|
+
return `${codes.join('')}${text}${ansi.reset}`;
|
|
13
|
+
}
|
|
14
|
+
export function banner() {
|
|
15
|
+
console.log(color(`
|
|
16
|
+
__ __ _ ____ _
|
|
17
|
+
\\ \\ / /_ _ ___| | __ _ / ___| ___ _ __ (_) ___
|
|
18
|
+
\\ \\ /\\ / / _\` / __| |/ _\` | | _ / _ \\ '_ \\| |/ _ \\
|
|
19
|
+
\\ V V / (_| \\__ \\ | (_| | |_| | __/ | | | | __/
|
|
20
|
+
\\_/\\_/ \\__,_|___/_|\\__,_|\\____|\\___|_| |_|_|\\___|
|
|
21
|
+
`, ansi.bold, ansi.cyan));
|
|
22
|
+
}
|
|
1
23
|
export function success(message) {
|
|
2
|
-
console.log(`✔ ${message}
|
|
24
|
+
console.log(color(`✔ ${message}`, ansi.green));
|
|
3
25
|
}
|
|
4
26
|
export function error(message) {
|
|
5
|
-
console.error(`✗ ${message}
|
|
27
|
+
console.error(color(`✗ ${message}`, ansi.red));
|
|
6
28
|
}
|
|
7
29
|
export function info(message) {
|
|
8
|
-
console.log(`ℹ ${message}
|
|
30
|
+
console.log(color(`ℹ ${message}`, ansi.blue));
|
|
9
31
|
}
|
|
10
32
|
export function warning(message) {
|
|
11
|
-
console.log(`⚠ ${message}
|
|
33
|
+
console.log(color(`⚠ ${message}`, ansi.yellow));
|
|
12
34
|
}
|
|
13
35
|
export function highlight(message) {
|
|
14
|
-
console.log(`✨ ${message}
|
|
36
|
+
console.log(color(`✨ ${message}`, ansi.magenta, ansi.bold));
|
|
37
|
+
}
|
|
38
|
+
export function metric(label, value) {
|
|
39
|
+
console.log(` ${color(label.padEnd(20), ansi.blue)} ${color(String(value), ansi.bold)}`);
|
|
40
|
+
}
|
|
41
|
+
export function assetList(assets, includeModifiedAt = false, activeProviders) {
|
|
42
|
+
const assetTypes = ['agent', 'skill', 'mcp', 'context'];
|
|
43
|
+
const headings = {
|
|
44
|
+
agent: 'AGENTS',
|
|
45
|
+
skill: 'SKILLS',
|
|
46
|
+
mcp: 'MCP SERVERS',
|
|
47
|
+
context: 'CONTEXT FILES',
|
|
48
|
+
};
|
|
49
|
+
const activeProviderSet = activeProviders ? new Set(activeProviders) : null;
|
|
50
|
+
for (const type of assetTypes) {
|
|
51
|
+
const typedAssets = assets
|
|
52
|
+
.filter((asset) => asset.type === type)
|
|
53
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
54
|
+
if (typedAssets.length === 0)
|
|
55
|
+
continue;
|
|
56
|
+
console.log(color(` ${headings[type]} (${typedAssets.length})`, ansi.cyan, ansi.bold));
|
|
57
|
+
for (const asset of typedAssets) {
|
|
58
|
+
const providers = [...new Set(asset.stubs.map((stub) => stub.tool))]
|
|
59
|
+
.sort()
|
|
60
|
+
.filter((provider) => !activeProviderSet || activeProviderSet.has(provider));
|
|
61
|
+
console.log(` ${color('•', ansi.green)} ${color(asset.name, ansi.bold)}`);
|
|
62
|
+
console.log(` ${color('Mirrors:', ansi.blue)} ${providers.join(', ') || 'none'}`);
|
|
63
|
+
if (includeModifiedAt) {
|
|
64
|
+
console.log(` ${color('Updated:', ansi.blue)} ${new Date(asset.last_modified_at).toLocaleString()}`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
spacer();
|
|
68
|
+
}
|
|
15
69
|
}
|
|
16
70
|
export function step(title) {
|
|
17
71
|
console.log(`\n${title}`);
|
|
18
72
|
}
|
|
19
73
|
export function section(title) {
|
|
20
|
-
console.log(`\n🔍 ${title}
|
|
74
|
+
console.log(color(`\n🔍 ${title}`, ansi.blue, ansi.bold));
|
|
21
75
|
}
|
|
22
76
|
export function table(rows, columnWidths) {
|
|
23
77
|
if (rows.length === 0)
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export type WaslaScope = 'user' | 'workspace';
|
|
2
|
+
export declare function getConfigPath(): string;
|
|
3
|
+
export declare function readConfiguredScope(): Promise<WaslaScope | null>;
|
|
4
|
+
export declare function requireConfiguredScope(): Promise<WaslaScope>;
|
|
5
|
+
export declare function writeConfiguredScope(scope: WaslaScope): Promise<void>;
|
|
6
|
+
export declare function getConfiguredRegistryPath(scope: WaslaScope): string;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { dirname, join } from 'path';
|
|
2
|
+
import { ensureDir, fileExists, readJSON, writeJSON } from './fs.js';
|
|
3
|
+
import { getRegistryDir, getRegistryPath } from './paths.js';
|
|
4
|
+
export function getConfigPath() {
|
|
5
|
+
return join(getRegistryDir('user'), 'config.json');
|
|
6
|
+
}
|
|
7
|
+
export async function readConfiguredScope() {
|
|
8
|
+
const configPath = getConfigPath();
|
|
9
|
+
if (!(await fileExists(configPath)))
|
|
10
|
+
return null;
|
|
11
|
+
const config = await readJSON(configPath);
|
|
12
|
+
if (typeof config !== 'object' || config === null || typeof config.scope !== 'string') {
|
|
13
|
+
throw new Error(`Invalid scope in ${configPath}. Run: waslagenie config --scope <scope>`);
|
|
14
|
+
}
|
|
15
|
+
if (config.scope !== 'user' && config.scope !== 'workspace') {
|
|
16
|
+
throw new Error(`Invalid scope in ${configPath}. Run: waslagenie config --scope <scope>`);
|
|
17
|
+
}
|
|
18
|
+
return config.scope;
|
|
19
|
+
}
|
|
20
|
+
export async function requireConfiguredScope() {
|
|
21
|
+
const scope = await readConfiguredScope();
|
|
22
|
+
if (!scope) {
|
|
23
|
+
throw new Error('Scope is not configured. Run: waslagenie config --scope <user|workspace>');
|
|
24
|
+
}
|
|
25
|
+
return scope;
|
|
26
|
+
}
|
|
27
|
+
export async function writeConfiguredScope(scope) {
|
|
28
|
+
const configPath = getConfigPath();
|
|
29
|
+
await ensureDir(dirname(configPath));
|
|
30
|
+
await writeJSON(configPath, { scope });
|
|
31
|
+
}
|
|
32
|
+
export function getConfiguredRegistryPath(scope) {
|
|
33
|
+
return getRegistryPath(scope);
|
|
34
|
+
}
|
package/dist/utils/fs.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { readdir, readFile, writeFile, stat, mkdir, rm } from 'fs/promises';
|
|
2
|
-
import { basename, extname } from 'path';
|
|
3
2
|
export async function fileExists(path) {
|
|
4
3
|
try {
|
|
5
4
|
await stat(path);
|
|
@@ -60,14 +59,21 @@ export async function listDirs(dir) {
|
|
|
60
59
|
}
|
|
61
60
|
}
|
|
62
61
|
export function getFileName(path) {
|
|
63
|
-
return
|
|
62
|
+
return path.split(/[/\\]/).filter(Boolean).pop() || '';
|
|
64
63
|
}
|
|
65
64
|
export function getFileNameWithoutExt(path) {
|
|
66
|
-
const fileName =
|
|
67
|
-
const
|
|
68
|
-
|
|
65
|
+
const fileName = getFileName(path);
|
|
66
|
+
const dotIndex = fileName.lastIndexOf('.');
|
|
67
|
+
if (dotIndex <= 0) {
|
|
68
|
+
return fileName;
|
|
69
|
+
}
|
|
70
|
+
return fileName.substring(0, dotIndex);
|
|
69
71
|
}
|
|
70
72
|
export function getFileExtension(path) {
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
+
const fileName = getFileName(path);
|
|
74
|
+
const dotIndex = fileName.lastIndexOf('.');
|
|
75
|
+
if (dotIndex <= 0) {
|
|
76
|
+
return '';
|
|
77
|
+
}
|
|
78
|
+
return fileName.substring(dotIndex + 1);
|
|
73
79
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@untitled-devs/wasla",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Universal synchronization layer for AI agent orchestrators",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/cli/index.js",
|
|
@@ -17,50 +17,50 @@
|
|
|
17
17
|
"postbuild": "node -e \"require('fs').chmodSync('dist/cli/index.js', 0o755)\"",
|
|
18
18
|
"dev": "tsc --watch",
|
|
19
19
|
"start": "node dist/cli/index.js",
|
|
20
|
-
"sync": "npm run build && node dist/cli/index.js sync
|
|
21
|
-
"watch": "npm run build && node dist/cli/index.js watch
|
|
22
|
-
"sync:claude:gemini": "npm run build && node dist/cli/index.js sync-to --from claude --to gemini
|
|
23
|
-
"sync:claude:openclaw": "npm run build && node dist/cli/index.js sync-to --from claude --to openclaw
|
|
24
|
-
"sync:claude:opencode": "npm run build && node dist/cli/index.js sync-to --from claude --to opencode
|
|
25
|
-
"sync:claude:cursor": "npm run build && node dist/cli/index.js sync-to --from claude --to cursor
|
|
26
|
-
"sync:claude:github-copilot": "npm run build && node dist/cli/index.js sync-to --from claude --to github-copilot
|
|
27
|
-
"sync:claude:github-copilot-cli": "npm run build && node dist/cli/index.js sync-to --from claude --to github-copilot-cli
|
|
28
|
-
"sync:gemini:claude": "npm run build && node dist/cli/index.js sync-to --from gemini --to claude
|
|
29
|
-
"sync:gemini:openclaw": "npm run build && node dist/cli/index.js sync-to --from gemini --to openclaw
|
|
30
|
-
"sync:gemini:opencode": "npm run build && node dist/cli/index.js sync-to --from gemini --to opencode
|
|
31
|
-
"sync:gemini:cursor": "npm run build && node dist/cli/index.js sync-to --from gemini --to cursor
|
|
32
|
-
"sync:gemini:github-copilot": "npm run build && node dist/cli/index.js sync-to --from gemini --to github-copilot
|
|
33
|
-
"sync:gemini:github-copilot-cli": "npm run build && node dist/cli/index.js sync-to --from gemini --to github-copilot-cli
|
|
34
|
-
"sync:openclaw:claude": "npm run build && node dist/cli/index.js sync-to --from openclaw --to claude
|
|
35
|
-
"sync:openclaw:gemini": "npm run build && node dist/cli/index.js sync-to --from openclaw --to gemini
|
|
36
|
-
"sync:openclaw:opencode": "npm run build && node dist/cli/index.js sync-to --from openclaw --to opencode
|
|
37
|
-
"sync:openclaw:cursor": "npm run build && node dist/cli/index.js sync-to --from openclaw --to cursor
|
|
38
|
-
"sync:openclaw:github-copilot": "npm run build && node dist/cli/index.js sync-to --from openclaw --to github-copilot
|
|
39
|
-
"sync:openclaw:github-copilot-cli": "npm run build && node dist/cli/index.js sync-to --from openclaw --to github-copilot-cli
|
|
40
|
-
"sync:opencode:claude": "npm run build && node dist/cli/index.js sync-to --from opencode --to claude
|
|
41
|
-
"sync:opencode:gemini": "npm run build && node dist/cli/index.js sync-to --from opencode --to gemini
|
|
42
|
-
"sync:opencode:openclaw": "npm run build && node dist/cli/index.js sync-to --from opencode --to openclaw
|
|
43
|
-
"sync:opencode:cursor": "npm run build && node dist/cli/index.js sync-to --from opencode --to cursor
|
|
44
|
-
"sync:opencode:github-copilot": "npm run build && node dist/cli/index.js sync-to --from opencode --to github-copilot
|
|
45
|
-
"sync:opencode:github-copilot-cli": "npm run build && node dist/cli/index.js sync-to --from opencode --to github-copilot-cli
|
|
46
|
-
"sync:cursor:claude": "npm run build && node dist/cli/index.js sync-to --from cursor --to claude
|
|
47
|
-
"sync:cursor:gemini": "npm run build && node dist/cli/index.js sync-to --from cursor --to gemini
|
|
48
|
-
"sync:cursor:openclaw": "npm run build && node dist/cli/index.js sync-to --from cursor --to openclaw
|
|
49
|
-
"sync:cursor:opencode": "npm run build && node dist/cli/index.js sync-to --from cursor --to opencode
|
|
50
|
-
"sync:cursor:github-copilot": "npm run build && node dist/cli/index.js sync-to --from cursor --to github-copilot
|
|
51
|
-
"sync:cursor:github-copilot-cli": "npm run build && node dist/cli/index.js sync-to --from cursor --to github-copilot-cli
|
|
52
|
-
"sync:github-copilot:claude": "npm run build && node dist/cli/index.js sync-to --from github-copilot --to claude
|
|
53
|
-
"sync:github-copilot:gemini": "npm run build && node dist/cli/index.js sync-to --from github-copilot --to gemini
|
|
54
|
-
"sync:github-copilot:openclaw": "npm run build && node dist/cli/index.js sync-to --from github-copilot --to openclaw
|
|
55
|
-
"sync:github-copilot:opencode": "npm run build && node dist/cli/index.js sync-to --from github-copilot --to opencode
|
|
56
|
-
"sync:github-copilot:cursor": "npm run build && node dist/cli/index.js sync-to --from github-copilot --to cursor
|
|
57
|
-
"sync:github-copilot:github-copilot-cli": "npm run build && node dist/cli/index.js sync-to --from github-copilot --to github-copilot-cli
|
|
58
|
-
"sync:github-copilot-cli:claude": "npm run build && node dist/cli/index.js sync-to --from github-copilot-cli --to claude
|
|
59
|
-
"sync:github-copilot-cli:gemini": "npm run build && node dist/cli/index.js sync-to --from github-copilot-cli --to gemini
|
|
60
|
-
"sync:github-copilot-cli:openclaw": "npm run build && node dist/cli/index.js sync-to --from github-copilot-cli --to openclaw
|
|
61
|
-
"sync:github-copilot-cli:opencode": "npm run build && node dist/cli/index.js sync-to --from github-copilot-cli --to opencode
|
|
62
|
-
"sync:github-copilot-cli:cursor": "npm run build && node dist/cli/index.js sync-to --from github-copilot-cli --to cursor
|
|
63
|
-
"sync:github-copilot-cli:github-copilot": "npm run build && node dist/cli/index.js sync-to --from github-copilot-cli --to github-copilot
|
|
20
|
+
"sync": "npm run build && node dist/cli/index.js sync",
|
|
21
|
+
"watch": "npm run build && node dist/cli/index.js watch",
|
|
22
|
+
"sync:claude:gemini": "npm run build && node dist/cli/index.js sync-to --from claude --to gemini",
|
|
23
|
+
"sync:claude:openclaw": "npm run build && node dist/cli/index.js sync-to --from claude --to openclaw",
|
|
24
|
+
"sync:claude:opencode": "npm run build && node dist/cli/index.js sync-to --from claude --to opencode",
|
|
25
|
+
"sync:claude:cursor": "npm run build && node dist/cli/index.js sync-to --from claude --to cursor",
|
|
26
|
+
"sync:claude:github-copilot": "npm run build && node dist/cli/index.js sync-to --from claude --to github-copilot",
|
|
27
|
+
"sync:claude:github-copilot-cli": "npm run build && node dist/cli/index.js sync-to --from claude --to github-copilot-cli",
|
|
28
|
+
"sync:gemini:claude": "npm run build && node dist/cli/index.js sync-to --from gemini --to claude",
|
|
29
|
+
"sync:gemini:openclaw": "npm run build && node dist/cli/index.js sync-to --from gemini --to openclaw",
|
|
30
|
+
"sync:gemini:opencode": "npm run build && node dist/cli/index.js sync-to --from gemini --to opencode",
|
|
31
|
+
"sync:gemini:cursor": "npm run build && node dist/cli/index.js sync-to --from gemini --to cursor",
|
|
32
|
+
"sync:gemini:github-copilot": "npm run build && node dist/cli/index.js sync-to --from gemini --to github-copilot",
|
|
33
|
+
"sync:gemini:github-copilot-cli": "npm run build && node dist/cli/index.js sync-to --from gemini --to github-copilot-cli",
|
|
34
|
+
"sync:openclaw:claude": "npm run build && node dist/cli/index.js sync-to --from openclaw --to claude",
|
|
35
|
+
"sync:openclaw:gemini": "npm run build && node dist/cli/index.js sync-to --from openclaw --to gemini",
|
|
36
|
+
"sync:openclaw:opencode": "npm run build && node dist/cli/index.js sync-to --from openclaw --to opencode",
|
|
37
|
+
"sync:openclaw:cursor": "npm run build && node dist/cli/index.js sync-to --from openclaw --to cursor",
|
|
38
|
+
"sync:openclaw:github-copilot": "npm run build && node dist/cli/index.js sync-to --from openclaw --to github-copilot",
|
|
39
|
+
"sync:openclaw:github-copilot-cli": "npm run build && node dist/cli/index.js sync-to --from openclaw --to github-copilot-cli",
|
|
40
|
+
"sync:opencode:claude": "npm run build && node dist/cli/index.js sync-to --from opencode --to claude",
|
|
41
|
+
"sync:opencode:gemini": "npm run build && node dist/cli/index.js sync-to --from opencode --to gemini",
|
|
42
|
+
"sync:opencode:openclaw": "npm run build && node dist/cli/index.js sync-to --from opencode --to openclaw",
|
|
43
|
+
"sync:opencode:cursor": "npm run build && node dist/cli/index.js sync-to --from opencode --to cursor",
|
|
44
|
+
"sync:opencode:github-copilot": "npm run build && node dist/cli/index.js sync-to --from opencode --to github-copilot",
|
|
45
|
+
"sync:opencode:github-copilot-cli": "npm run build && node dist/cli/index.js sync-to --from opencode --to github-copilot-cli",
|
|
46
|
+
"sync:cursor:claude": "npm run build && node dist/cli/index.js sync-to --from cursor --to claude",
|
|
47
|
+
"sync:cursor:gemini": "npm run build && node dist/cli/index.js sync-to --from cursor --to gemini",
|
|
48
|
+
"sync:cursor:openclaw": "npm run build && node dist/cli/index.js sync-to --from cursor --to openclaw",
|
|
49
|
+
"sync:cursor:opencode": "npm run build && node dist/cli/index.js sync-to --from cursor --to opencode",
|
|
50
|
+
"sync:cursor:github-copilot": "npm run build && node dist/cli/index.js sync-to --from cursor --to github-copilot",
|
|
51
|
+
"sync:cursor:github-copilot-cli": "npm run build && node dist/cli/index.js sync-to --from cursor --to github-copilot-cli",
|
|
52
|
+
"sync:github-copilot:claude": "npm run build && node dist/cli/index.js sync-to --from github-copilot --to claude",
|
|
53
|
+
"sync:github-copilot:gemini": "npm run build && node dist/cli/index.js sync-to --from github-copilot --to gemini",
|
|
54
|
+
"sync:github-copilot:openclaw": "npm run build && node dist/cli/index.js sync-to --from github-copilot --to openclaw",
|
|
55
|
+
"sync:github-copilot:opencode": "npm run build && node dist/cli/index.js sync-to --from github-copilot --to opencode",
|
|
56
|
+
"sync:github-copilot:cursor": "npm run build && node dist/cli/index.js sync-to --from github-copilot --to cursor",
|
|
57
|
+
"sync:github-copilot:github-copilot-cli": "npm run build && node dist/cli/index.js sync-to --from github-copilot --to github-copilot-cli",
|
|
58
|
+
"sync:github-copilot-cli:claude": "npm run build && node dist/cli/index.js sync-to --from github-copilot-cli --to claude",
|
|
59
|
+
"sync:github-copilot-cli:gemini": "npm run build && node dist/cli/index.js sync-to --from github-copilot-cli --to gemini",
|
|
60
|
+
"sync:github-copilot-cli:openclaw": "npm run build && node dist/cli/index.js sync-to --from github-copilot-cli --to openclaw",
|
|
61
|
+
"sync:github-copilot-cli:opencode": "npm run build && node dist/cli/index.js sync-to --from github-copilot-cli --to opencode",
|
|
62
|
+
"sync:github-copilot-cli:cursor": "npm run build && node dist/cli/index.js sync-to --from github-copilot-cli --to cursor",
|
|
63
|
+
"sync:github-copilot-cli:github-copilot": "npm run build && node dist/cli/index.js sync-to --from github-copilot-cli --to github-copilot",
|
|
64
64
|
"test": "vitest",
|
|
65
65
|
"test:run": "vitest run",
|
|
66
66
|
"test:watch": "vitest --watch",
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
"docs": "cd docs && npm run start",
|
|
73
73
|
"docs:install": "npm --prefix docs install",
|
|
74
74
|
"docs:build": "cd docs && npm run build",
|
|
75
|
-
"visualizer": "npm run visualizer:install && npm run visualizer:build && npm run build && node dist/cli/index.js visualizer
|
|
75
|
+
"visualizer": "npm run visualizer:install && npm run visualizer:build && npm run build && node dist/cli/index.js visualizer",
|
|
76
76
|
"ui": "npm run visualizer",
|
|
77
77
|
"visualizer:install": "npm --prefix src/visualizer install",
|
|
78
78
|
"visualizer:dev": "npm --prefix src/visualizer run dev",
|
|
@@ -87,6 +87,8 @@
|
|
|
87
87
|
"type:fix": "tsc --noEmit && prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"",
|
|
88
88
|
"check": "npm run type:check && npm run format:check",
|
|
89
89
|
"fix": "npm run format && npm run lint:fix",
|
|
90
|
+
"changelog": "node scripts/release.mjs changelog",
|
|
91
|
+
"release": "node scripts/release.mjs release",
|
|
90
92
|
"clean": "node -e \"['dist', '.nyc_output', 'output', 'coverage'].forEach(p => require('fs').rmSync(p, { recursive: true, force: true }))\"",
|
|
91
93
|
"all": "npm run clean && npm run build && npm run check && npm test"
|
|
92
94
|
},
|
|
@@ -110,6 +112,7 @@
|
|
|
110
112
|
"devDependencies": {
|
|
111
113
|
"@ai-hero/sandcastle": "^0.6.6",
|
|
112
114
|
"@types/node": "^20.10.6",
|
|
115
|
+
"@types/prompts": "^2.4.9",
|
|
113
116
|
"@types/ws": "^8.18.1",
|
|
114
117
|
"@vitest/coverage-v8": "^1.6.1",
|
|
115
118
|
"@vitest/ui": "^1.0.0",
|