@rse/ase 0.9.33 → 0.9.34

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/dst/ase-setup.js CHANGED
@@ -153,7 +153,8 @@ export default class SetupCommand {
153
153
  }
154
154
  }
155
155
  /* handler for "ase setup install" (both tools) */
156
- async doInstall(tool, dev) {
156
+ async doInstall(tool, dev, scope) {
157
+ this.requireClaudeScope(tool, scope);
157
158
  const spec = toolSpecs[tool];
158
159
  await this.ensureTool("npm");
159
160
  await this.ensureTool(spec.cli);
@@ -162,15 +163,18 @@ export default class SetupCommand {
162
163
  `installing ASE ${spec.label} plugin (origin: ${dev ? "local" : "remote/bundled"})`);
163
164
  const pkgdir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
164
165
  const source = dev ? path.resolve(pkgdir, "..") : pkgdir;
165
- await this.run(spec.cli, ["plugin", "marketplace", "add", source]);
166
- await this.run(spec.cli, ["plugin", spec.pInstall, "ase@ase"], { retries: 3 });
166
+ const scopeArgs = tool === "claude" ? ["--scope", scope] : [];
167
+ await this.run(spec.cli, ["plugin", "marketplace", "add", source, ...scopeArgs]);
168
+ await this.run(spec.cli, ["plugin", spec.pInstall, "ase@ase", ...scopeArgs], { retries: 3 });
167
169
  return 0;
168
170
  }
169
171
  /* handler for "ase setup update" (both tools) */
170
- async doUpdate(tool, force, dev) {
172
+ async doUpdate(tool, force, dev, scope) {
173
+ this.requireClaudeScope(tool, scope);
171
174
  const spec = toolSpecs[tool];
172
175
  await this.ensureTool("npm");
173
176
  await this.ensureTool(spec.cli);
177
+ const scopeArgs = tool === "claude" ? ["--scope", scope] : [];
174
178
  /* best-effort stop of background service */
175
179
  this.log.write("info", `setup: update${dev ? "[dev]" : ""}: ` +
176
180
  "stopping potentially running ASE service");
@@ -186,8 +190,8 @@ export default class SetupCommand {
186
190
  but there is no version change in the plugin manifest,
187
191
  so just re-install the plugin to let the tool update its copy */
188
192
  this.log.write("info", `setup: update[dev]: re-install ASE ${spec.label} plugin (origin: local)`);
189
- await this.run(spec.cli, ["plugin", spec.pRemove, "ase@ase"], { ignoreError: `ASE ${spec.label} plugin not installed` });
190
- await this.run(spec.cli, ["plugin", spec.pInstall, "ase@ase"], { retries: 3 });
193
+ await this.run(spec.cli, ["plugin", spec.pRemove, "ase@ase", ...scopeArgs], { ignoreError: `ASE ${spec.label} plugin not installed` });
194
+ await this.run(spec.cli, ["plugin", spec.pInstall, "ase@ase", ...scopeArgs], { retries: 3 });
191
195
  }
192
196
  else {
193
197
  /* perform NPM version check */
@@ -204,49 +208,55 @@ export default class SetupCommand {
204
208
  await this.run(updateCmd.cmd, updateCmd.args);
205
209
  /* update ASE plugin (refresh the marketplace snapshot, then
206
210
  update the plugin itself; the OpenAI Codex CLI has no
207
- "plugin update" subcommand, so re-install it instead) */
211
+ "plugin update" subcommand, so re-install it instead;
212
+ "plugin marketplace update" has no "--scope" option at all,
213
+ so it never receives one) */
208
214
  this.log.write("info", `setup: update: updating ASE ${spec.label} plugin`);
209
215
  await this.run(spec.cli, ["plugin", "marketplace", spec.pUpdate, "ase"]);
210
216
  if (tool !== "codex")
211
- await this.run(spec.cli, ["plugin", "update", "ase@ase"]);
217
+ await this.run(spec.cli, ["plugin", "update", "ase@ase", ...scopeArgs]);
212
218
  else {
213
- await this.run(spec.cli, ["plugin", spec.pRemove, "ase@ase"], { ignoreError: `ASE ${spec.label} plugin not installed` });
214
- await this.run(spec.cli, ["plugin", spec.pInstall, "ase@ase"], { retries: 3 });
219
+ await this.run(spec.cli, ["plugin", spec.pRemove, "ase@ase", ...scopeArgs], { ignoreError: `ASE ${spec.label} plugin not installed` });
220
+ await this.run(spec.cli, ["plugin", spec.pInstall, "ase@ase", ...scopeArgs], { retries: 3 });
215
221
  }
216
222
  }
217
223
  return 0;
218
224
  }
219
225
  /* handler for "ase setup enable" (both tools) */
220
- async doEnable(tool) {
226
+ async doEnable(tool, scope) {
227
+ this.requireClaudeScope(tool, scope);
221
228
  const spec = toolSpecs[tool];
222
229
  await this.ensureTool(spec.cli);
223
230
  this.log.write("info", `setup: enable: enabling ASE ${spec.label} plugin`);
224
231
  /* the GitHub Copilot CLI and OpenAI Codex CLI have no "plugin
225
232
  enable" subcommand, so (re-)install the plugin instead */
226
233
  const args = tool === "claude" ?
227
- ["plugin", "enable", "ase@ase"] :
234
+ ["plugin", "enable", "ase@ase", "--scope", scope] :
228
235
  ["plugin", spec.pInstall, "ase@ase"];
229
236
  await this.run(spec.cli, args, { retries: tool === "claude" ? 1 : 3 });
230
237
  return 0;
231
238
  }
232
239
  /* handler for "ase setup disable" (both tools) */
233
- async doDisable(tool) {
240
+ async doDisable(tool, scope) {
241
+ this.requireClaudeScope(tool, scope);
234
242
  const spec = toolSpecs[tool];
235
243
  await this.ensureTool(spec.cli);
236
244
  this.log.write("info", `setup: disable: disabling ASE ${spec.label} plugin`);
237
245
  /* the GitHub Copilot CLI and OpenAI Codex CLI have no "plugin
238
246
  disable" subcommand, so uninstall the plugin instead */
239
247
  const args = tool === "claude" ?
240
- ["plugin", "disable", "ase@ase"] :
248
+ ["plugin", "disable", "ase@ase", "--scope", scope] :
241
249
  ["plugin", spec.pRemove, "ase@ase"];
242
250
  await this.run(spec.cli, args, { retries: tool === "claude" ? 1 : 3 });
243
251
  return 0;
244
252
  }
245
253
  /* handler for "ase setup uninstall" (both tools) */
246
- async doUninstall(tool, dev) {
254
+ async doUninstall(tool, dev, scope) {
255
+ this.requireClaudeScope(tool, scope);
247
256
  const spec = toolSpecs[tool];
248
257
  await this.ensureTool("npm");
249
258
  await this.ensureTool(spec.cli);
259
+ const scopeArgs = tool === "claude" ? ["--scope", scope] : [];
250
260
  /* best-effort stop of background service */
251
261
  this.log.write("info", `setup: uninstall${dev ? "[dev]" : ""}: ` +
252
262
  "stopping potentially running ASE service");
@@ -254,8 +264,8 @@ export default class SetupCommand {
254
264
  /* uninstall ASE plugin */
255
265
  this.log.write("info", `setup: uninstall${dev ? "[dev]" : ""}: ` +
256
266
  `uninstalling ASE ${spec.label} plugin (origin: ${dev ? "local" : "remote/bundled"})`);
257
- await this.run(spec.cli, ["plugin", spec.pRemove, "ase@ase"], { ignoreError: `ASE ${spec.label} plugin not installed` });
258
- await this.run(spec.cli, ["plugin", "marketplace", "remove", "ase"], { ignoreError: `ASE ${spec.label} plugin marketplace not registered` });
267
+ await this.run(spec.cli, ["plugin", spec.pRemove, "ase@ase", ...scopeArgs], { ignoreError: `ASE ${spec.label} plugin not installed` });
268
+ await this.run(spec.cli, ["plugin", "marketplace", "remove", "ase", ...scopeArgs], { ignoreError: `ASE ${spec.label} plugin marketplace not registered` });
259
269
  /* uninstall ASE CLI tool (non-development only) */
260
270
  if (!dev) {
261
271
  this.log.write("info", "setup: uninstall: uninstalling ASE CLI tool (origin: remote)");
@@ -286,7 +296,8 @@ export default class SetupCommand {
286
296
  return 0;
287
297
  }
288
298
  /* handler for "ase setup mcp activate|deactivate [<servers>]" */
289
- async doMcp(action, tool, servers) {
299
+ async doMcp(action, tool, servers, scope) {
300
+ this.requireClaudeScope(tool, scope);
290
301
  await this.ensureTool(toolSpecs[tool].cli);
291
302
  /* source .env files into the environment so the per-server
292
303
  API keys (ASE_MCP_KEY_<XXX>) can live in a .env file instead
@@ -336,7 +347,7 @@ export default class SetupCommand {
336
347
  if (installed) {
337
348
  this.log.write("info", `setup: mcp: activate: [${id}]: MCP server "${handle.server}" ` +
338
349
  "already registered: removing stale registration first");
339
- await this.mcpRemove(tool, handle.server);
350
+ await this.mcpRemove(tool, handle.server, scope);
340
351
  }
341
352
  }
342
353
  else if (!installed) {
@@ -348,7 +359,7 @@ export default class SetupCommand {
348
359
  /* call the handler */
349
360
  this.log.write("info", `setup: mcp: ${action}: [${id}]: MCP server "${handle.server}" ` +
350
361
  `(name: ${handle.name}${handle.version ? (", version: " + handle.version) : ""})`);
351
- await handle.handler(handle, tool, action, envKey, envVal);
362
+ await handle.handler(handle, tool, scope, action, envKey, envVal);
352
363
  }
353
364
  return 0;
354
365
  }
@@ -362,10 +373,10 @@ export default class SetupCommand {
362
373
  (a local subprocess command) and "http" (a remote URL, optionally
363
374
  with HTTP headers) transports; the per-tool command line differs
364
375
  between Anthropic Claude Code CLI, GitHub Copilot CLI, and OpenAI Codex CLI */
365
- async mcpAdd(tool, name, env, transport) {
376
+ async mcpAdd(tool, name, env, transport, scope) {
366
377
  const args = ["mcp", "add"];
367
378
  if (tool === "claude") {
368
- args.push("--scope", "user");
379
+ args.push("--scope", scope);
369
380
  args.push("--transport", transport.type);
370
381
  if (transport.type === "stdio") {
371
382
  for (const [key, val] of Object.entries(env))
@@ -417,9 +428,9 @@ export default class SetupCommand {
417
428
  }
418
429
  /* unregister an MCP server from the tool; the per-tool command line
419
430
  differs between Anthropic Claude Code CLI, GitHub Copilot CLI, and OpenAI Codex CLI */
420
- async mcpRemove(tool, name) {
431
+ async mcpRemove(tool, name, scope) {
421
432
  const args = tool === "claude" ?
422
- ["mcp", "remove", "--scope", "user", name] :
433
+ ["mcp", "remove", "--scope", scope, name] :
423
434
  ["mcp", "remove", name];
424
435
  await this.run(toolSpecs[tool].cli, args, { ignoreError: `MCP server "${name}" not registered` });
425
436
  }
@@ -427,7 +438,7 @@ export default class SetupCommand {
427
438
  OPENROUTER url/api/model triples, factoring out the shared
428
439
  mcp-to-openai stdio scaffold common to all chat-model servers */
429
440
  chatMcpHandler(direct, router) {
430
- return async (spec, tool, action, envKey, envVal) => {
441
+ return async (spec, tool, scope, action, envKey, envVal) => {
431
442
  if (action === "activate")
432
443
  await this.mcpAdd(tool, spec.server, { OPENAI_KEY: envVal }, {
433
444
  type: "stdio", command: [
@@ -444,9 +455,9 @@ export default class SetupCommand {
444
455
  "--openai-model", direct.model
445
456
  ])
446
457
  ]
447
- });
458
+ }, scope);
448
459
  else
449
- await this.mcpRemove(tool, spec.server);
460
+ await this.mcpRemove(tool, spec.server, scope);
450
461
  };
451
462
  }
452
463
  /* registry of pre-defined MCP servers: maps each server id onto its
@@ -513,14 +524,14 @@ export default class SetupCommand {
513
524
  env: ["BRAVE"],
514
525
  server: "search-brave",
515
526
  skills: ["ase-meta-search", "ase-meta-evaluate", "ase-arch-discover"],
516
- handler: async (spec, tool, action, _envKey, envVal) => {
527
+ handler: async (spec, tool, scope, action, _envKey, envVal) => {
517
528
  if (action === "activate")
518
529
  await this.mcpAdd(tool, spec.server, {
519
530
  "BRAVE_API_KEY": envVal,
520
531
  "BRAVE_MCP_ENABLED_TOOLS": "brave_web_search"
521
- }, { type: "stdio", command: ["npx", "-y", "@brave/brave-search-mcp-server"] });
532
+ }, { type: "stdio", command: ["npx", "-y", "@brave/brave-search-mcp-server"] }, scope);
522
533
  else
523
- await this.mcpRemove(tool, spec.server);
534
+ await this.mcpRemove(tool, spec.server, scope);
524
535
  }
525
536
  },
526
537
  {
@@ -530,13 +541,13 @@ export default class SetupCommand {
530
541
  env: ["PERPLEXITY"],
531
542
  server: "search-perplexity",
532
543
  skills: ["ase-meta-search", "ase-meta-evaluate", "ase-arch-discover"],
533
- handler: async (spec, tool, action, _envKey, envVal) => {
544
+ handler: async (spec, tool, scope, action, _envKey, envVal) => {
534
545
  if (action === "activate")
535
546
  await this.mcpAdd(tool, spec.server, {
536
547
  "PERPLEXITY_API_KEY": envVal
537
- }, { type: "stdio", command: ["npx", "-y", "@perplexity-ai/mcp-server"] });
548
+ }, { type: "stdio", command: ["npx", "-y", "@perplexity-ai/mcp-server"] }, scope);
538
549
  else
539
- await this.mcpRemove(tool, spec.server);
550
+ await this.mcpRemove(tool, spec.server, scope);
540
551
  }
541
552
  },
542
553
  {
@@ -546,11 +557,11 @@ export default class SetupCommand {
546
557
  env: ["EXA"],
547
558
  server: "search-exa",
548
559
  skills: ["ase-meta-search", "ase-meta-evaluate", "ase-arch-discover"],
549
- handler: async (spec, tool, action, _envKey, envVal) => {
560
+ handler: async (spec, tool, scope, action, _envKey, envVal) => {
550
561
  if (action === "activate")
551
- await this.mcpAdd(tool, spec.server, {}, { type: "http", url: `https://mcp.exa.ai/mcp?exaApiKey=${envVal}` });
562
+ await this.mcpAdd(tool, spec.server, {}, { type: "http", url: `https://mcp.exa.ai/mcp?exaApiKey=${envVal}` }, scope);
552
563
  else
553
- await this.mcpRemove(tool, spec.server);
564
+ await this.mcpRemove(tool, spec.server, scope);
554
565
  }
555
566
  }
556
567
  ];
@@ -560,6 +571,18 @@ export default class SetupCommand {
560
571
  throw new Error(`invalid --tool value: "${value}" (expected "claude", "copilot", or "codex")`);
561
572
  return value;
562
573
  }
574
+ /* parse and validate the --scope option */
575
+ parseScope(value) {
576
+ if (value !== "user" && value !== "project" && value !== "local")
577
+ throw new Error(`invalid --scope value: "${value}" (expected "user", "project", or "local")`);
578
+ return value;
579
+ }
580
+ /* reject a non-default --scope for tools which have no scope concept
581
+ at all (only Anthropic Claude Code CLI supports plugin/MCP scopes) */
582
+ requireClaudeScope(tool, scope) {
583
+ if (tool !== "claude" && scope !== "user")
584
+ throw new Error("--scope is only supported for --tool claude");
585
+ }
563
586
  /* register commands */
564
587
  register(program) {
565
588
  /* default for --dev derived from ASE_SETUP_DEV environment variable */
@@ -581,44 +604,49 @@ export default class SetupCommand {
581
604
  .command("install")
582
605
  .description("install the ASE plugin for a tool")
583
606
  .option("-t, --tool <tool>", "target tool (\"claude\", \"copilot\", or \"codex\")", toolDflt)
607
+ .option("-s, --scope <scope>", "target scope (\"user\", \"project\", or \"local\")", "user")
584
608
  .option("-d, --dev", "use local working copy instead of remote/bundled repository", devDflt)
585
609
  .action(async (opts) => {
586
- process.exit(await this.doInstall(this.parseTool(opts.tool), opts.dev));
610
+ process.exit(await this.doInstall(this.parseTool(opts.tool), opts.dev, this.parseScope(opts.scope)));
587
611
  });
588
612
  /* register CLI sub-command "ase setup update" */
589
613
  setupCmd
590
614
  .command("update")
591
615
  .description("update the ASE tool and the ASE plugin for a tool")
592
616
  .option("-t, --tool <tool>", "target tool (\"claude\", \"copilot\", or \"codex\")", toolDflt)
617
+ .option("-s, --scope <scope>", "target scope (\"user\", \"project\", or \"local\")", "user")
593
618
  .option("-f, --force", "always perform the update, even if already at latest version", false)
594
619
  .option("-d, --dev", "use local working copy instead of remote/bundled repository", devDflt)
595
620
  .action(async (opts) => {
596
- process.exit(await this.doUpdate(this.parseTool(opts.tool), opts.force, opts.dev));
621
+ process.exit(await this.doUpdate(this.parseTool(opts.tool), opts.force, opts.dev, this.parseScope(opts.scope)));
597
622
  });
598
623
  /* register CLI sub-command "ase setup uninstall" */
599
624
  setupCmd
600
625
  .command("uninstall")
601
626
  .description("uninstall the ASE plugin for a tool and the ASE tool")
602
627
  .option("-t, --tool <tool>", "target tool (\"claude\", \"copilot\", or \"codex\")", toolDflt)
628
+ .option("-s, --scope <scope>", "target scope (\"user\", \"project\", or \"local\")", "user")
603
629
  .option("-d, --dev", "use local working copy instead of remote/bundled repository", devDflt)
604
630
  .action(async (opts) => {
605
- process.exit(await this.doUninstall(this.parseTool(opts.tool), opts.dev));
631
+ process.exit(await this.doUninstall(this.parseTool(opts.tool), opts.dev, this.parseScope(opts.scope)));
606
632
  });
607
633
  /* register CLI sub-command "ase setup enable" */
608
634
  setupCmd
609
635
  .command("enable")
610
636
  .description("enable the ASE plugin for a tool")
611
637
  .option("-t, --tool <tool>", "target tool (\"claude\", \"copilot\", or \"codex\")", toolDflt)
638
+ .option("-s, --scope <scope>", "target scope (\"user\", \"project\", or \"local\")", "user")
612
639
  .action(async (opts) => {
613
- process.exit(await this.doEnable(this.parseTool(opts.tool)));
640
+ process.exit(await this.doEnable(this.parseTool(opts.tool), this.parseScope(opts.scope)));
614
641
  });
615
642
  /* register CLI sub-command "ase setup disable" */
616
643
  setupCmd
617
644
  .command("disable")
618
645
  .description("disable the ASE plugin for a tool")
619
646
  .option("-t, --tool <tool>", "target tool (\"claude\", \"copilot\", or \"codex\")", toolDflt)
647
+ .option("-s, --scope <scope>", "target scope (\"user\", \"project\", or \"local\")", "user")
620
648
  .action(async (opts) => {
621
- process.exit(await this.doDisable(this.parseTool(opts.tool)));
649
+ process.exit(await this.doDisable(this.parseTool(opts.tool), this.parseScope(opts.scope)));
622
650
  });
623
651
  /* register CLI sub-command "ase setup mcp" */
624
652
  const mcpCmd = setupCmd
@@ -640,16 +668,18 @@ export default class SetupCommand {
640
668
  .command("activate [servers]")
641
669
  .description("activate pre-defined MCP servers (comma-separated list, or \"all\")")
642
670
  .option("-t, --tool <tool>", "target tool (\"claude\", \"copilot\", or \"codex\")", toolDflt)
671
+ .option("-s, --scope <scope>", "target scope (\"user\", \"project\", or \"local\")", "user")
643
672
  .action(async (servers, opts) => {
644
- process.exit(await this.doMcp("activate", this.parseTool(opts.tool), servers ?? "all"));
673
+ process.exit(await this.doMcp("activate", this.parseTool(opts.tool), servers ?? "all", this.parseScope(opts.scope)));
645
674
  });
646
675
  /* register CLI sub-command "ase setup mcp deactivate" */
647
676
  mcpCmd
648
677
  .command("deactivate [servers]")
649
678
  .description("deactivate pre-defined MCP servers (comma-separated list, or \"all\")")
650
679
  .option("-t, --tool <tool>", "target tool (\"claude\", \"copilot\", or \"codex\")", toolDflt)
680
+ .option("-s, --scope <scope>", "target scope (\"user\", \"project\", or \"local\")", "user")
651
681
  .action(async (servers, opts) => {
652
- process.exit(await this.doMcp("deactivate", this.parseTool(opts.tool), servers ?? "all"));
682
+ process.exit(await this.doMcp("deactivate", this.parseTool(opts.tool), servers ?? "all", this.parseScope(opts.scope)));
653
683
  });
654
684
  }
655
685
  }
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "homepage": "http://github.com/rse/ase",
7
7
  "repository": { "url": "git+https://github.com/rse/ase.git", "type": "git" },
8
8
  "bugs": { "url": "http://github.com/rse/ase/issues" },
9
- "version": "0.9.33",
9
+ "version": "0.9.34",
10
10
  "license": "Apache-2.0",
11
11
  "author": {
12
12
  "name": "Dr. Ralf S. Engelschall",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ase",
3
- "version": "0.9.33",
3
+ "version": "0.9.34",
4
4
  "description": "Agentic Software Engineering (ASE)",
5
5
  "keywords": [ "agentic", "software", "engineering" ],
6
6
  "homepage": "https://ase.tools",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ase",
3
- "version": "0.9.33",
3
+ "version": "0.9.34",
4
4
  "description": "Agentic Software Engineering (ASE)",
5
5
  "keywords": [ "agentic", "software", "engineering" ],
6
6
  "homepage": "https://ase.tools",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ase",
3
- "version": "0.9.33",
3
+ "version": "0.9.34",
4
4
  "description": "Agentic Software Engineering (ASE)",
5
5
  "keywords": [ "agentic", "software", "engineering" ],
6
6
  "homepage": "https://ase.tools",
@@ -6,7 +6,7 @@
6
6
  "homepage": "http://github.com/rse/ase",
7
7
  "repository": { "url": "git+https://github.com/rse/ase.git", "type": "git" },
8
8
  "bugs": { "url": "http://github.com/rse/ase/issues" },
9
- "version": "0.9.33",
9
+ "version": "0.9.34",
10
10
  "license": "Apache-2.0",
11
11
  "author": {
12
12
  "name": "Dr. Ralf S. Engelschall",