You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/users/extension/introduction.md
+24-6Lines changed: 24 additions & 6 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -12,11 +12,11 @@ We offer a suite of extension management tools using both `qwen extensions` CLI
12
12
13
13
You can manage extensions at runtime within the interactive CLI using `/extensions` slash commands. These commands support hot-reloading, meaning changes take effect immediately without restarting the application.
The archive must contain a complete extension at its root, or a single top-level directory containing the extension.
142
+
134
143
Note that we create a copy of the installed extension, so you will need to run `qwen extensions update` to pull in changes from both locally-defined extensions and those on GitHub.
Archive URLs can be updated later as long as the URL continues to point at a newer archive for the same extension.
153
+
136
154
### Uninstalling an extension
137
155
138
156
To uninstall, run `qwen extensions uninstall extension-name`, so, in the case of the install example:
@@ -155,7 +173,7 @@ This is useful if you have an extension disabled at the top-level and only enabl
155
173
156
174
### Updating an extension
157
175
158
-
For extensions installed from a local path, a git repository, or an npm registry, you can explicitly update to the latest version with `qwen extensions update extension-name`. For npm extensions installed without a version pin (e.g. `@scope/pkg`), updates check the `latest` dist-tag. For those installed with a specific dist-tag (e.g. `@scope/pkg@beta`), updates track that tag. Extensions pinned to an exact version (e.g. `@scope/pkg@1.2.0`) are always considered up-to-date.
176
+
For extensions installed from a local path or archive, an archive URL, a git repository, or an npm registry, you can explicitly update to the latest version with `qwen extensions update extension-name`. For npm extensions installed without a version pin (e.g. `@scope/pkg`), updates check the `latest` dist-tag. For those installed with a specific dist-tag (e.g. `@scope/pkg@beta`), updates track that tag. Extensions pinned to an exact version (e.g. `@scope/pkg@1.2.0`) are always considered up-to-date.
it('should print archive validation errors from the extension manager',async()=>{
285
+
constprocessSpy=vi
286
+
.spyOn(process,'exit')
287
+
.mockImplementation(()=>undefinedasnever);
288
+
289
+
mockParseInstallSource.mockResolvedValue({
290
+
type: 'git',
291
+
source: 'owner/repo',
292
+
});
293
+
mockInstallExtension.mockRejectedValue(
294
+
newError(
295
+
'Extension archive is missing qwen-extension.json. The archive must contain a complete extension at its root, or a single top-level extension directory.',
296
+
),
297
+
);
298
+
299
+
awaithandleInstall({source: 'owner/repo'});
300
+
301
+
expect(mockWriteStderrLine).toHaveBeenCalledWith(
302
+
'Extension archive is missing qwen-extension.json. The archive must contain a complete extension at its root, or a single top-level extension directory.',
Copy file name to clipboardExpand all lines: packages/cli/src/commands/extensions/install.ts
+12-5Lines changed: 12 additions & 5 deletions
Original file line number
Diff line number
Diff line change
@@ -37,7 +37,8 @@ export async function handleInstall(args: InstallArgs) {
37
37
if(
38
38
installMetadata.type!=='git'&&
39
39
installMetadata.type!=='github-release'&&
40
-
installMetadata.type!=='npm'
40
+
installMetadata.type!=='npm'&&
41
+
installMetadata.type!=='archive-url'
41
42
){
42
43
if(args.ref||args.autoUpdate){
43
44
thrownewError(
@@ -48,10 +49,16 @@ export async function handleInstall(args: InstallArgs) {
48
49
}
49
50
}
50
51
51
-
if(installMetadata.type==='npm'&&args.ref){
52
+
if(
53
+
(installMetadata.type==='npm'||
54
+
installMetadata.type==='archive-url')&&
55
+
args.ref
56
+
){
52
57
thrownewError(
53
58
t(
54
-
'--ref is not applicable for npm extensions. Use @version suffix instead (e.g. @scope/package@1.2.0).',
59
+
installMetadata.type==='npm'
60
+
? '--ref is not applicable for npm extensions. Use @version suffix instead (e.g. @scope/package@1.2.0).'
61
+
: '--ref is not applicable for archive URL extensions.',
55
62
),
56
63
);
57
64
}
@@ -101,13 +108,13 @@ export async function handleInstall(args: InstallArgs) {
101
108
exportconstinstallCommand: CommandModule={
102
109
command: 'install <source>',
103
110
describe: t(
104
-
'Installs an extension from a git repository URL, local path, scoped npm package (@scope/name), or claude marketplace (marketplace-url:plugin-name).',
111
+
'Installs an extension from a git repository URL, local path or archive, archive URL, scoped npm package (@scope/name), or claude marketplace (marketplace-url:plugin-name).',
105
112
),
106
113
builder: (yargs)=>
107
114
yargs
108
115
.positional('source',{
109
116
describe: t(
110
-
'The github URL, local path, or marketplace source (marketplace-url:plugin-name) of the extension to install.',
117
+
'The github URL, local path or archive, archive URL, or marketplace source (marketplace-url:plugin-name) of the extension to install.',
0 commit comments