@hzlmy2002/web-market 0.1.1 → 0.1.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 CHANGED
@@ -7,12 +7,22 @@ Node/TypeScript stdio MCP for focused website competitive analysis. Five tools c
7
7
  Requires Node 22 or newer. Run one of these commands in a terminal:
8
8
 
9
9
  ```sh
10
- npx -y @hzlmy2002/web-market@0.1.1 setup --client codex
11
- npx -y @hzlmy2002/web-market@0.1.1 setup --client claude-code
12
- npx -y @hzlmy2002/web-market@0.1.1 setup --client hermes
10
+ npx -y @hzlmy2002/web-market@0.1.2 setup --client codex
11
+ npx -y @hzlmy2002/web-market@0.1.2 setup --client claude-code
12
+ npx -y @hzlmy2002/web-market@0.1.2 setup --client hermes
13
13
  ```
14
14
 
15
- This installs the Skill and registers a version-pinned `npx -y @hzlmy2002/web-market@0.1.1 serve` MCP command. Clearing the npm cache does not invalidate the configured path: npx downloads the pinned release again when necessary. Restart or refresh the client to discover the Skill. If no key is configured, setup prompts for hidden input and saves the key in the selected client’s MCP `env.AISA_API_KEY` setting. This works independently of shell startup files on macOS, Linux, and Windows. Existing saved keys are reused. If `AISA_API_KEY` is already set in the setup environment, setup keeps using environment-based authentication without copying the key; the client must inherit that variable. Non-interactive setup without a saved or environment key exits with instructions. Use `uninstall --client ...` to remove an unchanged managed installation.
15
+ This installs the Skill and registers a version-pinned `npx -y @hzlmy2002/web-market@0.1.2 serve` MCP command. Clearing the npm cache does not invalidate the configured path: npx downloads the pinned release again when necessary. Restart or refresh the client to discover the Skill. If no key is configured, setup prompts for hidden input and saves the key in the selected client’s MCP `env.AISA_API_KEY` setting. This works independently of shell startup files on macOS, Linux, and Windows. Existing saved keys are reused. If `AISA_API_KEY` is already set in the setup environment, setup keeps using environment-based authentication without copying the key; the client must inherit that variable. Non-interactive setup without a saved or environment key exits with instructions. Use `uninstall --client ...` to remove an unchanged managed installation.
16
+
17
+ When testing the published release from this source repository, first change to another directory (for example, `cd ~`). npm exec/npx can select the current project when its name and version match the requested package, but a source checkout has no installed `aisa-web-market` command link. This results in `sh: aisa-web-market: command not found`. Alternatively, use the local setup command below after building.
18
+
19
+ ## Automatic client detection
20
+
21
+ Run `npx -y @hzlmy2002/web-market@0.1.2 setup` to install for every detected client. From a built source checkout, use `node dist/cli.js setup`. Detection checks `.codex/`, `.claude/` or `.claude.json`, and `.hermes/` in the user's home directory (or `--home`). These are usage traces, not proof that the executable is still installed. Shared `.agents/` directories alone do not count as detection.
22
+
23
+ Use `--client` to select a single client or install before its first run. If nothing is detected, setup explains how to proceed without creating client configurations. Custom client configuration roots are not discovered automatically. A newly entered key is requested once and reused for clients needing a key; existing client keys remain in place. Installation results are reported per client; a failure does not undo successful installations, and any failure produces a nonzero exit status. Uninstall still requires `--client`.
24
+
25
+ Automatic detection is available starting with version 0.1.2. Windows uses the same home-directory markers, but the full workflow has not yet been tested on a Windows machine.
16
26
 
17
27
  ## Local setup
18
28
 
package/dist/cli.js CHANGED
@@ -1,26 +1,40 @@
1
1
  #!/usr/bin/env node
2
- import { resolveSetupKey } from './credentials.js';
2
+ import { sharedSetupKeyResolver } from './credentials.js';
3
3
  import { parseArgs } from 'node:util';
4
4
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
5
5
  import { createServer } from './server.js';
