devtopia 1.7.0 → 1.8.2
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 +3 -3
- package/dist/commands/lineage.d.ts +1 -0
- package/dist/commands/lineage.js +47 -0
- package/dist/commands/submit.js +52 -0
- package/dist/config.js +1 -1
- package/dist/index.js +24 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -182,9 +182,9 @@ When submitting, tools are auto-categorized or you can specify:
|
|
|
182
182
|
|
|
183
183
|
## Links
|
|
184
184
|
|
|
185
|
-
- **Registry:** https://
|
|
186
|
-
- **API Docs:** https://
|
|
187
|
-
- **All Tools:** https://
|
|
185
|
+
- **Registry:** https://devtopia.net
|
|
186
|
+
- **API Docs:** https://devtopia.net/docs
|
|
187
|
+
- **All Tools:** https://devtopia.net/tools
|
|
188
188
|
|
|
189
189
|
---
|
|
190
190
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function updateLineage(toolName: string, buildsOn?: string): Promise<void>;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { API_BASE } from '../config.js';
|
|
2
|
+
import { loadIdentity, hasIdentity } from '../identity.js';
|
|
3
|
+
export async function updateLineage(toolName, buildsOn) {
|
|
4
|
+
if (!hasIdentity()) {
|
|
5
|
+
console.log(`\n❌ Not registered yet.`);
|
|
6
|
+
console.log(` Run: devtopia register -n YOUR_NAME\n`);
|
|
7
|
+
process.exit(1);
|
|
8
|
+
}
|
|
9
|
+
const identity = loadIdentity();
|
|
10
|
+
if (!identity) {
|
|
11
|
+
console.log(`\n❌ Could not read identity.\n`);
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
// Parse builds_on
|
|
15
|
+
const buildsOnArray = buildsOn
|
|
16
|
+
? buildsOn.split(',').map(t => t.trim()).filter(Boolean)
|
|
17
|
+
: [];
|
|
18
|
+
try {
|
|
19
|
+
const res = await fetch(`${API_BASE}/api/tools/${toolName}/lineage`, {
|
|
20
|
+
method: 'PATCH',
|
|
21
|
+
headers: { 'Content-Type': 'application/json' },
|
|
22
|
+
body: JSON.stringify({
|
|
23
|
+
builds_on: buildsOnArray.length > 0 ? buildsOnArray : null,
|
|
24
|
+
tripcode: identity.tripcode,
|
|
25
|
+
}),
|
|
26
|
+
});
|
|
27
|
+
const data = await res.json();
|
|
28
|
+
if (!res.ok) {
|
|
29
|
+
console.log(`\n❌ ${data.error}\n`);
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
console.log(`\n✅ Lineage updated successfully!`);
|
|
33
|
+
console.log(`\n Tool: /${toolName}`);
|
|
34
|
+
if (buildsOnArray.length > 0) {
|
|
35
|
+
console.log(` Builds on: ${buildsOnArray.join(', ')}`);
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
console.log(` Builds on: (none - lineage cleared)`);
|
|
39
|
+
}
|
|
40
|
+
console.log(`\n View lineage:`);
|
|
41
|
+
console.log(` $ devtopia cat ${toolName}\n`);
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
console.log(`\n❌ Could not connect to server at ${API_BASE}\n`);
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
}
|
package/dist/commands/submit.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { readFileSync, existsSync } from 'fs';
|
|
2
2
|
import { extname, resolve, dirname, join } from 'path';
|
|
3
|
+
import { createInterface } from 'readline';
|
|
3
4
|
import { API_BASE } from '../config.js';
|
|
4
5
|
import { loadIdentity, hasIdentity } from '../identity.js';
|
|
5
6
|
const LANG_MAP = {
|
|
@@ -362,9 +363,54 @@ export async function submit(name, file, options) {
|
|
|
362
363
|
console.log();
|
|
363
364
|
process.exit(1);
|
|
364
365
|
}
|
|
366
|
+
// Auto-detect if not provided
|
|
365
367
|
if (!category) {
|
|
366
368
|
category = detectCategory(description, source);
|
|
367
369
|
}
|
|
370
|
+
// Prompt for category confirmation/selection if not provided via CLI
|
|
371
|
+
if (!options.category && process.stdin.isTTY) {
|
|
372
|
+
const rl = createInterface({
|
|
373
|
+
input: process.stdin,
|
|
374
|
+
output: process.stdout
|
|
375
|
+
});
|
|
376
|
+
const detectedCat = CATEGORIES.find(c => c.id === category);
|
|
377
|
+
console.log(`\n📁 Category Selection`);
|
|
378
|
+
console.log(` Auto-detected: ${detectedCat?.name || category} (${category})`);
|
|
379
|
+
console.log(`\n Common categories:`);
|
|
380
|
+
// Show most common/relevant categories
|
|
381
|
+
const commonCategories = [
|
|
382
|
+
'api', 'json', 'data', 'text', 'web', 'crypto', 'file',
|
|
383
|
+
'array', 'validate', 'util', 'other'
|
|
384
|
+
];
|
|
385
|
+
for (const catId of commonCategories) {
|
|
386
|
+
const cat = CATEGORIES.find(c => c.id === catId);
|
|
387
|
+
if (cat) {
|
|
388
|
+
const marker = cat.id === category ? ' ← detected' : '';
|
|
389
|
+
console.log(` ${cat.id.padEnd(12)} ${cat.name}${marker}`);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
console.log(`\n (Use 'devtopia categories' to see all categories)`);
|
|
393
|
+
console.log(`\n Press Enter to use detected category, or type a category ID:`);
|
|
394
|
+
const answer = await new Promise((resolve) => {
|
|
395
|
+
rl.question(` Category [${category}]: `, (ans) => {
|
|
396
|
+
rl.close();
|
|
397
|
+
resolve(ans.trim());
|
|
398
|
+
});
|
|
399
|
+
});
|
|
400
|
+
if (answer) {
|
|
401
|
+
const selectedCat = CATEGORIES.find(c => c.id === answer.toLowerCase());
|
|
402
|
+
if (selectedCat) {
|
|
403
|
+
category = selectedCat.id;
|
|
404
|
+
}
|
|
405
|
+
else {
|
|
406
|
+
console.log(`\n⚠️ Invalid category "${answer}", using detected: ${category}\n`);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
else if (!options.category) {
|
|
411
|
+
console.log(`\n💡 Tip: Category auto-detected as "${category}"`);
|
|
412
|
+
console.log(` Use -c <category> to specify a different category.\n`);
|
|
413
|
+
}
|
|
368
414
|
// Parse dependencies
|
|
369
415
|
const dependencies = options.deps
|
|
370
416
|
? options.deps.split(',').map(d => d.trim()).filter(Boolean)
|
|
@@ -373,6 +419,12 @@ export async function submit(name, file, options) {
|
|
|
373
419
|
const buildsOn = options.buildsOn
|
|
374
420
|
? options.buildsOn.split(',').map(d => d.trim()).filter(Boolean)
|
|
375
421
|
: [];
|
|
422
|
+
// Encourage lineage tracking
|
|
423
|
+
if (!options.buildsOn && buildsOn.length === 0) {
|
|
424
|
+
console.log(`\n💡 Tip: Use --builds-on to show lineage!`);
|
|
425
|
+
console.log(` Example: --builds-on api-request,json-validate`);
|
|
426
|
+
console.log(` This helps others see how tools build on each other.\n`);
|
|
427
|
+
}
|
|
376
428
|
const catInfo = CATEGORIES.find(c => c.id === category);
|
|
377
429
|
console.log(`\n📦 Submitting ${name}...`);
|
|
378
430
|
console.log(` File: ${file}`);
|
package/dist/config.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { homedir } from 'os';
|
|
2
2
|
import { join } from 'path';
|
|
3
3
|
// API base URL - can be overridden with DEVTOPIA_API env var
|
|
4
|
-
export const API_BASE = process.env.DEVTOPIA_API || 'https://
|
|
4
|
+
export const API_BASE = process.env.DEVTOPIA_API || 'https://devtopia.up.railway.app';
|
|
5
5
|
// Identity file location
|
|
6
6
|
export const IDENTITY_DIR = join(homedir(), '.devtopia');
|
|
7
7
|
export const IDENTITY_FILE = join(IDENTITY_DIR, 'identity.json');
|
package/dist/index.js
CHANGED
|
@@ -8,6 +8,7 @@ import { cat } from './commands/cat.js';
|
|
|
8
8
|
import { submit } from './commands/submit.js';
|
|
9
9
|
import { run } from './commands/run.js';
|
|
10
10
|
import { categories } from './commands/categories.js';
|
|
11
|
+
import { updateLineage } from './commands/lineage.js';
|
|
11
12
|
const program = new Command();
|
|
12
13
|
program
|
|
13
14
|
.name('devtopia')
|
|
@@ -86,8 +87,30 @@ program
|
|
|
86
87
|
.option('-r, --readme <path>', 'Path to README file (auto-detected if not specified)')
|
|
87
88
|
.option('-c, --category <id>', 'Category (auto-detected if not specified)')
|
|
88
89
|
.option('--deps <deps>', 'Comma-separated dependencies')
|
|
89
|
-
.option('--builds-on <tools>', 'Comma-separated parent tools this extends/composes')
|
|
90
|
+
.option('--builds-on <tools>', 'Comma-separated parent tools this extends/composes (RECOMMENDED: shows lineage)')
|
|
91
|
+
.addHelpText('after', `
|
|
92
|
+
Examples:
|
|
93
|
+
$ devtopia submit my-tool ./my-tool.js -d "Does something useful"
|
|
94
|
+
$ devtopia submit api-client ./client.js --builds-on api-request,json-validate
|
|
95
|
+
$ devtopia submit data-pipeline ./pipeline.js -r ./README.md --builds-on json-flatten,array-chunk
|
|
96
|
+
|
|
97
|
+
💡 Best Practice: Use --builds-on to show how your tool composes with others!
|
|
98
|
+
This creates visible dependency chains and helps the ecosystem grow.
|
|
99
|
+
`)
|
|
90
100
|
.action(submit);
|
|
101
|
+
program
|
|
102
|
+
.command('lineage <tool> [builds-on]')
|
|
103
|
+
.description('Update tool lineage - specify which tools this builds on')
|
|
104
|
+
.addHelpText('after', `
|
|
105
|
+
Examples:
|
|
106
|
+
$ devtopia lineage api-retry api-request
|
|
107
|
+
$ devtopia lineage data-pipeline "json-flatten,json-validate,array-chunk"
|
|
108
|
+
$ devtopia lineage my-tool "" # Clear lineage
|
|
109
|
+
|
|
110
|
+
💡 Use this to add or update lineage for tools you've already submitted!
|
|
111
|
+
This helps others see how tools build on each other.
|
|
112
|
+
`)
|
|
113
|
+
.action((tool, buildsOn) => updateLineage(tool, buildsOn));
|
|
91
114
|
// =============================================================================
|
|
92
115
|
// Running (LOCAL)
|
|
93
116
|
// =============================================================================
|