@fredlackey/devutils 0.0.19 → 0.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 +223 -32
- package/package.json +7 -5
- package/src/api/loader.js +229 -0
- package/src/api/registry.json +62 -0
- package/src/cli.js +305 -0
- package/src/commands/ai/index.js +16 -0
- package/src/commands/ai/launch.js +112 -0
- package/src/commands/ai/list.js +54 -0
- package/src/commands/ai/resume.js +70 -0
- package/src/commands/ai/sessions.js +121 -0
- package/src/commands/ai/set.js +131 -0
- package/src/commands/ai/show.js +74 -0
- package/src/commands/ai/tools.js +46 -0
- package/src/commands/alias/add.js +93 -0
- package/src/commands/alias/helpers.js +107 -0
- package/src/commands/alias/index.js +14 -0
- package/src/commands/alias/list.js +55 -0
- package/src/commands/alias/remove.js +62 -0
- package/src/commands/alias/sync.js +109 -0
- package/src/commands/api/disable.js +73 -0
- package/src/commands/api/enable.js +148 -0
- package/src/commands/api/index.js +15 -0
- package/src/commands/api/list.js +66 -0
- package/src/commands/api/update.js +87 -0
- package/src/commands/auth/index.js +15 -0
- package/src/commands/auth/list.js +49 -0
- package/src/commands/auth/login.js +384 -0
- package/src/commands/auth/logout.js +111 -0
- package/src/commands/auth/refresh.js +184 -0
- package/src/commands/auth/services.js +169 -0
- package/src/commands/auth/status.js +104 -0
- package/src/commands/config/export.js +224 -0
- package/src/commands/config/get.js +52 -0
- package/src/commands/config/import.js +308 -0
- package/src/commands/config/index.js +17 -0
- package/src/commands/config/init.js +143 -0
- package/src/commands/config/reset.js +57 -0
- package/src/commands/config/set.js +93 -0
- package/src/commands/config/show.js +35 -0
- package/src/commands/help.js +338 -0
- package/src/commands/identity/add.js +133 -0
- package/src/commands/identity/index.js +17 -0
- package/src/commands/identity/link.js +76 -0
- package/src/commands/identity/list.js +48 -0
- package/src/commands/identity/remove.js +72 -0
- package/src/commands/identity/show.js +65 -0
- package/src/commands/identity/sync.js +172 -0
- package/src/commands/identity/unlink.js +57 -0
- package/src/commands/ignore/add.js +165 -0
- package/src/commands/ignore/index.js +14 -0
- package/src/commands/ignore/list.js +89 -0
- package/src/commands/ignore/markers.js +43 -0
- package/src/commands/ignore/remove.js +164 -0
- package/src/commands/ignore/show.js +169 -0
- package/src/commands/machine/detect.js +122 -0
- package/src/commands/machine/index.js +14 -0
- package/src/commands/machine/list.js +74 -0
- package/src/commands/machine/set.js +106 -0
- package/src/commands/machine/show.js +35 -0
- package/src/commands/schema.js +152 -0
- package/src/commands/search/collections.js +134 -0
- package/src/commands/search/get.js +71 -0
- package/src/commands/search/index-cmd.js +54 -0
- package/src/commands/search/index.js +21 -0
- package/src/commands/search/keyword.js +60 -0
- package/src/commands/search/qmd.js +70 -0
- package/src/commands/search/query.js +64 -0
- package/src/commands/search/semantic.js +62 -0
- package/src/commands/search/status.js +46 -0
- package/src/commands/status.js +276 -0
- package/src/commands/tools/check.js +79 -0
- package/src/commands/tools/index.js +14 -0
- package/src/commands/tools/install.js +110 -0
- package/src/commands/tools/list.js +91 -0
- package/src/commands/tools/search.js +60 -0
- package/src/commands/update.js +113 -0
- package/src/commands/util/add.js +151 -0
- package/src/commands/util/index.js +15 -0
- package/src/commands/util/list.js +97 -0
- package/src/commands/util/remove.js +76 -0
- package/src/commands/util/run.js +79 -0
- package/src/commands/util/show.js +67 -0
- package/src/commands/version.js +33 -0
- package/src/installers/_template.js +104 -0
- package/src/installers/git.js +150 -0
- package/src/installers/homebrew.js +190 -0
- package/src/installers/node.js +223 -0
- package/src/installers/registry.json +29 -0
- package/src/lib/config.js +125 -0
- package/src/lib/detect.js +74 -0
- package/src/lib/errors.js +114 -0
- package/src/lib/github.js +315 -0
- package/src/lib/installer.js +225 -0
- package/src/lib/output.js +239 -0
- package/src/lib/platform.js +112 -0
- package/src/lib/platforms/amazon-linux.js +41 -0
- package/src/lib/platforms/gitbash.js +46 -0
- package/src/lib/platforms/macos.js +45 -0
- package/src/lib/platforms/raspbian.js +41 -0
- package/src/lib/platforms/ubuntu.js +39 -0
- package/src/lib/platforms/windows.js +45 -0
- package/src/lib/prompt.js +161 -0
- package/src/lib/schema.js +211 -0
- package/src/lib/shell.js +75 -0
- package/src/patterns/gitignore/claude-code.txt +25 -0
- package/src/patterns/gitignore/docker.txt +15 -0
- package/src/patterns/gitignore/go.txt +24 -0
- package/src/patterns/gitignore/java.txt +38 -0
- package/src/patterns/gitignore/jetbrains.txt +26 -0
- package/src/patterns/gitignore/linux.txt +18 -0
- package/src/patterns/gitignore/macos.txt +27 -0
- package/src/patterns/gitignore/node.txt +51 -0
- package/src/patterns/gitignore/python.txt +55 -0
- package/src/patterns/gitignore/rust.txt +14 -0
- package/src/patterns/gitignore/terraform.txt +30 -0
- package/src/patterns/gitignore/vscode.txt +15 -0
- package/src/patterns/gitignore/windows.txt +25 -0
- package/src/utils/clone/index.js +165 -0
- package/src/utils/git-push/index.js +230 -0
- package/src/utils/git-status/index.js +116 -0
- package/src/utils/git-status/unix.sh +75 -0
- package/src/utils/registry.json +41 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const shell = require('../../lib/shell');
|
|
5
|
+
const loader = require('../../api/loader');
|
|
6
|
+
|
|
7
|
+
const meta = {
|
|
8
|
+
description: 'Remove an installed API plugin',
|
|
9
|
+
arguments: [
|
|
10
|
+
{ name: 'name', description: 'Plugin name to remove', required: true }
|
|
11
|
+
],
|
|
12
|
+
flags: [
|
|
13
|
+
{ name: 'confirm', type: 'boolean', description: 'Skip confirmation prompt' }
|
|
14
|
+
]
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Removes an installed API plugin.
|
|
19
|
+
* Runs npm uninstall, removes the entry from plugins.json,
|
|
20
|
+
* and asks for confirmation unless --confirm is passed.
|
|
21
|
+
*
|
|
22
|
+
* @param {object} args - Parsed CLI arguments { positional, flags }.
|
|
23
|
+
* @param {object} context - CLI context { output, errors, prompt }.
|
|
24
|
+
*/
|
|
25
|
+
async function run(args, context) {
|
|
26
|
+
const pluginName = args.positional[0];
|
|
27
|
+
|
|
28
|
+
if (!pluginName) {
|
|
29
|
+
context.errors.throwError(400, 'Missing required argument: <name>. Example: dev api disable gmail', 'api');
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Check if the plugin is installed
|
|
34
|
+
const plugins = loader.readPluginsJson();
|
|
35
|
+
const entry = plugins[pluginName];
|
|
36
|
+
|
|
37
|
+
if (!entry) {
|
|
38
|
+
context.output.info(`Plugin "${pluginName}" is not installed.`);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Ask for confirmation unless --confirm is passed
|
|
43
|
+
if (!args.flags.confirm) {
|
|
44
|
+
const ok = await context.prompt.confirm(
|
|
45
|
+
`Remove plugin "${pluginName}" (${entry.package})?`,
|
|
46
|
+
false
|
|
47
|
+
);
|
|
48
|
+
if (!ok) {
|
|
49
|
+
context.output.info('Cancelled.');
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Run npm uninstall
|
|
55
|
+
const result = await shell.exec(`npm uninstall ${entry.package}`, { cwd: loader.PLUGINS_DIR });
|
|
56
|
+
|
|
57
|
+
if (result.exitCode !== 0) {
|
|
58
|
+
context.errors.throwError(
|
|
59
|
+
500,
|
|
60
|
+
`Failed to uninstall plugin "${pluginName}".\n${result.stderr || result.stdout}`,
|
|
61
|
+
'api'
|
|
62
|
+
);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Remove the entry from plugins.json
|
|
67
|
+
delete plugins[pluginName];
|
|
68
|
+
fs.writeFileSync(loader.PLUGINS_FILE, JSON.stringify(plugins, null, 2) + '\n');
|
|
69
|
+
|
|
70
|
+
context.output.info(`Plugin "${pluginName}" removed.`);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
module.exports = { meta, run };
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const shell = require('../../lib/shell');
|
|
6
|
+
const loader = require('../../api/loader');
|
|
7
|
+
|
|
8
|
+
const meta = {
|
|
9
|
+
description: 'Install an API plugin from npm or a git repository',
|
|
10
|
+
arguments: [
|
|
11
|
+
{ name: 'name', description: 'Plugin name or full package name', required: true }
|
|
12
|
+
],
|
|
13
|
+
flags: [
|
|
14
|
+
{ name: 'source', type: 'string', description: 'Install source type: "npm" or "git" (default: npm)' },
|
|
15
|
+
{ name: 'url', type: 'string', description: 'Package name or git URL when using a non-registry plugin' }
|
|
16
|
+
]
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Installs an API plugin from npm or a git repository.
|
|
21
|
+
* Resolves short names (like "gmail") through the registry, or accepts
|
|
22
|
+
* full package names (starting with "@") and git URLs directly.
|
|
23
|
+
*
|
|
24
|
+
* @param {object} args - Parsed CLI arguments { positional, flags }.
|
|
25
|
+
* @param {object} context - CLI context { output, errors, prompt }.
|
|
26
|
+
*/
|
|
27
|
+
async function run(args, context) {
|
|
28
|
+
const pluginName = args.positional[0];
|
|
29
|
+
|
|
30
|
+
if (!pluginName) {
|
|
31
|
+
context.errors.throwError(400, 'Missing required argument: <name>. Example: dev api enable gmail', 'api');
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Resolve the package name from the registry or direct input
|
|
36
|
+
const registry = loader.getRegistryPlugins();
|
|
37
|
+
const registryEntry = registry.find(entry => entry.name === pluginName);
|
|
38
|
+
let packageName;
|
|
39
|
+
|
|
40
|
+
if (registryEntry) {
|
|
41
|
+
// Found in registry - use the registry package name
|
|
42
|
+
packageName = registryEntry.package;
|
|
43
|
+
} else if (args.flags.url) {
|
|
44
|
+
// Not in registry but user provided a URL/package name
|
|
45
|
+
packageName = args.flags.url;
|
|
46
|
+
} else if (pluginName.startsWith('@') || pluginName.includes('/')) {
|
|
47
|
+
// Looks like a scoped npm package or git URL - use directly
|
|
48
|
+
packageName = pluginName;
|
|
49
|
+
} else {
|
|
50
|
+
context.errors.throwError(
|
|
51
|
+
404,
|
|
52
|
+
`Plugin "${pluginName}" not found in the registry. Use --source git --url <git-url> to install from a git repository, or --url <package-name> to install a non-registry npm package.`,
|
|
53
|
+
'api'
|
|
54
|
+
);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Check if already installed
|
|
59
|
+
const installed = loader.readPluginsJson();
|
|
60
|
+
if (installed[pluginName]) {
|
|
61
|
+
context.output.info(
|
|
62
|
+
`Plugin "${pluginName}" is already installed (version ${installed[pluginName].version || 'unknown'}). Use "dev api update ${pluginName}" to update.`
|
|
63
|
+
);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Ensure the plugins directory exists with a package.json
|
|
68
|
+
const pluginsDir = loader.PLUGINS_DIR;
|
|
69
|
+
const pkgJsonPath = path.join(pluginsDir, 'package.json');
|
|
70
|
+
|
|
71
|
+
if (!fs.existsSync(pkgJsonPath)) {
|
|
72
|
+
fs.mkdirSync(pluginsDir, { recursive: true });
|
|
73
|
+
fs.writeFileSync(pkgJsonPath, JSON.stringify({
|
|
74
|
+
name: 'devutils-plugins',
|
|
75
|
+
version: '1.0.0',
|
|
76
|
+
private: true,
|
|
77
|
+
description: 'DevUtils CLI plugin packages'
|
|
78
|
+
}, null, 2) + '\n');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Determine the install target
|
|
82
|
+
const installTarget = args.flags.url || packageName;
|
|
83
|
+
|
|
84
|
+
// Run npm install
|
|
85
|
+
context.output.info(`Installing ${pluginName} (${installTarget})...`);
|
|
86
|
+
const result = await shell.exec(`npm install ${installTarget}`, { cwd: pluginsDir });
|
|
87
|
+
|
|
88
|
+
if (result.exitCode !== 0) {
|
|
89
|
+
context.errors.throwError(
|
|
90
|
+
500,
|
|
91
|
+
`Failed to install plugin "${pluginName}".\n${result.stderr || result.stdout}`,
|
|
92
|
+
'api'
|
|
93
|
+
);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Read the installed version from the plugin's package.json
|
|
98
|
+
let installedVersion = 'unknown';
|
|
99
|
+
try {
|
|
100
|
+
const pluginPkgPath = path.join(pluginsDir, 'node_modules', packageName, 'package.json');
|
|
101
|
+
const pluginPkg = JSON.parse(fs.readFileSync(pluginPkgPath, 'utf8'));
|
|
102
|
+
installedVersion = pluginPkg.version || 'unknown';
|
|
103
|
+
} catch (err) {
|
|
104
|
+
// Could not read version, continue with 'unknown'
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Update plugins.json
|
|
108
|
+
const plugins = loader.readPluginsJson();
|
|
109
|
+
const sourceType = args.flags.source || 'npm';
|
|
110
|
+
plugins[pluginName] = {
|
|
111
|
+
package: packageName,
|
|
112
|
+
version: installedVersion,
|
|
113
|
+
source: sourceType,
|
|
114
|
+
installedAt: new Date().toISOString()
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
// Only store the URL if one was explicitly provided
|
|
118
|
+
if (args.flags.url) {
|
|
119
|
+
plugins[pluginName].url = args.flags.url;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Ensure the parent directory exists for plugins.json
|
|
123
|
+
const pluginsFileDir = path.dirname(loader.PLUGINS_FILE);
|
|
124
|
+
if (!fs.existsSync(pluginsFileDir)) {
|
|
125
|
+
fs.mkdirSync(pluginsFileDir, { recursive: true });
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
fs.writeFileSync(loader.PLUGINS_FILE, JSON.stringify(plugins, null, 2) + '\n');
|
|
129
|
+
|
|
130
|
+
// Validate the plugin contract
|
|
131
|
+
const loadResult = loader.loadPlugin(pluginName);
|
|
132
|
+
if (loadResult.error) {
|
|
133
|
+
context.output.info(
|
|
134
|
+
`Warning: Plugin installed but does not follow the expected contract. It may not work correctly.\n${loadResult.message}`
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Print success
|
|
139
|
+
context.output.info(`Plugin "${pluginName}" installed (v${installedVersion}).`);
|
|
140
|
+
|
|
141
|
+
// Show auth hint if available from the registry entry
|
|
142
|
+
const authService = registryEntry ? registryEntry.auth : null;
|
|
143
|
+
if (authService) {
|
|
144
|
+
context.output.info(`This plugin requires "${authService}" authentication. Run "dev auth login ${authService}" if you haven't already.`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
module.exports = { meta, run };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API service registration.
|
|
3
|
+
* API plugin system — manages plugin installation, removal, and updates.
|
|
4
|
+
* Plugin commands are loaded at runtime from ~/.devutils/plugins/.
|
|
5
|
+
*/
|
|
6
|
+
module.exports = {
|
|
7
|
+
name: 'api',
|
|
8
|
+
description: 'API plugin system',
|
|
9
|
+
commands: {
|
|
10
|
+
list: () => require('./list'),
|
|
11
|
+
enable: () => require('./enable'),
|
|
12
|
+
disable: () => require('./disable'),
|
|
13
|
+
update: () => require('./update'),
|
|
14
|
+
}
|
|
15
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const loader = require('../../api/loader');
|
|
4
|
+
|
|
5
|
+
const meta = {
|
|
6
|
+
description: 'List installed and available API plugins',
|
|
7
|
+
arguments: [],
|
|
8
|
+
flags: [
|
|
9
|
+
{ name: 'installed', type: 'boolean', description: 'Show only installed plugins' },
|
|
10
|
+
{ name: 'available', type: 'boolean', description: 'Show only available (not installed) plugins' }
|
|
11
|
+
]
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Lists installed and/or available API plugins.
|
|
16
|
+
* Shows both by default, or filters with --installed / --available flags.
|
|
17
|
+
*
|
|
18
|
+
* @param {object} args - Parsed CLI arguments { positional, flags }.
|
|
19
|
+
* @param {object} context - CLI context { output, errors }.
|
|
20
|
+
*/
|
|
21
|
+
async function run(args, context) {
|
|
22
|
+
const installed = loader.getInstalledPlugins();
|
|
23
|
+
const registry = loader.getRegistryPlugins();
|
|
24
|
+
const installedNames = Object.keys(installed);
|
|
25
|
+
|
|
26
|
+
// Build the installed list
|
|
27
|
+
const installedList = installedNames.map(name => ({
|
|
28
|
+
name,
|
|
29
|
+
package: installed[name].package,
|
|
30
|
+
version: installed[name].version || 'unknown',
|
|
31
|
+
source: installed[name].source || 'npm',
|
|
32
|
+
installedAt: installed[name].installedAt || ''
|
|
33
|
+
}));
|
|
34
|
+
|
|
35
|
+
// Build the available list (registry entries that are not installed)
|
|
36
|
+
const availableList = registry
|
|
37
|
+
.filter(entry => !installed[entry.name])
|
|
38
|
+
.map(entry => ({
|
|
39
|
+
name: entry.name,
|
|
40
|
+
package: entry.package,
|
|
41
|
+
description: entry.description
|
|
42
|
+
}));
|
|
43
|
+
|
|
44
|
+
// Apply filters
|
|
45
|
+
const showInstalled = args.flags.installed || !args.flags.available;
|
|
46
|
+
const showAvailable = args.flags.available || !args.flags.installed;
|
|
47
|
+
|
|
48
|
+
const result = {};
|
|
49
|
+
|
|
50
|
+
if (showInstalled) {
|
|
51
|
+
result.installed = installedList;
|
|
52
|
+
}
|
|
53
|
+
if (showAvailable) {
|
|
54
|
+
result.available = availableList;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// If only installed was requested and nothing is installed, give a hint
|
|
58
|
+
if (args.flags.installed && installedList.length === 0) {
|
|
59
|
+
context.output.info('No API plugins installed. Run "dev api enable <name>" to install one.');
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
context.output.out(result);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
module.exports = { meta, run };
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const shell = require('../../lib/shell');
|
|
6
|
+
const loader = require('../../api/loader');
|
|
7
|
+
|
|
8
|
+
const meta = {
|
|
9
|
+
description: 'Update an installed API plugin to the latest version',
|
|
10
|
+
arguments: [
|
|
11
|
+
{ name: 'name', description: 'Plugin name to update', required: true }
|
|
12
|
+
],
|
|
13
|
+
flags: []
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Updates an installed API plugin to the latest version.
|
|
18
|
+
* For npm-sourced plugins, runs npm update. For git-sourced plugins,
|
|
19
|
+
* re-runs npm install with the original git URL.
|
|
20
|
+
*
|
|
21
|
+
* @param {object} args - Parsed CLI arguments { positional, flags }.
|
|
22
|
+
* @param {object} context - CLI context { output, errors }.
|
|
23
|
+
*/
|
|
24
|
+
async function run(args, context) {
|
|
25
|
+
const pluginName = args.positional[0];
|
|
26
|
+
|
|
27
|
+
if (!pluginName) {
|
|
28
|
+
context.errors.throwError(400, 'Missing required argument: <name>. Example: dev api update gmail', 'api');
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Check if the plugin is installed
|
|
33
|
+
const plugins = loader.readPluginsJson();
|
|
34
|
+
const entry = plugins[pluginName];
|
|
35
|
+
|
|
36
|
+
if (!entry) {
|
|
37
|
+
context.output.info(`Plugin "${pluginName}" is not installed.`);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const previousVersion = entry.version || 'unknown';
|
|
42
|
+
const pluginsDir = loader.PLUGINS_DIR;
|
|
43
|
+
|
|
44
|
+
// Determine update strategy based on source type
|
|
45
|
+
let result;
|
|
46
|
+
if (entry.source === 'git' && entry.url) {
|
|
47
|
+
// Git-sourced plugins: re-install from the original URL
|
|
48
|
+
context.output.info(`Updating ${pluginName} from git...`);
|
|
49
|
+
result = await shell.exec(`npm install ${entry.url}`, { cwd: pluginsDir });
|
|
50
|
+
} else {
|
|
51
|
+
// npm-sourced plugins: use npm update
|
|
52
|
+
context.output.info(`Updating ${pluginName}...`);
|
|
53
|
+
result = await shell.exec(`npm update ${entry.package}`, { cwd: pluginsDir });
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (result.exitCode !== 0) {
|
|
57
|
+
context.errors.throwError(
|
|
58
|
+
500,
|
|
59
|
+
`Failed to update plugin "${pluginName}".\n${result.stderr || result.stdout}`,
|
|
60
|
+
'api'
|
|
61
|
+
);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Read the new version from the plugin's package.json
|
|
66
|
+
let newVersion = 'unknown';
|
|
67
|
+
try {
|
|
68
|
+
const pluginPkgPath = path.join(pluginsDir, 'node_modules', entry.package, 'package.json');
|
|
69
|
+
const pluginPkg = JSON.parse(fs.readFileSync(pluginPkgPath, 'utf8'));
|
|
70
|
+
newVersion = pluginPkg.version || 'unknown';
|
|
71
|
+
} catch (err) {
|
|
72
|
+
// Could not read version
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Update the version in plugins.json
|
|
76
|
+
plugins[pluginName].version = newVersion;
|
|
77
|
+
fs.writeFileSync(loader.PLUGINS_FILE, JSON.stringify(plugins, null, 2) + '\n');
|
|
78
|
+
|
|
79
|
+
// Report the result
|
|
80
|
+
if (newVersion !== previousVersion) {
|
|
81
|
+
context.output.info(`Updated ${pluginName} from ${previousVersion} to ${newVersion}.`);
|
|
82
|
+
} else {
|
|
83
|
+
context.output.info(`${pluginName} is already at the latest version (${newVersion}).`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
module.exports = { meta, run };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth service registration.
|
|
3
|
+
* OAuth and credential management.
|
|
4
|
+
*/
|
|
5
|
+
module.exports = {
|
|
6
|
+
name: 'auth',
|
|
7
|
+
description: 'OAuth and credential management',
|
|
8
|
+
commands: {
|
|
9
|
+
login: () => require('./login'),
|
|
10
|
+
logout: () => require('./logout'),
|
|
11
|
+
list: () => require('./list'),
|
|
12
|
+
status: () => require('./status'),
|
|
13
|
+
refresh: () => require('./refresh'),
|
|
14
|
+
}
|
|
15
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { AUTH_SERVICES, readCredential, getTokenStatus } = require('./services');
|
|
4
|
+
|
|
5
|
+
const meta = {
|
|
6
|
+
description: 'List all connected services and their token status',
|
|
7
|
+
arguments: [],
|
|
8
|
+
flags: []
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Run the auth list command.
|
|
13
|
+
* Scans all known services from AUTH_SERVICES and shows their auth status.
|
|
14
|
+
* Shows 'valid', 'expired', or 'missing' for each service.
|
|
15
|
+
*
|
|
16
|
+
* @param {object} args - Parsed CLI arguments (positional, flags).
|
|
17
|
+
* @param {object} context - CLI context (output, prompt, errors).
|
|
18
|
+
*/
|
|
19
|
+
async function run(args, context) {
|
|
20
|
+
const services = Object.keys(AUTH_SERVICES);
|
|
21
|
+
const results = [];
|
|
22
|
+
|
|
23
|
+
for (const service of services) {
|
|
24
|
+
const config = AUTH_SERVICES[service];
|
|
25
|
+
const credential = readCredential(service);
|
|
26
|
+
const status = getTokenStatus(credential);
|
|
27
|
+
|
|
28
|
+
results.push({
|
|
29
|
+
service: service,
|
|
30
|
+
type: config.type,
|
|
31
|
+
status: status,
|
|
32
|
+
authenticatedAt: credential && credential.authenticatedAt ? credential.authenticatedAt : '-'
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Check if any services are connected
|
|
37
|
+
const hasConnected = results.some(r => r.status !== 'missing');
|
|
38
|
+
|
|
39
|
+
if (!hasConnected) {
|
|
40
|
+
context.output.info('No services authenticated. Run "dev auth login <service>" to connect.');
|
|
41
|
+
context.output.info('');
|
|
42
|
+
context.output.info('Available services: ' + services.join(', '));
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
context.output.out(results);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
module.exports = { meta, run };
|