6
- import { install } from './install.js';
6
+ import { detectClients, install } from './install.js';
7
7
  async function main() {
8
8
  const { values, positionals } = parseArgs({ allowPositionals: true, options: { client: { type: 'string' }, home: { type: 'string' }, 'install-skills': { type: 'boolean' }, help: { type: 'boolean' } } });
9
9
  const command = positionals[0] ?? 'serve';
10
10
  if (values.help) {
11
- console.log('aisa-web-market serve [--install-skills --client codex|claude-code|hermes]\naisa-web-market setup|uninstall --client codex|claude-code|hermes [--home directory]\naisa-web-market status\nSet AISA_API_KEY in the server environment. setup prompts for a missing key and saves it in the client MCP configuration.');
11
+ console.log('aisa-web-market serve [--install-skills --client codex|claude-code|hermes]\naisa-web-market setup [--client codex|claude-code|hermes] [--home directory]\naisa-web-market uninstall --client codex|claude-code|hermes [--home directory]\naisa-web-market status\nsetup detects all supported clients in your home directory when --client is omitted. Set AISA_API_KEY in the server environment. setup prompts for a missing key and saves it in the client MCP configuration.');
12
12
  return;
13
13
  }
14
14
  if (positionals.length > 1)
15
15
  throw Error('Unexpected positional argument.');
16
16
  if (command === 'status') {
17
- console.log(JSON.stringify({ credential_configured: Boolean(process.env.AISA_API_KEY?.trim()), authentication: 'bearer', version: '0.1.1' }));
17
+ console.log(JSON.stringify({ credential_configured: Boolean(process.env.AISA_API_KEY?.trim()), authentication: 'bearer', version: '0.1.2' }));
18
18
  return;
19
19
  }
20
20
  if (command === 'setup' || command === 'uninstall') {
21
+ if (command === 'uninstall' && !values.client)
22
+ throw Error('--client is required for uninstall.');
23
+ const clients = values.client ? [values.client] : await detectClients(values.home);
24
+ if (!clients.length)
25
+ throw Error('No supported clients detected. Run a client once, or use setup --client codex|claude-code|hermes.');
21
26
  if (!values.client)
22
- throw Error('--client is required.');
23
- console.log(JSON.stringify(await install(values.client, { home: values.home, remove: command === 'uninstall', resolveKey: command === 'setup' ? resolveSetupKey : undefined })));
27
+ console.error(`Detected clients: ${clients.join(', ')}`);
28
+ const resolveKey = sharedSetupKeyResolver();
29
+ for (const client of clients) {
30
+ try {
31
+ console.log(JSON.stringify(await install(client, { home: values.home, remove: command === 'uninstall', resolveKey: command === 'setup' ? resolveKey : undefined })));
32
+ }
33
+ catch (error) {
34
+ console.error(`${client}: ${error instanceof Error ? error.message : 'Installation failed.'}`);
35
+ process.exitCode = 1;
36
+ }
37
+ }
24
38
  console.log('Client configuration preserves existing values; serialization may reformat comments. A saved key is passed directly to the MCP process; otherwise ensure the client inherits AISA_API_KEY. Restart or refresh the client to load skills.');
25
39
  return;
26
40
  }
@@ -1,2 +1,3 @@
1
1
  export declare function promptKey(): Promise<string>;
2
2
  export declare function resolveSetupKey(savedKey?: string): Promise<string | undefined>;
3
+ export declare function sharedSetupKeyResolver(resolve?: typeof resolveSetupKey): (savedKey?: string) => Promise<string | undefined>;
@@ -60,3 +60,12 @@ export async function resolveSetupKey(savedKey) {
60
60
  return undefined;
61
61
  return promptKey();
62
62
  }
63
+ export function sharedSetupKeyResolver(resolve = resolveSetupKey) {
64
+ let requested;
65
+ return (savedKey) => {
66
+ // Keep each client's existing credentials. Share only the newly requested key.
67
+ if (savedKey?.trim())
68
+ return Promise.resolve(savedKey);
69
+ return requested ??= resolve();
70
+ };
71
+ }
package/dist/install.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export type Client = 'codex' | 'claude-code' | 'hermes';
2
+ export declare function detectClients(home?: string): Promise<Client[]>;
2
3
  export declare const packageRoot: string;
3
4
  export declare function launchEntry(client: Client, root?: string): {
4
5
  env_vars?: string[] | undefined;
package/dist/install.js CHANGED
@@ -5,6 +5,27 @@ import { homedir } from 'node:os';
5
5
  import { fileURLToPath } from 'node:url';
6
6
  import TOML from '@iarna/toml';
7
7
  import YAML from 'yaml';
8
+ export async function detectClients(home = homedir()) {
9
+ const markers = [
10
+ ['codex', '.codex', 'directory'],
11
+ ['claude-code', '.claude', 'directory'],
12
+ ['claude-code', '.claude.json', 'file'],
13
+ ['hermes', '.hermes', 'directory'],
14
+ ];
15
+ const found = new Set();
16
+ for (const [client, relative, kind] of markers) {
17
+ try {
18
+ const stat = await fs.stat(path.resolve(home, relative));
19
+ if (kind === 'directory' ? stat.isDirectory() : stat.isFile())
20
+ found.add(client);
21
+ }
22
+ catch (error) {
23
+ if (error.code !== 'ENOENT' && error.code !== 'ENOTDIR')
24
+ throw error;
25
+ }
26
+ }
27
+ return [...found];
28
+ }
8
29
  export const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
9
30
  const skillName = 'aisa-web-market';
10
31
  // npm/npx installations live in node_modules. Persist a version-pinned registry
@@ -12,7 +33,7 @@ const skillName = 'aisa-web-market';
12
33
  // local Node entry so development changes remain immediately testable.
13
34
  export function launchEntry(client, root = packageRoot) {
14
35
  const command = root.split(path.sep).includes('node_modules')
15
- ? { command: process.platform === 'win32' ? 'npx.cmd' : 'npx', args: ['-y', '@hzlmy2002/web-market@0.1.1', 'serve'] }
36
+ ? { command: process.platform === 'win32' ? 'npx.cmd' : 'npx', args: ['-y', '@hzlmy2002/web-market@0.1.2', 'serve'] }
16
37
  : { command: process.execPath, args: [path.join(root, 'dist/cli.js'), 'serve'] };
17
38
  return { ...command, ...(client === 'codex' ? { env_vars: ['AISA_API_KEY'] } : {}) };
18
39
  }
@@ -96,7 +117,7 @@ export async function install(client, options = {}) {
96
117
  const root = skillRoot(client, home);
97
118
  const entry = launchEntry(client);
98
119
  const writes = new Map();
99
- const next = { version: '0.1.1', files: {}, config: previous.config, configHash: previous.configHash };
120
+ const next = { version: '0.1.2', files: {}, config: previous.config, configHash: previous.configHash };
100
121
  const bundled = await skillFiles(path.join(packageRoot, 'skills', skillName));
101
122
  for (const relative of new Set([...Object.keys(bundled), ...Object.keys(previous.files)])) {
102
123
  if (path.isAbsolute(relative) || relative.split(/[\\/]/).includes('..'))
package/dist/server.js CHANGED
@@ -3,7 +3,7 @@ import { ApiClient, safeError } from './api.js';
3
3
  import { inputs, output } from './schema.js';
4
4
  import { execute, descriptions } from './tools.js';
5
5
  export function createServer(api = new ApiClient()) {
6
- const server = new McpServer({ name: 'aisa-web-market', version: '0.1.1' }, { instructions: 'Website competitive analysis using five AIsa tools. Use the installed aisa-web-market skill for scenario guidance. Compare identical scope and preserve missing-data evidence. API calls are billed. Credentials come from AISA_API_KEY; never request the key in conversation.' });
6
+ const server = new McpServer({ name: 'aisa-web-market', version: '0.1.2' }, { instructions: 'Website competitive analysis using five AIsa tools. Use the installed aisa-web-market skill for scenario guidance. Compare identical scope and preserve missing-data evidence. API calls are billed. Credentials come from AISA_API_KEY; never request the key in conversation.' });
7
7
  for (const name of Object.keys(inputs)) {
8
8
  server.registerTool(name, { description: descriptions[name], inputSchema: inputs[name], outputSchema: output.shape, annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: false, openWorldHint: true } }, async (args, extra) => {
9
9
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hzlmy2002/web-market",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Focused website competitive analysis: five MCP tools and a portable skill",
5
5
  "type": "module",
6
6
  "bin": {