@maptec/cli 1.0.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.
Files changed (43) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +284 -0
  3. package/bin/maptec.js +2 -0
  4. package/dist/chunk-K574OFFK.js +122 -0
  5. package/dist/chunk-K574OFFK.js.map +1 -0
  6. package/dist/cli.js +899 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/store-ZU7HLXCV.js +18 -0
  9. package/dist/store-ZU7HLXCV.js.map +1 -0
  10. package/package.json +47 -0
  11. package/skills/README.md +30 -0
  12. package/skills/jsapi-skills/README.md +60 -0
  13. package/skills/jsapi-skills/SKILL.md +145 -0
  14. package/skills/jsapi-skills/package.json +31 -0
  15. package/skills/jsapi-skills/references/controls.md +195 -0
  16. package/skills/jsapi-skills/references/events.md +222 -0
  17. package/skills/jsapi-skills/references/geocoding.md +184 -0
  18. package/skills/jsapi-skills/references/map-style.md +123 -0
  19. package/skills/jsapi-skills/references/map.md +154 -0
  20. package/skills/jsapi-skills/references/marker.md +136 -0
  21. package/skills/jsapi-skills/references/operate.md +138 -0
  22. package/skills/jsapi-skills/references/overlay.md +311 -0
  23. package/skills/jsapi-skills/references/place-search.md +411 -0
  24. package/skills/jsapi-skills/references/poi-categories.md +123 -0
  25. package/skills/jsapi-skills/references/popup.md +146 -0
  26. package/skills/jsapi-skills/references/re-geocoding.md +183 -0
  27. package/skills/jsapi-skills/references/routing.md +347 -0
  28. package/skills/jsapi-skills/references/track.md +240 -0
  29. package/skills/jsapi-skills/scripts/validate_jsapi_skill.py +160 -0
  30. package/skills/webapi-skills/README.md +73 -0
  31. package/skills/webapi-skills/SKILL.md +63 -0
  32. package/skills/webapi-skills/package.json +32 -0
  33. package/skills/webapi-skills/references/direction-api.md +175 -0
  34. package/skills/webapi-skills/references/geocoding.md +195 -0
  35. package/skills/webapi-skills/references/ip-location.md +87 -0
  36. package/skills/webapi-skills/references/matrix-api.md +149 -0
  37. package/skills/webapi-skills/references/nearby-search.md +223 -0
  38. package/skills/webapi-skills/references/places.md +239 -0
  39. package/skills/webapi-skills/references/quick-start-cn.md +219 -0
  40. package/skills/webapi-skills/references/reverse-geocoding.md +157 -0
  41. package/skills/webapi-skills/references/suggest.md +111 -0
  42. package/skills/webapi-skills/references/text-search.md +282 -0
  43. package/skills/webapi-skills/scripts/validate_webapi_skill.py +158 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli.ts","../src/errors.ts","../src/commands/init.ts","../src/output/json.ts","../src/output/fields.ts","../src/commands/config.ts","../src/api/client.ts","../src/api/geocode.ts","../src/commands/geocode.ts","../src/commands/reverse-geocode.ts","../src/api/location.ts","../src/api/place-search.ts","../src/commands/search.ts","../src/api/directions.ts","../src/api/route-resolve.ts","../src/output/route-fields.ts","../src/commands/route.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { readFileSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport { dirname, join } from 'node:path';\nimport { CliError, ExitCode, exitWithError } from './errors.js';\nimport { loadConfig } from './config/store.js';\nimport { runInit } from './commands/init.js';\nimport { runConfigGet, runConfigSet } from './commands/config.js';\nimport { runGeocode } from './commands/geocode.js';\nimport { runReverseGeocode } from './commands/reverse-geocode.js';\nimport {\n runSearchNearby,\n runSearchPlace,\n runSearchSuggest,\n runSearchText,\n} from './commands/search.js';\nimport { runRoute } from './commands/route.js';\nimport type { OutputFormat, OutputOptions } from './output/json.js';\n\nfunction getVersion(): string {\n try {\n const dir = dirname(fileURLToPath(import.meta.url));\n const pkgPath = join(dir, '..', 'package.json');\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf8')) as { version: string };\n return pkg.version;\n } catch {\n return '0.0.0';\n }\n}\n\nfunction parseFields(value: string): string[] {\n return value.split(',').map((s) => s.trim()).filter(Boolean);\n}\n\nfunction buildOutputOptions(\n globalOpts: {\n format?: string;\n out?: string;\n quiet?: boolean;\n fields?: string;\n },\n): OutputOptions {\n const format = (globalOpts.format ?? 'json') as OutputFormat;\n if (format !== 'json' && format !== 'table') {\n throw new CliError(`无效 --format \"${globalOpts.format}\"`, ExitCode.USER_ERROR);\n }\n return {\n format,\n out: globalOpts.out,\n quiet: globalOpts.quiet,\n fields: globalOpts.fields ? parseFields(globalOpts.fields) : undefined,\n };\n}\n\nasync function main(): Promise<void> {\n const program = new Command();\n\n program\n .name('maptec')\n .description('Maptec 地图 CLI — 结构化 JSON 输出,供开发者与 AI Agent 调用')\n .version(getVersion(), '-V, --version', '显示版本号');\n\n program\n .option('--format <json|table>', '输出格式', 'json')\n .option('--out <file>', '写入文件而非 stdout')\n .option('--quiet', '减少 stderr 进度信息')\n .option('--timeout <ms>', '覆盖默认请求超时(毫秒)')\n .option('--fields <list>', '裁剪输出字段,逗号分隔');\n\n program\n .command('init')\n .description('交互式配置 apiKey 与 baseUrl')\n .action(async () => {\n const globalOpts = program.opts();\n if (globalOpts.timeout) {\n const config = await loadConfig();\n config.timeoutMs = Number(globalOpts.timeout);\n }\n await runInit(buildOutputOptions(globalOpts));\n });\n\n const configCmd = program.command('config').description('读写 ~/.maptec/config.json');\n\n configCmd\n .command('get')\n .description('打印当前配置(apiKey 脱敏)')\n .action(async () => {\n const globalOpts = program.opts();\n await runConfigGet(buildOutputOptions(globalOpts));\n });\n\n configCmd\n .command('set <key> <value>')\n .description('设置配置项:api-key | base-url | default-format | timeout')\n .action(async (key: string, value: string) => {\n const globalOpts = program.opts();\n await runConfigSet(key, value, buildOutputOptions(globalOpts));\n });\n\n program\n .command('geocode')\n .description('正向地理编码:地址 → 坐标')\n .requiredOption('--address <text>', '地址字符串')\n .option('--language <code>', '返回语言,如 zh-CN')\n .option('--region <code>', '地区偏向,如 CN')\n .action(async (opts) => {\n const globalOpts = program.opts();\n await applyTimeoutOverride(globalOpts.timeout);\n await runGeocode(opts, buildOutputOptions(globalOpts));\n });\n\n program\n .command('reverse-geocode')\n .description('反向地理编码:坐标 → 地址')\n .requiredOption('--lat <number>', '纬度', parseFloat)\n .requiredOption('--lng <number>', '经度', parseFloat)\n .option('--language <code>', '返回语言')\n .option('--region <code>', '地区偏向')\n .option('--result-type <types>', '结果类型过滤,竖线分隔')\n .option('--location-type <types>', '精度类型过滤')\n .action(async (opts) => {\n const globalOpts = program.opts();\n await applyTimeoutOverride(globalOpts.timeout);\n await runReverseGeocode(\n {\n lat: opts.lat,\n lng: opts.lng,\n language: opts.language,\n region: opts.region,\n resultType: opts.resultType,\n locationType: opts.locationType,\n },\n buildOutputOptions(globalOpts),\n );\n });\n\n const searchCmd = program.command('search').description('地点搜索');\n\n searchCmd\n .command('text')\n .description('关键词文本搜索')\n .requiredOption('--query <text>', '搜索关键词')\n .option('--location <lng,lat>', '位置偏向(圆心)')\n .option('--language <code>', '语言')\n .option('--region <code>', '地区')\n .option('--page-size <n>', '每页条数', parseInt)\n .option('--type <category>', 'POI 类别')\n .option('--rank <mode>', 'RELEVANCE|DISTANCE|POPULARITY')\n .action(async (opts) => {\n const globalOpts = program.opts();\n await applyTimeoutOverride(globalOpts.timeout);\n await runSearchText(opts, buildOutputOptions(globalOpts));\n });\n\n searchCmd\n .command('nearby')\n .description('附近搜索')\n .requiredOption('--lat <number>', '纬度', parseFloat)\n .requiredOption('--lng <number>', '经度', parseFloat)\n .option('--radius <meters>', '半径(米)', parseInt)\n .option('--types <list>', '类型,逗号分隔')\n .option('--limit <n>', '结果上限', parseInt)\n .option('--language <code>', '语言')\n .option('--region <code>', '地区')\n .option('--rank <mode>', '排序')\n .action(async (opts) => {\n const globalOpts = program.opts();\n await applyTimeoutOverride(globalOpts.timeout);\n await runSearchNearby(\n {\n lat: opts.lat,\n lng: opts.lng,\n radius: opts.radius,\n types: opts.types,\n limit: opts.limit,\n language: opts.language,\n region: opts.region,\n rank: opts.rank,\n },\n buildOutputOptions(globalOpts),\n );\n });\n\n searchCmd\n .command('suggest')\n .description('输入提示 / 自动补全')\n .requiredOption('--query <text>', '输入字符串')\n .option('--location <lng,lat>', '位置偏向')\n .option('--language <code>', '语言')\n .option('--region <code>', '地区')\n .option('--limit <n>', '结果上限', parseInt)\n .action(async (opts) => {\n const globalOpts = program.opts();\n await applyTimeoutOverride(globalOpts.timeout);\n await runSearchSuggest(opts, buildOutputOptions(globalOpts));\n });\n\n searchCmd\n .command('place')\n .description('地点详情')\n .requiredOption('--id <placeId>', '地点 ID')\n .option('--language <code>', '语言')\n .option('--region <code>', '地区')\n .option('--session-token <token>', '会话令牌')\n .action(async (opts) => {\n const globalOpts = program.opts();\n await applyTimeoutOverride(globalOpts.timeout);\n await runSearchPlace(\n {\n id: opts.id,\n language: opts.language,\n region: opts.region,\n sessionToken: opts.sessionToken,\n },\n buildOutputOptions(globalOpts),\n );\n });\n\n const routeCmd = program.command('route').description('路线规划');\n\n const addRouteOptions = (cmd: ReturnType<typeof routeCmd.command>) => {\n cmd\n .option('--from <text>', '起点地址或 lng,lat')\n .option('--to <text>', '终点地址或 lng,lat')\n .option('--from-lat <number>', '起点纬度', parseFloat)\n .option('--from-lng <number>', '起点经度', parseFloat)\n .option('--to-lat <number>', '终点纬度', parseFloat)\n .option('--to-lng <number>', '终点经度', parseFloat)\n .option('--strategy <name>', 'fastest|shortest|eco|balanced')\n .option('--language <code>', '导航语言');\n };\n\n addRouteOptions(\n routeCmd\n .command('driving')\n .description('驾车路线')\n .action(async (opts) => {\n const globalOpts = program.opts();\n await applyTimeoutOverride(globalOpts.timeout);\n await runRoute(\n {\n mode: 'driving',\n from: opts.from,\n to: opts.to,\n fromLat: opts.fromLat,\n fromLng: opts.fromLng,\n toLat: opts.toLat,\n toLng: opts.toLng,\n strategy: opts.strategy,\n language: opts.language,\n },\n buildOutputOptions(globalOpts),\n );\n }),\n );\n\n addRouteOptions(\n routeCmd\n .command('truck')\n .description('货车路线')\n .option('--height <meters>', '车高(米)', parseFloat)\n .option('--weight <tons>', '总重(吨)', parseFloat)\n .option('--length <meters>', '车长(米)', parseFloat)\n .action(async (opts) => {\n const globalOpts = program.opts();\n await applyTimeoutOverride(globalOpts.timeout);\n await runRoute(\n {\n mode: 'truck',\n from: opts.from,\n to: opts.to,\n fromLat: opts.fromLat,\n fromLng: opts.fromLng,\n toLat: opts.toLat,\n toLng: opts.toLng,\n strategy: opts.strategy,\n language: opts.language,\n height: opts.height,\n weight: opts.weight,\n length: opts.length,\n },\n buildOutputOptions(globalOpts),\n );\n }),\n );\n\n await program.parseAsync(process.argv);\n}\n\nasync function applyTimeoutOverride(timeout?: string): Promise<void> {\n if (!timeout) return;\n const ms = Number(timeout);\n if (!Number.isFinite(ms) || ms <= 0) {\n throw new CliError('无效 --timeout 值', ExitCode.USER_ERROR);\n }\n const config = await loadConfig();\n const { saveConfig } = await import('./config/store.js');\n config.timeoutMs = ms;\n await saveConfig(config);\n}\n\nmain().catch(exitWithError);\n","/** CLI 退出码,与架构文档 §6.2 对齐 */\nexport const ExitCode = {\n USER_ERROR: 1,\n CONFIG_MISSING: 2,\n API_ERROR: 3,\n NETWORK_ERROR: 4,\n INTERNAL_ERROR: 5,\n} as const;\n\nexport type ExitCodeValue = (typeof ExitCode)[keyof typeof ExitCode];\n\nexport class CliError extends Error {\n constructor(\n message: string,\n readonly exitCode: ExitCodeValue,\n readonly hint?: string,\n ) {\n super(message);\n this.name = 'CliError';\n }\n}\n\nexport function printError(err: unknown): void {\n if (err instanceof CliError) {\n console.error(`error: ${err.message}`);\n if (err.hint) {\n console.error(`hint: ${err.hint}`);\n }\n return;\n }\n if (err instanceof Error) {\n console.error(`error: ${err.message}`);\n return;\n }\n console.error('error: 未知错误');\n}\n\nexport function exitWithError(err: unknown): never {\n printError(err);\n const code =\n err instanceof CliError ? err.exitCode : ExitCode.INTERNAL_ERROR;\n process.exit(code);\n}\n","import * as readline from 'node:readline/promises';\nimport { stdin as input, stdout as output } from 'node:process';\nimport { CliError, ExitCode } from '../errors.js';\nimport { loadConfig, saveConfig } from '../config/store.js';\nimport { maskApiKey, normalizeBaseUrl } from '../config/env.js';\nimport { emitSuccess, type OutputOptions } from '../output/json.js';\n\nexport async function runInit(outputOpts: OutputOptions): Promise<void> {\n const rl = readline.createInterface({ input, output });\n try {\n const existing = await loadConfig();\n const apiKeyPrompt = existing.apiKey\n ? `API Key [当前 ${maskApiKey(existing.apiKey)},回车保留]: `\n : 'API Key: ';\n const apiKeyInput = (await rl.question(apiKeyPrompt)).trim();\n\n const baseUrlPrompt = existing.baseUrl\n ? `Base URL [当前 ${existing.baseUrl},回车保留]: `\n : 'Base URL (https://api.example.com): ';\n const baseUrlInput = (await rl.question(baseUrlPrompt)).trim();\n\n const config = await loadConfig();\n if (apiKeyInput) {\n config.apiKey = apiKeyInput;\n }\n if (!config.apiKey) {\n throw new CliError(\n '必须提供 API Key',\n ExitCode.USER_ERROR,\n '从 Maptec 开放平台控制台获取,或设置 MAPTEC_API_KEY',\n );\n }\n\n if (baseUrlInput) {\n try {\n config.baseUrl = normalizeBaseUrl(baseUrlInput);\n } catch (err) {\n throw new CliError(\n err instanceof Error ? err.message : '无效 Base URL',\n ExitCode.USER_ERROR,\n );\n }\n }\n if (!config.baseUrl) {\n throw new CliError(\n '必须提供 Base URL',\n ExitCode.USER_ERROR,\n '示例:https://api.maptec.com ,或设置 MAPTEC_BASE_URL',\n );\n }\n\n // 丢弃旧版 env 字段\n delete (config as { env?: string }).env;\n await saveConfig(config);\n\n await emitSuccess(\n {\n command: 'init',\n data: {\n apiKey: maskApiKey(config.apiKey),\n baseUrl: config.baseUrl,\n configPath: '~/.maptec/config.json',\n },\n },\n outputOpts,\n );\n } finally {\n rl.close();\n }\n}\n","import { writeFile } from 'node:fs/promises';\nimport { pickFields } from './fields.js';\n\nexport type OutputFormat = 'json' | 'table';\n\nexport interface OutputOptions {\n format: OutputFormat;\n out?: string;\n quiet?: boolean;\n fields?: string[];\n}\n\nexport interface SuccessPayload<T> {\n command: string;\n data: T;\n}\n\nexport async function emitSuccess<T>(\n payload: SuccessPayload<T>,\n options: OutputOptions,\n): Promise<void> {\n let data = payload.data;\n if (options.fields?.length) {\n data = pickFields(data, options.fields) as T;\n }\n\n const envelope = {\n ok: true as const,\n command: payload.command,\n data,\n };\n\n if (options.format === 'table') {\n const text = formatTable(data);\n await writeOutput(text, options);\n return;\n }\n\n const json = `${JSON.stringify(envelope, null, 2)}\\n`;\n await writeOutput(json, options);\n}\n\nasync function writeOutput(text: string, options: OutputOptions): Promise<void> {\n if (options.out) {\n await writeFile(options.out, text, 'utf8');\n if (!options.quiet) {\n console.error(`已写入 ${options.out}`);\n }\n return;\n }\n process.stdout.write(text.endsWith('\\n') ? text : `${text}\\n`);\n}\n\nfunction formatTable(data: unknown): string {\n if (data === null || data === undefined) {\n return '(empty)';\n }\n if (typeof data !== 'object') {\n return String(data);\n }\n if (Array.isArray(data)) {\n if (data.length === 0) return '(no results)';\n return data.map((item, i) => `[${i}] ${JSON.stringify(item)}`).join('\\n');\n }\n return Object.entries(data as Record<string, unknown>)\n .map(([k, v]) => `${k}: ${typeof v === 'object' ? JSON.stringify(v) : String(v)}`)\n .join('\\n');\n}\n\nimport { CliError, ExitCode } from '../errors.js';\n\nexport function handleApiBusinessStatus<T extends { status?: string; error?: { code: string; message: string } }>(\n result: T,\n command: string,\n): T {\n if (result.status === 'ERROR' && result.error) {\n const err = result.error;\n throw new CliError(\n `${err.code} — ${err.message}`,\n ExitCode.API_ERROR,\n `检查命令参数,当前命令:${command}`,\n );\n }\n return result;\n}\n","export function pickFields<T>(data: T, fields: string[]): unknown {\n if (data === null || data === undefined) return data;\n if (Array.isArray(data)) {\n return data.map((item) => pickFields(item, fields));\n }\n if (typeof data !== 'object') return data;\n\n const fieldSet = new Set(fields.map((f) => f.trim()).filter(Boolean));\n if (fieldSet.size === 0) return data;\n\n const out: Record<string, unknown> = {};\n for (const key of fieldSet) {\n if (key in (data as Record<string, unknown>)) {\n out[key] = (data as Record<string, unknown>)[key];\n }\n }\n return out;\n}\n","import { CliError, ExitCode } from '../errors.js';\nimport {\n getConfigPath,\n loadConfig,\n setApiKey,\n setBaseUrl,\n setConfigValue,\n} from '../config/store.js';\nimport {\n maskApiKey,\n resolveApiKey,\n resolveBaseUrl,\n} from '../config/env.js';\nimport { emitSuccess, type OutputOptions } from '../output/json.js';\n\nexport async function runConfigGet(outputOpts: OutputOptions): Promise<void> {\n const config = await loadConfig();\n const apiKey = resolveApiKey(config);\n\n await emitSuccess(\n {\n command: 'config.get',\n data: {\n apiKey: apiKey ? maskApiKey(apiKey) : null,\n baseUrl: resolveBaseUrl(config) ?? null,\n defaultFormat: config.defaultFormat,\n timeoutMs: config.timeoutMs,\n configPath: getConfigPath(),\n },\n },\n outputOpts,\n );\n}\n\nexport async function runConfigSet(\n key: string,\n value: string,\n outputOpts: OutputOptions,\n): Promise<void> {\n let config;\n switch (key) {\n case 'api-key':\n case 'apiKey':\n config = await setApiKey(value);\n break;\n case 'base-url':\n case 'baseUrl':\n try {\n config = await setBaseUrl(value);\n } catch (err) {\n throw new CliError(\n err instanceof Error ? err.message : '无效 baseUrl',\n ExitCode.USER_ERROR,\n );\n }\n break;\n case 'default-format':\n case 'defaultFormat':\n config = await setConfigValue('defaultFormat', value);\n break;\n case 'timeout':\n case 'timeoutMs':\n config = await setConfigValue('timeoutMs', Number(value));\n break;\n default:\n throw new CliError(\n `未知配置项 \"${key}\"`,\n ExitCode.USER_ERROR,\n '可选:api-key | base-url | default-format | timeout',\n );\n }\n\n await emitSuccess(\n {\n command: 'config.set',\n data: {\n key,\n baseUrl: config.baseUrl ?? null,\n apiKey: config.apiKey ? maskApiKey(config.apiKey) : null,\n },\n },\n outputOpts,\n );\n}\n","import { CliError, ExitCode } from '../errors.js';\nimport {\n API_VERSION,\n resolveApiKey,\n resolveBaseUrl,\n type MaptecConfig,\n} from '../config/env.js';\nimport type { ApiErrorBody } from './types.js';\n\nexport interface RequestOptions {\n method?: 'GET' | 'POST';\n path: string;\n query?: Record<string, string | undefined>;\n body?: unknown;\n timeoutMs?: number;\n}\n\nfunction buildQueryString(query: Record<string, string | undefined>): string {\n const parts = Object.entries(query)\n .filter(([, v]) => v !== undefined && v !== '')\n .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v!)}`);\n return parts.length ? `?${parts.join('&')}` : '';\n}\n\nfunction getAuthorizationValue(apiKey: string): string {\n return apiKey.trim();\n}\n\nexport async function apiRequest<T>(\n config: MaptecConfig,\n options: RequestOptions,\n): Promise<T> {\n const apiKey = resolveApiKey(config);\n if (!apiKey) {\n throw new CliError(\n '未配置 API Key',\n ExitCode.CONFIG_MISSING,\n '运行 maptec init 或设置 MAPTEC_API_KEY 环境变量',\n );\n }\n\n const baseUrl = resolveBaseUrl(config);\n if (!baseUrl) {\n throw new CliError(\n '未配置 Base URL',\n ExitCode.CONFIG_MISSING,\n '运行 maptec init 或设置 MAPTEC_BASE_URL 环境变量',\n );\n }\n const timeoutMs = options.timeoutMs ?? config.timeoutMs;\n const queryString = options.query ? buildQueryString(options.query) : '';\n const url = `${baseUrl}${options.path}${queryString}`;\n\n const headers: Record<string, string> = {\n Authorization: getAuthorizationValue(apiKey),\n };\n\n const method = options.method ?? 'GET';\n const init: RequestInit = {\n method,\n headers,\n signal: AbortSignal.timeout(timeoutMs),\n };\n\n if (options.body !== undefined) {\n headers['Content-Type'] = 'application/json';\n init.body = JSON.stringify(options.body);\n }\n\n let response: Response;\n try {\n response = await fetch(url, init);\n } catch (err) {\n const message =\n err instanceof Error && err.name === 'TimeoutError'\n ? `请求超时(${timeoutMs}ms)`\n : err instanceof Error\n ? err.message\n : '网络请求失败';\n throw new CliError(message, ExitCode.NETWORK_ERROR);\n }\n\n let data: T & ApiErrorBody;\n try {\n data = (await response.json()) as T & ApiErrorBody;\n } catch {\n throw new CliError(\n `无法解析 API 响应(HTTP ${response.status})`,\n response.ok ? ExitCode.INTERNAL_ERROR : ExitCode.API_ERROR,\n );\n }\n\n if (!response.ok) {\n const code = data.error?.code ?? data.code ?? `HTTP_${response.status}`;\n const message =\n data.error?.message ?? data.message ?? `HTTP ${response.status}`;\n throw new CliError(message, ExitCode.API_ERROR, code);\n }\n\n return data;\n}\n\nexport function searchPath(segment: string): string {\n return `/search/${API_VERSION}/${segment}`;\n}\n\nexport function routesPath(segment: string): string {\n return `/routes/${API_VERSION}/${segment}`;\n}\n","import { apiRequest, searchPath } from './client.js';\nimport type { MaptecConfig } from '../config/env.js';\nimport type { GeocodeResult } from './types.js';\n\nexport interface ForwardGeocodeParams {\n address: string;\n language?: string;\n region?: string;\n components?: string;\n locationBias?: string;\n}\n\nexport async function forwardGeocode(\n config: MaptecConfig,\n params: ForwardGeocodeParams,\n): Promise<GeocodeResult> {\n const query: Record<string, string | undefined> = {\n address: params.address,\n language: params.language,\n region: params.region,\n components: params.components,\n locationBias: params.locationBias,\n };\n\n const data = await apiRequest<GeocodeResult>(config, {\n path: searchPath('geocode'),\n query,\n });\n\n if (!Array.isArray(data.results)) {\n data.results = [];\n }\n\n if (data.status === 'ERROR' && data.error) {\n return data;\n }\n\n return data;\n}\n\nexport interface ReverseGeocodeParams {\n lat: number;\n lng: number;\n language?: string;\n region?: string;\n resultType?: string;\n locationType?: string;\n}\n\nexport async function reverseGeocode(\n config: MaptecConfig,\n params: ReverseGeocodeParams,\n): Promise<GeocodeResult> {\n const query: Record<string, string | undefined> = {\n location: `${params.lat},${params.lng}`,\n language: params.language,\n region: params.region,\n resultType: params.resultType,\n locationType: params.locationType,\n };\n\n const data = await apiRequest<GeocodeResult>(config, {\n path: searchPath('reverse'),\n query,\n });\n\n if (!Array.isArray(data.results)) {\n data.results = [];\n }\n\n return data;\n}\n","import { CliError, ExitCode } from '../errors.js';\nimport { loadConfig } from '../config/store.js';\nimport { forwardGeocode } from '../api/geocode.js';\nimport {\n emitSuccess,\n handleApiBusinessStatus,\n type OutputOptions,\n} from '../output/json.js';\n\nexport interface GeocodeCommandOptions {\n address: string;\n language?: string;\n region?: string;\n}\n\nexport async function runGeocode(\n opts: GeocodeCommandOptions,\n outputOpts: OutputOptions,\n): Promise<void> {\n if (!opts.address?.trim()) {\n throw new CliError(\n '缺少 --address 参数',\n ExitCode.USER_ERROR,\n '示例:maptec geocode --address \"北京市朝阳区国贸\"',\n );\n }\n\n const config = await loadConfig();\n const result = await forwardGeocode(config, {\n address: opts.address.trim(),\n language: opts.language,\n region: opts.region,\n });\n\n if (result.status === 'ZERO_RESULTS') {\n throw new CliError(\n 'ZERO_RESULTS — 未找到匹配地址',\n ExitCode.API_ERROR,\n '检查 --address 或改用 maptec search text',\n );\n }\n\n handleApiBusinessStatus(result, 'geocode');\n\n await emitSuccess(\n { command: 'geocode', data: result },\n outputOpts,\n );\n}\n","import { CliError, ExitCode } from '../errors.js';\nimport { loadConfig } from '../config/store.js';\nimport { reverseGeocode } from '../api/geocode.js';\nimport {\n emitSuccess,\n handleApiBusinessStatus,\n type OutputOptions,\n} from '../output/json.js';\n\nexport interface ReverseGeocodeCommandOptions {\n lat: number;\n lng: number;\n language?: string;\n region?: string;\n resultType?: string;\n locationType?: string;\n}\n\nexport async function runReverseGeocode(\n opts: ReverseGeocodeCommandOptions,\n outputOpts: OutputOptions,\n): Promise<void> {\n if (!Number.isFinite(opts.lat) || !Number.isFinite(opts.lng)) {\n throw new CliError(\n '缺少有效的 --lat 与 --lng',\n ExitCode.USER_ERROR,\n '示例:maptec reverse-geocode --lat 39.908 --lng 116.397',\n );\n }\n\n const config = await loadConfig();\n const result = await reverseGeocode(config, opts);\n\n if (result.status === 'ZERO_RESULTS') {\n throw new CliError(\n 'ZERO_RESULTS — 该坐标无地址结果',\n ExitCode.API_ERROR,\n '检查坐标是否在服务范围内',\n );\n }\n\n handleApiBusinessStatus(result, 'reverse-geocode');\n\n await emitSuccess(\n { command: 'reverse-geocode', data: result },\n outputOpts,\n );\n}\n","import type { LngLatObject } from './types.js';\n\n/** 解析 \"lng,lat\" 或 \"lng,lat,radius\" */\nexport function parseLngLatPair(\n value: string,\n defaultRadius?: number,\n): { center: LngLatObject; radius?: number } {\n const parts = value.split(',').map((s) => s.trim());\n if (parts.length < 2) {\n throw new Error(`无效坐标 \"${value}\",格式:lng,lat 或 lng,lat,radius`);\n }\n const lng = Number(parts[0]);\n const lat = Number(parts[1]);\n if (!Number.isFinite(lng) || !Number.isFinite(lat)) {\n throw new Error(`无效坐标 \"${value}\"`);\n }\n const radius =\n parts[2] !== undefined ? Number(parts[2]) : defaultRadius;\n return {\n center: { longitude: lng, latitude: lat },\n radius: radius !== undefined && Number.isFinite(radius) ? radius : undefined,\n };\n}\n\nexport function toLocationAreaCircle(\n lng: number,\n lat: number,\n radius: number,\n): { center: LngLatObject; radius: number } {\n return {\n center: { longitude: lng, latitude: lat },\n radius,\n };\n}\n\nexport type RoutePointInput =\n | { kind: 'text'; value: string }\n | { kind: 'coord'; lat: number; lng: number };\n\nexport function buildRouteEndpoint(point: RoutePointInput): Record<string, unknown> {\n if (point.kind === 'coord') {\n return {\n location: {\n latitude: point.lat,\n longitude: point.lng,\n },\n };\n }\n const text = point.value.trim();\n if (/^[\\d.+-]+,[\\d.+-]+$/.test(text)) {\n const { center } = parseLngLatPair(text);\n return { location: center };\n }\n return { placeId: text };\n}\n","import { apiRequest, searchPath } from './client.js';\nimport type { MaptecConfig } from '../config/env.js';\nimport { parseLngLatPair, toLocationAreaCircle } from './location.js';\nimport type {\n PlaceSearchDetailsResult,\n PlaceSearchNearbyResult,\n PlaceSearchSuggestResult,\n PlaceSearchTextResult,\n} from './types.js';\n\nexport interface TextSearchParams {\n query: string;\n location?: string;\n language?: string;\n region?: string;\n pageSize?: number;\n type?: string;\n rank?: 'RELEVANCE' | 'DISTANCE' | 'POPULARITY';\n}\n\nexport async function searchText(\n config: MaptecConfig,\n params: TextSearchParams,\n): Promise<PlaceSearchTextResult> {\n const body: Record<string, unknown> = {\n query: params.query,\n pageSize: params.pageSize ?? 20,\n language: params.language ?? 'en',\n };\n if (params.region) body.region = params.region;\n if (params.type) body.type = params.type;\n if (params.rank) body.rank = params.rank;\n if (params.location) {\n const { center, radius } = parseLngLatPair(params.location, 5000);\n body.locationBias = toLocationAreaCircle(\n center.longitude,\n center.latitude,\n radius ?? 5000,\n );\n }\n\n return apiRequest<PlaceSearchTextResult>(config, {\n method: 'POST',\n path: searchPath('text'),\n body,\n });\n}\n\nexport interface NearbySearchParams {\n lat: number;\n lng: number;\n radius?: number;\n types?: string;\n resultLimit?: number;\n language?: string;\n region?: string;\n rank?: 'RELEVANCE' | 'DISTANCE' | 'POPULARITY';\n}\n\nexport async function searchNearby(\n config: MaptecConfig,\n params: NearbySearchParams,\n): Promise<PlaceSearchNearbyResult> {\n const body: Record<string, unknown> = {\n locationLimit: toLocationAreaCircle(\n params.lng,\n params.lat,\n params.radius ?? 500,\n ),\n types: params.types ?? '',\n resultLimit: params.resultLimit ?? 20,\n rank: params.rank ?? 'DISTANCE',\n language: params.language ?? 'en',\n };\n if (params.region) body.region = params.region;\n\n return apiRequest<PlaceSearchNearbyResult>(config, {\n method: 'POST',\n path: searchPath('nearby'),\n body,\n });\n}\n\nexport interface SuggestSearchParams {\n query: string;\n location?: string;\n language?: string;\n region?: string;\n resultLimit?: number;\n}\n\nexport async function searchSuggest(\n config: MaptecConfig,\n params: SuggestSearchParams,\n): Promise<PlaceSearchSuggestResult> {\n const body: Record<string, unknown> = {\n query: params.query,\n resultLimit: params.resultLimit ?? 20,\n language: params.language ?? 'en',\n region: params.region ?? '',\n types: '',\n };\n if (params.location) {\n const { center, radius } = parseLngLatPair(params.location, 5000);\n body.locationBias = toLocationAreaCircle(\n center.longitude,\n center.latitude,\n radius ?? 5000,\n );\n }\n\n return apiRequest<PlaceSearchSuggestResult>(config, {\n method: 'POST',\n path: searchPath('suggest'),\n body,\n });\n}\n\nexport interface PlaceDetailsParams {\n placeId: string;\n language?: string;\n region?: string;\n sessionToken?: string;\n}\n\nexport async function getPlaceDetails(\n config: MaptecConfig,\n params: PlaceDetailsParams,\n): Promise<PlaceSearchDetailsResult> {\n const query: Record<string, string | undefined> = {\n language: params.language ?? 'en',\n region: params.region,\n sessionToken: params.sessionToken,\n };\n\n return apiRequest<PlaceSearchDetailsResult>(config, {\n path: searchPath(`places/${encodeURIComponent(params.placeId)}`),\n query,\n });\n}\n","import { CliError, ExitCode } from '../errors.js';\nimport { loadConfig } from '../config/store.js';\nimport {\n getPlaceDetails,\n searchNearby,\n searchSuggest,\n searchText,\n} from '../api/place-search.js';\nimport {\n emitSuccess,\n handleApiBusinessStatus,\n type OutputOptions,\n} from '../output/json.js';\n\nfunction assertOkStatus(result: { status?: string }, command: string): void {\n if (result.status === 'ZERO_RESULTS') {\n throw new CliError(\n 'ZERO_RESULTS — 未找到匹配结果',\n ExitCode.API_ERROR,\n `检查搜索参数,命令:${command}`,\n );\n }\n handleApiBusinessStatus(result, command);\n}\n\nexport async function runSearchText(\n opts: {\n query: string;\n location?: string;\n language?: string;\n region?: string;\n pageSize?: number;\n type?: string;\n rank?: 'RELEVANCE' | 'DISTANCE' | 'POPULARITY';\n },\n outputOpts: OutputOptions,\n): Promise<void> {\n if (!opts.query?.trim()) {\n throw new CliError('缺少 --query', ExitCode.USER_ERROR);\n }\n const config = await loadConfig();\n const result = await searchText(config, opts);\n assertOkStatus(result, 'search.text');\n await emitSuccess({ command: 'search.text', data: result }, outputOpts);\n}\n\nexport async function runSearchNearby(\n opts: {\n lat: number;\n lng: number;\n radius?: number;\n types?: string;\n limit?: number;\n language?: string;\n region?: string;\n rank?: 'RELEVANCE' | 'DISTANCE' | 'POPULARITY';\n },\n outputOpts: OutputOptions,\n): Promise<void> {\n const config = await loadConfig();\n const result = await searchNearby(config, {\n lat: opts.lat,\n lng: opts.lng,\n radius: opts.radius,\n types: opts.types,\n resultLimit: opts.limit,\n language: opts.language,\n region: opts.region,\n rank: opts.rank,\n });\n assertOkStatus(result, 'search.nearby');\n await emitSuccess({ command: 'search.nearby', data: result }, outputOpts);\n}\n\nexport async function runSearchSuggest(\n opts: {\n query: string;\n location?: string;\n language?: string;\n region?: string;\n limit?: number;\n },\n outputOpts: OutputOptions,\n): Promise<void> {\n const config = await loadConfig();\n const result = await searchSuggest(config, {\n query: opts.query,\n location: opts.location,\n language: opts.language,\n region: opts.region,\n resultLimit: opts.limit,\n });\n assertOkStatus(result, 'search.suggest');\n await emitSuccess({ command: 'search.suggest', data: result }, outputOpts);\n}\n\nexport async function runSearchPlace(\n opts: { id: string; language?: string; region?: string; sessionToken?: string },\n outputOpts: OutputOptions,\n): Promise<void> {\n const config = await loadConfig();\n const result = await getPlaceDetails(config, {\n placeId: opts.id,\n language: opts.language,\n region: opts.region,\n sessionToken: opts.sessionToken,\n });\n assertOkStatus(result, 'search.place');\n await emitSuccess({ command: 'search.place', data: result }, outputOpts);\n}\n","import { apiRequest, routesPath } from './client.js';\nimport type { MaptecConfig } from '../config/env.js';\nimport { buildRouteEndpoint, type RoutePointInput } from './location.js';\nimport type { DrivingResult } from './types.js';\n\nexport type RouteMode = 'driving' | 'truck';\n\nexport interface DirectionsParams {\n mode: RouteMode;\n origin: RoutePointInput;\n destination: RoutePointInput;\n strategy?: 'fastest' | 'shortest' | 'eco' | 'balanced';\n language?: string;\n vehicleSpec?: {\n heightMeters?: number;\n weightTons?: number;\n lengthMeters?: number;\n };\n}\n\nexport async function getDirections(\n config: MaptecConfig,\n params: DirectionsParams,\n): Promise<DrivingResult> {\n return getDirectionsWithEndpoints(config, {\n mode: params.mode,\n origin: buildRouteEndpoint(params.origin),\n destination: buildRouteEndpoint(params.destination),\n strategy: params.strategy,\n language: params.language,\n vehicleSpec: params.vehicleSpec,\n });\n}\n\nexport interface ResolvedDirectionsParams {\n mode: RouteMode;\n origin: Record<string, unknown>;\n destination: Record<string, unknown>;\n strategy?: 'fastest' | 'shortest' | 'eco' | 'balanced';\n language?: string;\n vehicleSpec?: DirectionsParams['vehicleSpec'];\n}\n\nexport async function getDirectionsWithEndpoints(\n config: MaptecConfig,\n params: ResolvedDirectionsParams,\n): Promise<DrivingResult> {\n const body: Record<string, unknown> = {\n origin: params.origin,\n destination: params.destination,\n mode: params.mode,\n };\n if (params.strategy) body.strategy = params.strategy;\n if (params.language) body.language = params.language;\n if (params.vehicleSpec) body.vehicleSpec = params.vehicleSpec;\n\n return apiRequest<DrivingResult>(config, {\n method: 'POST',\n path: routesPath('directions'),\n body,\n });\n}\n","import type { MaptecConfig } from '../config/env.js';\nimport { forwardGeocode } from './geocode.js';\nimport {\n buildRouteEndpoint,\n parseLngLatPair,\n type RoutePointInput,\n} from './location.js';\n\n/** 将文本地址 geocode 为坐标;已是坐标或 placeId 则原样构建 endpoint */\nexport async function resolveRouteEndpoint(\n config: MaptecConfig,\n point: RoutePointInput,\n): Promise<Record<string, unknown>> {\n if (point.kind === 'coord') {\n return buildRouteEndpoint(point);\n }\n\n const text = point.value.trim();\n\n if (/^[\\d.+-]+,[\\d.+-]+$/.test(text)) {\n return buildRouteEndpoint(point);\n }\n\n if (text.startsWith('places/') || text.includes('_v0.') || /^[\\d]+$/.test(text)) {\n return buildRouteEndpoint(point);\n }\n\n const geocoded = await forwardGeocode(config, { address: text });\n const first = geocoded.results?.[0];\n if (geocoded.status !== 'OK' || !first?.geometry?.location) {\n throw new Error(\n `无法 geocode 地址 \"${text}\"(${geocoded.status})`,\n );\n }\n\n const { latitude, longitude } = first.geometry.location;\n return buildRouteEndpoint({ kind: 'coord', lat: latitude, lng: longitude });\n}\n\nexport { parseLngLatPair };\n","import type { DrivingResult, DrivingRoute } from '../api/types.js';\n\nconst DEFAULT_ROUTE_FIELDS = ['distance', 'duration', 'summary'];\n\nexport function shapeRouteOutput(\n data: DrivingResult,\n fields?: string[],\n): unknown {\n if (!data.routes?.length) return data;\n\n const wanted = fields?.length ? fields : DEFAULT_ROUTE_FIELDS;\n const includePolyline = wanted.includes('polyline');\n\n const routes = data.routes.map((route) =>\n projectRoute(route, wanted, includePolyline),\n );\n\n return { ...data, routes };\n}\n\nfunction projectRoute(\n route: DrivingRoute,\n fields: string[],\n includePolyline: boolean,\n): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n\n if (fields.includes('summary') || fields.includes('distance') || fields.includes('duration')) {\n const summary: Record<string, unknown> = {};\n if (fields.includes('distance')) {\n summary.distanceMeters = route.summary.distanceMeters;\n }\n if (fields.includes('duration')) {\n summary.durationSeconds = route.summary.durationSeconds;\n }\n if (fields.includes('summary')) {\n summary.trafficDurationSeconds = route.summary.trafficDurationSeconds;\n }\n out.summary = summary;\n }\n\n if (fields.includes('warnings') && route.warnings) {\n out.warnings = route.warnings;\n }\n\n if (includePolyline) {\n const polyline = route.overviewPolyline;\n if (polyline) out.polyline = polyline;\n if (route.path) out.path = route.path;\n }\n\n if (fields.includes('legs') && route.legs) {\n out.legs = route.legs;\n }\n\n return out;\n}\n\n/** 默认剔除 polyline 相关大字段 */\nexport function stripRoutePolyline(data: DrivingResult): DrivingResult {\n if (!data.routes) return data;\n return {\n ...data,\n routes: data.routes.map(({ overviewPolyline, path, ...rest }) => rest),\n };\n}\n","import { CliError, ExitCode } from '../errors.js';\nimport { loadConfig } from '../config/store.js';\nimport { getDirectionsWithEndpoints, type RouteMode } from '../api/directions.js';\nimport { resolveRouteEndpoint } from '../api/route-resolve.js';\nimport type { RoutePointInput } from '../api/location.js';\nimport {\n emitSuccess,\n handleApiBusinessStatus,\n type OutputOptions,\n} from '../output/json.js';\nimport { shapeRouteOutput } from '../output/route-fields.js';\n\nexport interface RouteCommandOptions {\n mode: RouteMode;\n from?: string;\n to?: string;\n fromLat?: number;\n fromLng?: number;\n toLat?: number;\n toLng?: number;\n strategy?: 'fastest' | 'shortest' | 'eco' | 'balanced';\n language?: string;\n height?: number;\n weight?: number;\n length?: number;\n fields?: string[];\n}\n\nfunction resolveEndpoint(\n text: string | undefined,\n lat: number | undefined,\n lng: number | undefined,\n label: string,\n): RoutePointInput {\n if (lat !== undefined && lng !== undefined && Number.isFinite(lat) && Number.isFinite(lng)) {\n return { kind: 'coord', lat, lng };\n }\n if (text?.trim()) {\n return { kind: 'text', value: text.trim() };\n }\n throw new CliError(\n `缺少起点/终点 ${label}`,\n ExitCode.USER_ERROR,\n `使用 --${label} 或 --${label}-lat + --${label}-lng`,\n );\n}\n\nexport async function runRoute(\n opts: RouteCommandOptions,\n outputOpts: OutputOptions,\n): Promise<void> {\n const origin = resolveEndpoint(opts.from, opts.fromLat, opts.fromLng, 'from');\n const destination = resolveEndpoint(opts.to, opts.toLat, opts.toLng, 'to');\n\n const config = await loadConfig();\n const [originParam, destinationParam] = await Promise.all([\n resolveRouteEndpoint(config, origin),\n resolveRouteEndpoint(config, destination),\n ]);\n\n const result = await getDirectionsWithEndpoints(config, {\n mode: opts.mode,\n origin: originParam,\n destination: destinationParam,\n strategy: opts.strategy,\n language: opts.language,\n vehicleSpec:\n opts.mode === 'truck'\n ? {\n heightMeters: opts.height,\n weightTons: opts.weight,\n lengthMeters: opts.length,\n }\n : undefined,\n });\n\n if (result.status === 'NO_ROUTE_FOUND') {\n throw new CliError(\n 'NO_ROUTE_FOUND — 无法规划路线',\n ExitCode.API_ERROR,\n '检查起终点或改用 maptec geocode 确认坐标',\n );\n }\n\n handleApiBusinessStatus(result, `route.${opts.mode}`);\n\n const fields = outputOpts.fields ?? opts.fields;\n const shaped = shapeRouteOutput(result, fields) as typeof result;\n\n await emitSuccess(\n { command: `route.${opts.mode}`, data: shaped },\n { ...outputOpts, fields: undefined },\n );\n}\n"],"mappings":"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","names":["saveConfig"]}
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ getConfigPath,
4
+ loadConfig,
5
+ saveConfig,
6
+ setApiKey,
7
+ setBaseUrl,
8
+ setConfigValue
9
+ } from "./chunk-K574OFFK.js";
10
+ export {
11
+ getConfigPath,
12
+ loadConfig,
13
+ saveConfig,
14
+ setApiKey,
15
+ setBaseUrl,
16
+ setConfigValue
17
+ };
18
+ //# sourceMappingURL=store-ZU7HLXCV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@maptec/cli",
3
+ "version": "1.0.0",
4
+ "description": "Maptec 地图领域命令行工具 — 结构化 JSON 输出,供开发者与 AI Agent 调用",
5
+ "type": "module",
6
+ "bin": {
7
+ "maptec": "./bin/maptec.js"
8
+ },
9
+ "files": [
10
+ "bin",
11
+ "dist",
12
+ "skills",
13
+ "LICENSE"
14
+ ],
15
+ "scripts": {
16
+ "prebuild": "npm run skills:install",
17
+ "build": "tsup && chmod +x bin/maptec.js",
18
+ "dev": "tsup --watch",
19
+ "typecheck": "tsc --noEmit",
20
+ "test": "vitest run",
21
+ "skills:install": "MAPTEC_SKILL_INSTALL_DIR=./skills npx @maptec/jsapi-skills@latest install && MAPTEC_SKILL_INSTALL_DIR=./skills npx @maptec/webapi-skills@latest install",
22
+ "publish:public": "npm run build && npm publish --access public --registry=https://registry.npmjs.org/ --@maptec:registry=https://registry.npmjs.org/",
23
+ "prepublishOnly": "npm run build"
24
+ },
25
+ "publishConfig": {
26
+ "access": "public"
27
+ },
28
+ "engines": {
29
+ "node": ">=18"
30
+ },
31
+ "keywords": [
32
+ "maptec",
33
+ "map",
34
+ "geocode",
35
+ "cli"
36
+ ],
37
+ "license": "MIT",
38
+ "dependencies": {
39
+ "commander": "^13.1.0"
40
+ },
41
+ "devDependencies": {
42
+ "@types/node": "^22.15.0",
43
+ "tsup": "^8.5.0",
44
+ "typescript": "^5.8.3",
45
+ "vitest": "^3.1.0"
46
+ }
47
+ }
@@ -0,0 +1,30 @@
1
+ # Maptec CLI Skills
2
+
3
+ 本目录包含供 AI Agent 使用的官方 Skill,来源:
4
+
5
+ | Skill | npm 包 | 说明 |
6
+ |-------|--------|------|
7
+ | `jsapi-skills/` | [@maptec/jsapi-skills](https://www.npmjs.com/package/@maptec/jsapi-skills) | Maptec JSAPI(地图加载、覆盖物、POI、路线等) |
8
+ | `webapi-skills/` | [@maptec/webapi-skills](https://www.npmjs.com/package/@maptec/webapi-skills) | Maptec Web Services API(检索、地理编码、路线、距离矩阵等) |
9
+
10
+ ## 更新
11
+
12
+ 构建时会自动拉取最新 Skill(`prebuild` → `skills:install`)。也可手动执行:
13
+
14
+ ```bash
15
+ npm run skills:install
16
+ ```
17
+
18
+ 或手动指定目录:
19
+
20
+ ```bash
21
+ MAPTEC_SKILL_INSTALL_DIR=./skills npx @maptec/jsapi-skills install
22
+ MAPTEC_SKILL_INSTALL_DIR=./skills npx @maptec/webapi-skills install
23
+ ```
24
+
25
+ ## Agent 使用
26
+
27
+ - JSAPI 前端 / GUI 渲染:读取 `jsapi-skills/SKILL.md`,按需加载 `references/*.md`;生成代码应依赖 [`@maptec/maptec-js`](https://www.npmjs.com/package/@maptec/maptec-js)
28
+ - Web API / CLI 对接:读取 `webapi-skills/SKILL.md`,按需加载 `references/*.md`;执行走 `maptec` 或 MCP,**不要**把 maptec-js 当服务端 SDK
29
+
30
+ > `@maptec/cli` 本身**不依赖** `@maptec/maptec-js`。本目录 Skills 只是文档随包分发;浏览器 SDK 仅渲染层(GUI / 前端页)需要。
@@ -0,0 +1,60 @@
1
+ # jsapi-skills
2
+
3
+ 为 AI Agent 提供 MAPTEC JSAPI 服务能力的 Skill 集合,支持地图加载、交互、控件、事件、覆盖物、地点检索、路线规划等功能。
4
+
5
+ ## 简介
6
+
7
+ `jsapi-skills` 把 Maptec JSAPI 能力整理成结构化文档,供 AI Agent 进行能力归类、API 选型、参数约束、生命周期清理和代码生成。核心入口是 `SKILL.md`,各项能力的详细规则在 `references/` 目录下。
8
+
9
+ ## 功能列表
10
+
11
+ | 能力 | 说明 | 用户示例 |
12
+ |---|---|---|
13
+ | 地图加载 | 创建地图实例,初始化加载地图 | “生成一个新加坡的地图” |
14
+ | 地图交互 | 拖拽、缩放、旋转、倾斜、手势控制、交互开关配置 | “禁止用户旋转或拖拽地图” |
15
+ | 地图控件 | 缩放导航、比例尺、全屏、指南针、鹰眼控件配置 | “在地图右下角添加比例尺控件” |
16
+ | 样式切换 | 白天 / 黑夜模式切换 | “将地图切换为黑夜模式” |
17
+ | 事件监听 | 地图点击、缩放变化、中心点变化、覆盖物点击等 | “点击地图获取当前位置的经纬度” |
18
+ | Marker | Marker 覆盖物 | “在点击位置增加 Marker 点” |
19
+ | 矢量覆盖物 | 点、线、圆、多边形的样式、数据与事件绑定 | “在地图上绘制一个半径 2000 米的圆形” |
20
+ | 信息窗口 | 信息窗口覆盖物 | “点击地图增加一个信息窗口” |
21
+ | 轨迹动画 | 关键帧轨迹、轨迹增长、沿线移动、车头朝向、视角跟随 | “让小车图标沿路线移动” |
22
+ | POI 检索 | 关键词、周边、类型、详情检索 | “搜索新加坡所有咖啡馆并标注” |
23
+ | 路线规划 | 驾车路线规划与展示 | “绘制 NUS 到乌节路的驾车路线” |
24
+ | 地理编码 | 地址转经纬度坐标 | “将新加坡摩天观景轮标注在地图上” |
25
+ | 逆地理编码 | 经纬度坐标转地址信息 | “将用户当前位置坐标转换为详细地址” |
26
+
27
+ ## 安装 Skill
28
+
29
+ 用于将 `jsapi-skills` 安装到本机 Agent Skills 目录,供 AI Agent 识别和使用。
30
+
31
+ ### (1)通过 npm 包安装
32
+
33
+ ```bash
34
+ npx @maptec/jsapi-skills install
35
+ ```
36
+
37
+ 安装完成后,默认目录为:`~/.agents/skills/jsapi-skills`
38
+
39
+ ### (2)自定义安装目录
40
+
41
+ 支持用环境变量 `MAPTEC_SKILL_INSTALL_DIR` 指定安装父目录:
42
+
43
+ ```bash
44
+ MAPTEC_SKILL_INSTALL_DIR=/path/to/skills npx @maptec/jsapi-skills install
45
+ ```
46
+
47
+ ### (3)GitHub 开源地址
48
+
49
+ `jsapi-skills` 已开源到 GitHub 的 [maptec-api/jsapi-skills](https://github.com/maptec-api/jsapi-skills) 仓库,可以查看源码、了解目录结构,或在本地按需扩展能力文档:
50
+
51
+ [https://github.com/maptec-api/jsapi-skills](https://github.com/maptec-api/jsapi-skills)
52
+
53
+ ## 如何被 Agent 使用
54
+
55
+ 1. 根据用户需求归类到功能列表中的一个或多个能力。
56
+ 2. 按 `SKILL.md` 的能力路由,只读取相关的 `references/*.md`。
57
+ 3. 使用参考文档中的真实 Maptec 类、方法、参数和生命周期规则。
58
+ 4. 生成代码前说明命中的能力和使用的 API。
59
+ 5. 生成代码时必须包含错误处理、空结果处理、事件解绑和资源清理。
60
+ 6. 对不确定的能力标记 `需确认 Maptec 是否支持`,不要写成确定 API。
@@ -0,0 +1,145 @@
1
+ ---
2
+ name: jsapi-skills
3
+ description: 为 AI Agent 提供 MAPTEC JSAPI 服务能力的 Skill 集合,支持地图加载、交互、控件、事件、覆盖物、地点检索、路线规划等功能,让AI能够精准选择类、方法、参数、生命周期和清理方式。
4
+ ---
5
+
6
+ # Maptec JSAPI Skill
7
+
8
+ 为 AI Agent 提供 MAPTEC JSAPI 服务能力的 Skill 集合,支持地图加载、交互、控件、事件、覆盖物、地点检索、路线规划等功能,让AI能够精准选择类、方法、参数、生命周期和清理方式。
9
+
10
+ ## 安装接入
11
+
12
+ 支持 Script 和 npm 两种方式接入 MAPTEC JSAPI,Script 适合用于 HTML 页面使用,npm 适合用于工程化项目使用。
13
+
14
+ ### Script 接入
15
+
16
+ ```html
17
+ <script src="https://test-lbs.maptec.com/demo/lib/Maptec-dev.js"></script>
18
+ ```
19
+
20
+ Script 加载完成后,通过全局对象 `Maptec` 使用 JSAPI。
21
+
22
+ ### npm 接入
23
+
24
+ ```bash
25
+ npm i @maptec/maptec-js
26
+ ```
27
+
28
+ 安装完成后,可执行以下命令检查依赖是否安装成功:
29
+
30
+ ```bash
31
+ npm ls @maptec/maptec-js
32
+ ```
33
+
34
+ ## 鉴权
35
+
36
+ - Header:`Authorization: Bearer $MAPTEC_JSAPI_KEY`
37
+ - `MAPTEC_JSAPI_KEY` 从环境变量获取
38
+ - 若未设置,提示用户执行:
39
+ `export MAPTEC_JSAPI_KEY=<你的 MAPTEC JSAPI Key>`
40
+
41
+ ## 功能列表
42
+
43
+ | 能力 | 说明 | 用户示例 |
44
+ |---|---|---|
45
+ | 地图加载 | 创建地图实例,初始化加载地图 | “生成一个新加坡的地图” |
46
+ | 地图交互 | 支持地图拖拽、缩放、旋转、倾斜、手势控制、交互开关配置 | “禁止用户旋转或拖拽地图” |
47
+ | 地图控件 | 支持缩放导航、比例尺、全屏、指南针、鹰眼控件的位置配置、添加、移除与清理 | “在地图右下角添加比例尺控件” |
48
+ | 样式切换 | 支持白天、黑夜模式切换 | “将地图切换为黑夜模式”“增加一个按钮切换白天和黑夜地图” |
49
+ | 事件监听 | 支持地图事件和用户交互监听,配置地图点击、缩放变化、中心点变化、覆盖物点击等事件监听代码 | “点击地图获取当前位置的经纬度”“监听地图缩放级别变化” |
50
+ | Marker | 面向业务可视化场景,支持 Marker 覆盖物 | “在点击位置增加Marker点” |
51
+ | 矢量覆盖物 | 面向业务可视化场景,支持点、线、圆、多边形矢量覆盖物的样式配置、数据绑定、事件绑定 | “在地图上绘制一个半径2000米的圆形” |
52
+ | 信息窗口 | 面向业务可视化场景,支持信息窗口覆盖物 | “点击地图增加一个信息窗口展示当前位置经纬度” |
53
+ | 轨迹动画 | 面向动态轨迹可视化场景,支持关键帧轨迹、行驶轨迹增长、图标沿线移动、车头自动朝向、视角跟随 | “让小车图标沿路线移动”“实现轨迹回放并支持暂停、继续、停止” |
54
+ | POI检索 | 面向 POI 检索场景,支持关键词检索、周边检索、类型检索、详情检索 | “搜索新加坡所有咖啡馆并标注在地图上”“乌节路附近的餐厅” |
55
+ | 路线规划 | 面向路线规划场景,支持驾车路线规划和路线展示 | “绘制一个新加坡国立大学到乌节路的驾车路线” |
56
+ | 地理编码 | 面向地址解析场景,支持将地址转换为经纬度坐标 | “将新加坡摩天观景轮标注在地图上” |
57
+ | 逆地理编码 | 面向坐标反查地址场景,支持将经纬度转换为地址信息 | “将用户当前位置坐标转换为详细地址” |
58
+
59
+ ## 能力路由
60
+
61
+ 按需只读取相关参考文档:
62
+
63
+ - **地图加载**:`references/map.md`。
64
+ - **地图交互**:`references/operate.md`。
65
+ - **地图控件**:`references/controls.md`。
66
+ - **样式切换**:`references/map-style.md`;运行时样式切换使用 `map.setStyle(styleID)`。
67
+ - **事件监听**:`references/events.md`;涉及 Marker、矢量覆盖物或信息窗口事件时读取对应能力文档。
68
+ - **Marker**:`references/marker.md`。
69
+ - **矢量覆盖物**:`references/overlay.md`。
70
+ - **信息窗口**:`references/popup.md`。
71
+ - **轨迹动画**:`references/track.md`;如果轨迹来自真实道路,先读取 `references/routing.md`。
72
+ - **POI检索**:`references/place-search.md`;需要填写或匹配 POI `type/types` 时读取 `references/poi-categories.md`;地点范围不明确或附近检索需要中心点时读取 `references/geocoding.md`。
73
+ - **路线规划**:`references/routing.md`;起终点是地址或地名时先读取 `references/geocoding.md`。
74
+ - **地理编码**:`references/geocoding.md`;需要标注结果时读取 `references/marker.md`。
75
+ - **逆地理编码**:`references/re-geocoding.md`;需要用户当前位置时结合浏览器 `navigator.geolocation`。
76
+
77
+ ## 实现流程
78
+
79
+ 1. 先把用户需求归入一个或多个功能列表条目。
80
+ 2. 明确输入:地点名、地址、坐标、POI 类型、半径、路线起终点、样式模式、控件位置、交互开关、事件类型。
81
+ 3. 只使用已确认能力:
82
+ - 地图加载:`Maptec.Map`
83
+ - 地图交互:`MapOptions` 交互字段、`map.interactive`、`minZoom/maxZoom`、`minPitch/maxPitch`、`maxBounds`、`jumpTo/easeTo/flyTo/fitBounds`
84
+ - 地图控件:`NavigationControl`、`ScaleControl`、`FullscreenControl`、`CompassControl`、`HawkeyeControl`
85
+ - 样式切换:初始化 `style`;运行时使用 `map.setStyle(styleID)`
86
+ - 事件监听:`map.on`、`map.once`、`map.off`、Marker/矢量覆盖物/信息窗口 `on/off`
87
+ - Marker:`Maptec.Marker`
88
+ - 矢量覆盖物:`Maptec.CircleOverlay`、`Maptec.PolylineOverlay`、`Maptec.PolygonOverlay`、`Maptec.GeoJSONOverlay`
89
+ - 信息窗口:`Maptec.Popup`
90
+ - 轨迹动画:`PointKeyFrameTrack`、`PolylineKeyFrameTrack`、`CameraKeyFrameTrack`、`CameraOrbitKeyFrameTrack`
91
+ - POI检索:`Maptec.PlaceSearch`
92
+ - 路线规划:`Maptec.Driving`;货车路线才使用 `Maptec.TruckDriving`
93
+ - 地理编码:`Maptec.Geocode.getLocation`
94
+ - 逆地理编码:`Maptec.Geocode.getAddress`
95
+ 4. 生成代码前说明命中的能力、使用的类/方法、异步流程和需要用户确认的不确定点。
96
+ 5. 生成代码时包含错误处理、空结果处理、分页限制、事件解绑、覆盖物/控件清理和视图适配。
97
+
98
+ ## 强约束
99
+
100
+ - 地理坐标统一使用 `[lng, lat]`,不要使用 `[lat, lng]`。
101
+ - 不要发明 Maptec 不存在或未在当前文档确认的类、方法、参数或事件名。
102
+ - **必须严格按照 reference 文档中定义的响应字段名访问 API 数据**,不得套用其他地图 SDK(如 Google Maps、Mapbox)的字段名惯例。各服务响应字段名不同,严禁混用:
103
+
104
+ | 服务 | 结果列表字段 | 坐标字段 | ❌ 常见错误 |
105
+ |---|---|---|---|
106
+ | POI 检索 `PlaceSearch` | `result.places` | `place.location`(直接含 `latitude`/`longitude`) | ~~`result.results`~~、~~`place.geometry?.location`~~ |
107
+
108
+ - 真实 POI 必须使用 `Maptec.PlaceSearch`,不要伪造咖啡馆、餐厅、酒店等真实数据。
109
+ - POI `type/types` 必须来自 `references/poi-categories.md` 的 Maptec 类目值;不要使用未确认的通用词如 `school`、`restaurant`、`hotel`、`parking`,除非该值在类目补充中明确存在。不确定时只用关键词检索,不要强塞类型过滤。
110
+ - 地址、地名、地标转坐标必须先用 `Maptec.Geocode.getLocation`。
111
+ - 坐标反查地址必须用 `Maptec.Geocode.getAddress`。
112
+ - 真实驾车路线必须使用 `Maptec.Driving` 或 `Maptec.TruckDriving`,不要用手写折线冒充路线规划。
113
+ - 路线规划结果必须使用 `Maptec.Marker` 增加起终点方向图标,起点标识“起”,终点标识“终”,并在清理阶段移除这两个 Marker。
114
+ - Marker、Popup、CircleOverlay、PolylineOverlay、PolygonOverlay、GeoJSONOverlay 等通过 `map.addOverlay(overlay)` 添加,通过 `map.removeOverlay(overlay)` 或对应销毁方法清理。
115
+ - 控件通过 `map.addControl(control, position?)` 添加,通过 `map.removeControl(control)` 清理。
116
+ - 事件订阅必须保存订阅对象或 listener 引用,并在清理阶段取消。
117
+ - 地图加载后再添加依赖地图资源的控件、Marker、矢量覆盖物、信息窗口、检索结果、路线结果和动画对象。
118
+ - 地图初始化 `center` 必须设置为用户提及的地理区域的合理默认坐标(如"新加坡"→ `[103.8198, 1.3521]`),不得使用 `[0, 0]` 或空值。路线规划、POI 检索等场景,先用区域默认中心初始化地图,数据加载完成后再通过 `fitBounds` 适配实际数据视口。
119
+ - 绘制 Marker、Popup、CircleOverlay、PolylineOverlay、PolygonOverlay、GeoJSONOverlay、POI 检索结果或路线结果后,必须根据所有可见地理元素计算 bounds,并调用 `map.fitBounds(bounds, { padding, maxZoom? })` 进行视图适配;单点或小范围场景可使用 `map.easeTo/jumpTo` 设置中心和合适 zoom。
120
+ - “所有/尽可能多”的 POI 检索必须说明分页和前端上限,不要补造缺失结果。
121
+ - 样式切换使用 `map.setStyle(styleID)`;定位按钮使用浏览器 `navigator.geolocation` 加自定义业务按钮,不要编造内置定位控件类。
122
+ - 未在 `maptec-js/src/index.ts` 公开导出或源码中确认的能力,统一标记为需确认。
123
+
124
+ ## 语言自适应
125
+
126
+ - **必须**根据用户输入的语言自动选择响应语言。如果用户使用英文提问,所有输出(意图识别、代码注释、UI 文本、错误信息、日志输出等)必须使用英文;如果用户使用中文提问,则使用中文。
127
+ - 代码中的用户可见文本(如 Popup 内容、Marker 标签、按钮文字)必须与用户输入语言一致。
128
+ - 不要在英文场景下使用中文注释或中文 UI 文本,反之亦然。
129
+
130
+ ## 输出要求
131
+
132
+ 面对代码实现任务,输出:
133
+
134
+ - 命中的功能名称。
135
+ - 使用的 Maptec 类、方法和关键参数。
136
+ - 必要的地理编码、POI 检索、路线规划或轨迹动画流程。
137
+ - 可直接落地的代码或补丁。
138
+ - 未确认能力或 SDK 限制。
139
+
140
+ 面对方案设计任务,输出:
141
+
142
+ - 能力归类。
143
+ - 数据与服务调用计划。
144
+ - Marker、矢量覆盖物、信息窗口、控件、事件和样式计划。
145
+ - 生命周期和清理策略。
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@maptec/jsapi-skills",
3
+ "version": "1.0.3",
4
+ "description": "Maptec JSAPI Agent Skill package",
5
+ "type": "module",
6
+ "bin": {
7
+ "jsapi-skills": "bin/jsapi-skills.js"
8
+ },
9
+ "files": [
10
+ "bin",
11
+ "SKILL.md",
12
+ "README.md",
13
+ "LICENSE",
14
+ "references",
15
+ "scripts"
16
+ ],
17
+ "scripts": {
18
+ "validate": "python3 scripts/validate_jsapi_skill.py ."
19
+ },
20
+ "keywords": [
21
+ "maptec",
22
+ "jsapi",
23
+ "agent",
24
+ "skill",
25
+ "maps"
26
+ ],
27
+ "publishConfig": {
28
+ "access": "public"
29
+ },
30
+ "license": "MIT"
31
+ }