@steercards/agent-tools 0.0.0-stage → 0.1.1
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/CONTRIBUTING.md +34 -0
- package/LICENSE +21 -0
- package/README.md +194 -2
- package/SECURITY.md +28 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +217 -0
- package/dist/config.d.ts +22 -0
- package/dist/config.js +58 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +5 -0
- package/dist/install.d.ts +22 -0
- package/dist/install.js +107 -0
- package/dist/package.d.ts +5 -0
- package/dist/package.js +5 -0
- package/dist/runtime.d.ts +26 -0
- package/dist/runtime.js +214 -0
- package/dist/server.d.ts +9 -0
- package/dist/server.js +121 -0
- package/dist/setup.d.ts +34 -0
- package/dist/setup.js +458 -0
- package/docs/releases.md +51 -0
- package/package.json +64 -4
- package/skills/steercards/SKILL.md +44 -0
- package/skills/steercards/references/cards.md +34 -0
- package/skills/steercards/references/claims-runs.md +33 -0
- package/skills/steercards/references/collaboration.md +29 -0
- package/skills/steercards/references/context.md +21 -0
- package/skills/steercards/references/discovery.md +32 -0
- package/skills/steercards/references/files.md +32 -0
- package/skills/steercards/references/profiles.md +29 -0
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
작은 수정과 버그 보고도 환영합니다. 이 도구는 원격 Steercards MCP 서버에 연결하는 독립형 패키지입니다. 서버 기능과 도구 목록을 클라이언트에 고정하지 않는 설계를 유지하세요.
|
|
4
|
+
|
|
5
|
+
## 로컬 개발
|
|
6
|
+
|
|
7
|
+
Node.js 22 이상에서 실행합니다.
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
npm ci
|
|
11
|
+
npm run check
|
|
12
|
+
npm test
|
|
13
|
+
npm run build
|
|
14
|
+
npm pack --dry-run
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
테스트는 로컬 fixture를 사용합니다. 실제 키, 개인 워크스페이스 데이터, 네트워크 연결을 기본 테스트에 추가하지 마세요. 연결 테스트가 필요한 변경은 별도 테스트 계정과 최소한의 읽기 작업으로 확인하고 실행 범위를 PR에 기록하세요.
|
|
18
|
+
|
|
19
|
+
## 변경 제안
|
|
20
|
+
|
|
21
|
+
- 버그 보고에는 패키지·Node·OS·클라이언트 버전, 재현 명령과 예상·실제 결과를 적습니다. 키와 개인정보는 제거합니다.
|
|
22
|
+
- PR에는 사용자가 겪는 문제, 변경 후 동작, 수행한 검사와 아직 확인하지 않은 클라이언트를 적습니다.
|
|
23
|
+
- 도구 탐색·호출 변경은 로컬 MCP fixture로 검증합니다. 설정·파일 경로 변경은 Windows 경로와 공백이 있는 경로도 고려합니다.
|
|
24
|
+
- CLI 플래그, 환경 변수, 설치 경로가 바뀌면 README와 Skill을 함께 갱신합니다.
|
|
25
|
+
- `serve`의 stdout은 MCP 메시지 전용입니다. 진단 로그는 stderr로 출력하고 키를 노출하지 않습니다.
|
|
26
|
+
- `setup`은 MCP 설정과 Skill을 함께 설치·업데이트합니다. Steercards 외 설정·주석·사용자 파일은 보존하고 관리 항목에 사용자 수정이 있으면 쓰기 전에 중단합니다. 임시 프로젝트와 격리한 홈 디렉터리에서 첫 설치, 재실행, 이전 버전 업데이트, 충돌, dry run과 쓰기 실패 복구를 검증하세요.
|
|
27
|
+
- `.steercards/setup/` 기록의 버전·옵션·해시를 다음 업데이트의 기준으로 사용합니다. 실제 개인 설치 기록과 ZIP은 테스트 fixture나 커밋에 넣지 마세요.
|
|
28
|
+
- `setup`은 키 없이 실행하고 `.env`를 생성·변경하지 않습니다. `config`는 설정 조각만 출력하며 개별 `skill install`은 사용자 수정 파일을 덮어쓰지 않습니다.
|
|
29
|
+
|
|
30
|
+
변경 제안은 [공개 저장소](https://github.com/velody-ai/steercards-agent-tools)에 PR로 올려주세요. 보안 문제는 공개 이슈에 올리지 말고 [SECURITY.md](SECURITY.md)를 따릅니다.
|
|
31
|
+
|
|
32
|
+
## 릴리스
|
|
33
|
+
|
|
34
|
+
릴리스 담당자는 [npm 릴리스 안내](docs/releases.md)를 따릅니다. 버전 변경 PR을 main에 병합하고 실제 tarball을 검사한 뒤 일치하는 태그의 안정 버전 GitHub Release를 게시합니다. 일반 CI와 main 병합은 검증을 수행하고, Release 게시 이벤트가 npm trusted publishing을 실행합니다.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Steercards contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,195 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Steercards Agent Tools
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Steercards의 전체 MCP 도구를 CLI와 에이전트에서 사용할 수 있게 하는 독립형 Node.js 도구입니다. MIT 라이선스이며 Node.js 22 이상이 필요합니다.
|
|
4
|
+
|
|
5
|
+
- 원격 서버의 도구 목록·설명·입력 스키마를 실행 시 조회합니다. 도구 목록을 패키지에 고정하지 않습니다.
|
|
6
|
+
- 기본 `compact` 모드는 검색 → 스키마 확인 → 호출 흐름으로 초기 도구 노출을 줄입니다.
|
|
7
|
+
- `full` 모드는 원격 도구를 각각 노출합니다.
|
|
8
|
+
- 프로젝트 `.env`를 읽는 STDIO MCP 서버, 단독 CLI, 설치 가능한 Skill을 함께 제공합니다.
|
|
9
|
+
|
|
10
|
+
패키지 이름은 `@steercards/agent-tools`, 실행 명령은 `steercards`입니다. npm에서 설치하거나 소스에서 빌드해 사용할 수 있습니다.
|
|
11
|
+
|
|
12
|
+
## 소스에서 설치
|
|
13
|
+
|
|
14
|
+
소스 디렉터리에서 빌드한 뒤 `setup --local`을 실행합니다.
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
npm ci
|
|
18
|
+
npm run build
|
|
19
|
+
node /absolute/path/agent-tools/dist/cli.js setup --client codex-app --cwd /absolute/path/project --local
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
`setup` 한 번으로 Steercards MCP 설정과 Skill을 함께 설치합니다. 키 없이 설치할 수 있으며 `.env`를 만들거나 덮어쓰지 않습니다. 설치 뒤 프로젝트에 `.env.example`을 참고한 `.env`를 만들고 실제 Agent Key를 입력하세요.
|
|
23
|
+
|
|
24
|
+
```dotenv
|
|
25
|
+
STEERCARDS_AGENT_KEY=your-agent-key
|
|
26
|
+
# 기본값을 사용할 때는 생략합니다.
|
|
27
|
+
STEERCARDS_MCP_URL=https://steercards.com/api/mcp
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
프로젝트 `.gitignore`에 `.env`와 `.steercards/`를 추가하세요. `.steercards/`에는 프로젝트별 설치 기록과 Desktop용 Skill ZIP이 들어갑니다. 설치 기록은 다음 업데이트에 필요한 로컬 소유권 정보이므로 보존하세요. 절대 경로를 포함하므로 다른 프로젝트·컴퓨터로 복사하거나 프로젝트 이동 후 그대로 재사용할 수 없습니다.
|
|
31
|
+
|
|
32
|
+
클라이언트에서 필요한 MCP 승인과 재시작·다시 연결을 마친 뒤 확인합니다.
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
node /absolute/path/agent-tools/dist/cli.js doctor --cwd /absolute/path/project --connect
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
`doctor`는 키 값을 출력하지 않습니다. `--connect`를 추가하면 원격 서버에 연결하고 워크스페이스 목록을 조회하는 읽기 전용 검사를 수행합니다. 생략하면 로컬 설정만 확인합니다.
|
|
39
|
+
|
|
40
|
+
## npm 설치와 업데이트
|
|
41
|
+
|
|
42
|
+
처음 설치할 때와 새 버전으로 업데이트할 때 같은 명령을 사용합니다.
|
|
43
|
+
|
|
44
|
+
```sh
|
|
45
|
+
npx -y @steercards/agent-tools@latest setup --client codex-app --cwd /absolute/path/project
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
실행한 패키지 버전의 MCP 설정과 Skill을 함께 적용합니다. npx 기반 MCP 실행 명령은 해당 버전에 고정되므로 Skill과 같은 버전을 사용합니다. 같은 버전·옵션으로 다시 실행하면 변경 없이 성공합니다. 기존 설치에서는 생략한 실행 옵션(`--local`, `--mode`, `--url`, `--env-file`)을 설치 기록에서 유지합니다. `--local` 설치는 새 소스를 받은 뒤 `npm ci`, `npm run build`를 실행하고 같은 `setup --local` 명령을 다시 실행하세요.
|
|
49
|
+
|
|
50
|
+
소스의 `--local` 설치를 npm 실행 방식으로 전환할 때는 `--npx`를 지정합니다. 이후 MCP 설정은 실행한 패키지 버전의 npx 명령을 사용합니다.
|
|
51
|
+
|
|
52
|
+
```sh
|
|
53
|
+
npx -y @steercards/agent-tools@latest setup --client codex-app --cwd /absolute/path/project --npx
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
전역 설치를 선택했다면 패키지를 업데이트한 뒤 `setup`을 다시 실행합니다.
|
|
57
|
+
|
|
58
|
+
```sh
|
|
59
|
+
npm install --global @steercards/agent-tools@latest
|
|
60
|
+
steercards setup --client codex-app --cwd /absolute/path/project
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
이하 `steercards` 명령은 전역 설치를 기준으로 합니다. 소스 빌드 사용자는 `node /absolute/path/agent-tools/dist/cli.js`로 대체하면 됩니다.
|
|
64
|
+
|
|
65
|
+
## 환경 설정
|
|
66
|
+
|
|
67
|
+
| 설정 | 동작 |
|
|
68
|
+
| --- | --- |
|
|
69
|
+
| `STEERCARDS_AGENT_KEY` | Steercards Agent Key. 원격 요청에 필요합니다. |
|
|
70
|
+
| `STEERCARDS_MCP_URL` | 선택 사항. 기본값은 `https://steercards.com/api/mcp`입니다. |
|
|
71
|
+
| `--cwd PATH` | 프로젝트 디렉터리를 고정합니다. 생략하면 프로세스의 현재 디렉터리를 사용합니다. |
|
|
72
|
+
| `--env-file PATH` | 기본 `.env` 대신 읽을 파일입니다. 상대 경로는 `--cwd` 기준입니다. |
|
|
73
|
+
| `--url URL` | 이번 실행의 MCP URL을 지정합니다. 환경 변수보다 우선합니다. |
|
|
74
|
+
|
|
75
|
+
이미 설정된 프로세스 환경 변수가 `.env`보다 우선합니다. 기본 `.env`는 지정한 디렉터리에서만 찾으며 상위 디렉터리를 탐색하지 않습니다. dotenv 값에 셸 명령이나 `${VARIABLE}` 확장을 수행하지 않습니다. 원격 URL은 HTTPS를 사용하며 로컬 개발용 loopback 주소만 HTTP를 허용합니다. URL의 인증 정보·쿼리·fragment는 허용하지 않습니다.
|
|
76
|
+
|
|
77
|
+
GUI 앱은 터미널과 다른 디렉터리·환경에서 시작될 수 있습니다. 설정을 생성할 때 `--cwd`에 실제 프로젝트의 절대 경로를 지정하세요. 여러 프로젝트를 사용하면 서버 이름과 `--cwd`를 프로젝트별로 구분하세요. 키는 MCP 설정에 복사하지 않고 해당 프로젝트의 `.env`에 둡니다.
|
|
78
|
+
|
|
79
|
+
## 클라이언트 설치·업데이트
|
|
80
|
+
|
|
81
|
+
```sh
|
|
82
|
+
steercards setup --client codex-app --cwd /absolute/path/project
|
|
83
|
+
steercards setup --client claude-code --cwd /absolute/path/project
|
|
84
|
+
steercards setup --client cursor --cwd /absolute/path/project
|
|
85
|
+
steercards setup --client claude-desktop --cwd /absolute/path/project
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
TTY에서 `--client`를 생략하면 사용할 클라이언트를 선택합니다. CI·스크립트 등 대화형 입력을 사용할 수 없는 환경에서는 `--client`를 지정해야 합니다. `codex`, `codex-app`, `codex-cli`는 같은 Codex 설치 위치를 사용합니다.
|
|
89
|
+
|
|
90
|
+
| 클라이언트 | `--client` | MCP 설정과 Skill 설치 위치 |
|
|
91
|
+
| --- | --- | --- |
|
|
92
|
+
| Codex 앱·CLI | `codex`, `codex-app`, `codex-cli` | 프로젝트 `.codex/config.toml`과 `.agents/skills/steercards/`. 프로젝트 설정은 신뢰한 프로젝트에서 사용합니다. [공식 MCP 설정](https://developers.openai.com/codex/mcp), [Skills](https://developers.openai.com/codex/skills) |
|
|
93
|
+
| Claude Code | `claude-code` | 프로젝트 `.mcp.json`과 `.claude/skills/steercards/`. [공식 MCP 설정](https://code.claude.com/docs/en/mcp), [Skills](https://code.claude.com/docs/en/skills) |
|
|
94
|
+
| Cursor | `cursor` | 프로젝트 `.cursor/mcp.json`과 `.cursor/skills/steercards/`. [공식 MCP 설정](https://cursor.com/docs/mcp), [Skills](https://cursor.com/docs/skills) |
|
|
95
|
+
| Claude Desktop | `claude-desktop` | 아래 OS별 사용자 MCP 설정과 프로젝트 `.steercards/steercards-skill.zip`. [로컬 MCP 연결 안내](https://modelcontextprotocol.io/docs/develop/connect-local-servers) |
|
|
96
|
+
|
|
97
|
+
Claude Desktop 자동 설치는 macOS와 Windows를 지원합니다. MCP 설정은 macOS의 `~/Library/Application Support/Claude/claude_desktop_config.json`, Windows의 `%APPDATA%\Claude\claude_desktop_config.json`에 병합합니다. Desktop은 사용자 설정이므로 선택한 프로젝트의 `--cwd`가 연결 대상이 됩니다. 생성한 ZIP은 앱의 Skill 업로드 UI에서 직접 추가해야 하며 업데이트 후에는 새 ZIP을 다시 업로드합니다. 계정·앱의 업로드 지원 여부는 [Claude 공식 Skill 안내](https://support.claude.com/en/articles/12512180-use-skills-in-claude)를 확인하세요.
|
|
98
|
+
|
|
99
|
+
소스에서 빌드한 경우 `--local`을 사용하세요. 실제 Node 실행 파일과 `dist/cli.js`의 절대 경로를 MCP 설정에 넣으므로 해당 설치 디렉터리를 유지해야 합니다. Windows GUI에서도 실행 경로를 확실히 고정하는 이 방식을 권장합니다. `--local`을 생략한 설정은 `npx`를 사용하므로 클라이언트에서 `npx`를 실행할 수 있어야 합니다.
|
|
100
|
+
|
|
101
|
+
지원 옵션:
|
|
102
|
+
|
|
103
|
+
```sh
|
|
104
|
+
steercards setup [--client CLIENT] [--local | --npx] [--dry-run] [--cwd PATH] [--env-file PATH] [--url URL] [--mode compact|full]
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
`--dry-run`은 파일을 쓰지 않고 예정된 작업만 보여줍니다. 키를 출력하거나 연결 검사를 수행하지 않습니다. `setup`은 코드 클라이언트를 프로젝트 범위에 설치하며 `--global`을 지원하지 않습니다. `--env-file`, `--url`, `--mode`는 생성할 MCP 실행 옵션에도 반영됩니다. 같은 버전에서도 옵션을 바꾸면 해당 설정을 갱신합니다. `--local`과 `--npx`는 함께 사용할 수 없으며 `--npx`는 `setup` 전용 옵션입니다.
|
|
108
|
+
|
|
109
|
+
```sh
|
|
110
|
+
steercards setup --client cursor --cwd /absolute/path/project --dry-run
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
`setup`은 기존 설정의 Steercards MCP 항목만 병합하고 다른 서버·설정·주석과 사용자 파일은 보존합니다. `.steercards/setup/*.json`에 설치한 버전·옵션과 관리 파일의 해시를 기록하여 다음 업데이트에서 비교합니다. 관리 기록 없이 이전 `config`·`skill install` 명령으로 설치한 경우에도 현재 생성할 MCP 관리 필드와 Skill 파일이 같으면 관리 대상으로 등록합니다. Codex TOML은 이전 `config`의 정확한 출력 형식이어야 합니다. 그 외의 기존 충돌 항목이나 사용자가 수정한 관리 설정·Skill이 있으면 파일을 쓰기 전에 중단합니다. 충돌 시 수정 내용을 별도로 보관하고 기존 항목과 설치 기록을 검토한 뒤 수동 병합하거나 다시 설치하세요. 일반적인 쓰기 실패는 이전 파일로 복구하지만 전원 차단까지 포함한 원자적 저장을 보장하지 않습니다.
|
|
114
|
+
|
|
115
|
+
기본 `compact` 모드가 노출하는 도구는 다음 네 개입니다.
|
|
116
|
+
|
|
117
|
+
| 도구 | 용도 |
|
|
118
|
+
| --- | --- |
|
|
119
|
+
| `steercards_search_tools` | 필요한 원격 도구 검색 |
|
|
120
|
+
| `steercards_describe_tool` | 선택한 도구의 설명·입력 스키마 확인 |
|
|
121
|
+
| `steercards_call_tool` | 확인한 이름과 인자로 원격 도구 호출 |
|
|
122
|
+
| `steercards_get_guide` | Steercards 사용 가이드 조회 |
|
|
123
|
+
|
|
124
|
+
클라이언트가 개별 도구 노출을 필요로 하면 `setup`에 `--mode full`을 추가하세요.
|
|
125
|
+
|
|
126
|
+
```sh
|
|
127
|
+
steercards setup --client codex-app --cwd /absolute/path/project --mode full
|
|
128
|
+
steercards serve --cwd /absolute/path/project --mode full
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
`compact` 모드의 호출 도구는 여러 종류의 쓰기 작업도 실행할 수 있습니다. 도구 수를 줄이는 기능이며 접근 권한을 제한하지 않습니다. `full` 모드는 원격 도구 이름·스키마·메타데이터를 직접 노출하므로 클라이언트에서 개별 도구를 다루기 쉽습니다. 원격 도구의 메타데이터와 호출 결과의 `isError`·`structuredContent` 오류 신호를 보존합니다. 실제 사용 범위는 Agent Key의 서버 권한으로 결정됩니다.
|
|
132
|
+
|
|
133
|
+
## CLI로 도구 사용
|
|
134
|
+
|
|
135
|
+
먼저 검색 결과에서 정확한 도구 이름을 찾고 스키마를 확인한 뒤 호출합니다. 이름·필수 인자·사용 가능한 기능은 연결한 서버에서 조회한 결과를 따릅니다.
|
|
136
|
+
|
|
137
|
+
```sh
|
|
138
|
+
steercards tools workspace --limit 10 --cwd /absolute/path/project
|
|
139
|
+
steercards describe <tool-name> --cwd /absolute/path/project
|
|
140
|
+
steercards call <tool-name> --json '{"workspaceId":1}' --cwd /absolute/path/project
|
|
141
|
+
steercards call <tool-name> --file ./arguments.json --cwd /absolute/path/project
|
|
142
|
+
steercards call <tool-name> --stdin --cwd /absolute/path/project < arguments.json
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
`<tool-name>`과 JSON은 조회한 스키마에 맞게 바꿉니다. `--json`, `--file`, `--stdin`은 하나만 사용하며 모두 생략하면 `{}`를 전달합니다. 셸 기록에 남길 수 없는 내용은 파일 또는 표준 입력으로 전달하세요. 호출 결과에는 실제 워크스페이스 데이터가 포함될 수 있습니다. CLI는 JSON 결과를 출력하고 프로토콜·제품 오류 시 0이 아닌 종료 코드를 반환합니다. 쓰기 요청은 자동 재시도하지 않습니다.
|
|
146
|
+
|
|
147
|
+
`serve`는 MCP STDIO 연결용입니다. 터미널에서 직접 실행하면 클라이언트 입력을 기다리는 것이 정상입니다.
|
|
148
|
+
|
|
149
|
+
## 고급: 설정 조각과 Skill 개별 설치
|
|
150
|
+
|
|
151
|
+
기본 설치·업데이트에는 `setup`을 사용하세요. 직접 설정을 관리하려면 기존 개별 명령도 사용할 수 있습니다.
|
|
152
|
+
|
|
153
|
+
```sh
|
|
154
|
+
steercards config codex-app --cwd /absolute/path/project
|
|
155
|
+
steercards config cursor --cwd /absolute/path/project --local
|
|
156
|
+
steercards skill install --client codex --cwd /absolute/path/project
|
|
157
|
+
steercards skill install --client claude-code --cwd /absolute/path/project
|
|
158
|
+
steercards skill install --client cursor --cwd /absolute/path/project
|
|
159
|
+
steercards skill export --output /absolute/path/steercards-skill.zip
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
`config`는 설정 조각만 출력하며 클라이언트 설정을 수정하지 않습니다. 출력 내용을 기존 파일에 수동 병합해야 합니다. `skill install --global`은 사용자 홈 아래의 해당 클라이언트 Skill 디렉터리에 개별 설치합니다. 개별 Skill 설치는 같은 내용이면 성공하고 변경된 기존 디렉터리는 덮어쓰지 않습니다. 이 명령들은 MCP·Skill을 함께 갱신하거나 `setup`의 관리 기록을 만들지 않습니다.
|
|
163
|
+
|
|
164
|
+
Skill은 도구 탐색 순서와 작업 요령을 제공합니다. `compact` 모드에서는 Skill을 업로드하지 않아도 `steercards_get_guide` 도구로 가이드를 읽을 수 있습니다. `full` 모드는 이 도구를 추가하지 않으며, `steercards://guide/overview`와 주제별 MCP resource를 제공합니다. Claude Desktop에서 `full` 모드를 사용할 때는 Skill ZIP을 업로드하거나, 클라이언트가 resource 읽기를 지원하는 경우 해당 resource로 가이드를 읽으세요.
|
|
165
|
+
|
|
166
|
+
## 검증 범위와 문제 해결
|
|
167
|
+
|
|
168
|
+
공통 MCP 프로토콜과 로컬 CLI·설정 생성은 로컬 fixture 자동 테스트로 검증합니다. 2026-10-19에는 MCP SDK로 실제 STDIO 서버에 연결해 `compact`의 4개 도구와 `full`의 141개 원격 도구를 확인했고, 두 모드에서 `list_workspaces` 읽기 호출이 성공했습니다. 원격 도구 수는 서버와 Agent Key 권한에 따라 달라집니다.
|
|
169
|
+
|
|
170
|
+
Claude Code, Codex 앱·CLI, Cursor, Claude Desktop 각각의 네이티브 UI 연결을 모두 검증한 것은 아닙니다. 로컬 자동 테스트·실제 STDIO 연결 검증·CI의 OS별 실행·개별 앱에서의 연결 확인은 서로 다른 검증 범위입니다.
|
|
171
|
+
|
|
172
|
+
- 인증 오류: `doctor --cwd …`로 키 탐지 여부를 확인하고 `doctor --connect`로 읽기 전용 연결을 검사하세요. 키 값은 보고서나 이슈에 붙이지 마세요.
|
|
173
|
+
- GUI에서만 실행 실패: Node 22 이상을 설치하고 `--local` 설정을 다시 생성해 절대 실행 경로와 `--cwd`를 확인하세요.
|
|
174
|
+
- 도구가 보이지 않음: MCP 서버를 다시 연결하고 `tools`로 원격 목록을 확인하세요. 특정 키에 없는 권한을 이 패키지가 추가하지는 않습니다.
|
|
175
|
+
- 설치 충돌: `setup --dry-run`으로 예정된 작업을 확인하고 `.steercards/setup/` 기록과 기존 Steercards 항목·Skill 수정 사항을 검토하세요. 기존 파일을 통째로 교체하거나 관리 기록만 지워서 업데이트를 강제하지 마세요.
|
|
176
|
+
|
|
177
|
+
## 개발·기여·릴리스
|
|
178
|
+
|
|
179
|
+
```sh
|
|
180
|
+
npm ci
|
|
181
|
+
npm run check
|
|
182
|
+
npm test
|
|
183
|
+
npm run build
|
|
184
|
+
npm pack --dry-run
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
CI는 Linux·macOS·Windows의 Node 22·24에서 같은 검사를 실행합니다. 테스트는 로컬 fixture를 사용하며 실제 Agent Key가 필요하지 않습니다. 기여 방법은 [CONTRIBUTING.md](CONTRIBUTING.md), 보안 보고는 [SECURITY.md](SECURITY.md)를 참고하세요.
|
|
188
|
+
|
|
189
|
+
공개 소스는 [velody-ai/steercards-agent-tools](https://github.com/velody-ai/steercards-agent-tools)에서 관리합니다. 안정 버전 GitHub Release를 게시하면 `publish.yml`이 태그·패키지 버전과 main 포함 여부를 확인하고 검사를 다시 실행한 뒤 npm에 게시합니다. 인증은 GitHub OIDC trusted publishing을 사용하며 공개 패키지에 provenance를 연결합니다.
|
|
190
|
+
|
|
191
|
+
최초 npm 설정, 릴리스 명령, 게시·설치 확인과 실패 대응은 [npm 릴리스 안내](docs/releases.md)를 따릅니다.
|
|
192
|
+
|
|
193
|
+
## 라이선스
|
|
194
|
+
|
|
195
|
+
[MIT](LICENSE), Copyright (c) 2026 Steercards contributors.
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Security
|
|
2
|
+
|
|
3
|
+
## 보안 문제 보고
|
|
4
|
+
|
|
5
|
+
취약점, Agent Key 노출, 의도하지 않은 파일 덮어쓰기 또는 인증 경계를 우회하는 동작을 발견하면 실제 키와 워크스페이스 데이터를 공개 이슈에 올리지 마세요.
|
|
6
|
+
|
|
7
|
+
공개 저장소가 마련되고 GitHub private vulnerability reporting이 활성화되면 저장소의 **Security → Report a vulnerability**로 비공개 보고합니다. 그 기능이 없거나 소스를 직접 전달받았다면 유지관리자에게 기존 비공개 연락 경로로 보고 방법을 요청하세요. 전용 보안 이메일이나 응답 기한은 아직 지정하지 않았습니다. 첫 공개 릴리스 전에 실제 비공개 보고 경로를 확정해야 합니다.
|
|
8
|
+
|
|
9
|
+
보고에는 영향받는 버전, 재현 조건, 비밀값을 제거한 최소 재현과 예상 영향을 포함하세요. 노출된 키는 Steercards에서 폐기·재발급하고 로그·저장소·공유 자료에 남은 값을 제거하세요.
|
|
10
|
+
|
|
11
|
+
## 로컬 설치 파일
|
|
12
|
+
|
|
13
|
+
`setup`은 선택한 클라이언트의 Steercards MCP 설정과 Skill을 함께 설치·업데이트합니다. 코드 클라이언트는 프로젝트 설정에 쓰고, Claude Desktop은 OS 사용자 MCP 설정에 병합한 뒤 프로젝트에 Skill ZIP을 만듭니다. 앱의 승인·재시작과 Desktop Skill 업로드는 사용자가 진행합니다.
|
|
14
|
+
|
|
15
|
+
설치에는 Agent Key가 필요하지 않으며 `.env`를 만들거나 덮어쓰지 않습니다. `--dry-run`은 쓰기 없이 예정 작업을 보여줍니다. `.steercards/setup/*.json`에는 설치한 버전·실행 옵션·관리 파일의 해시가 들어갑니다. 키는 저장하지 않지만 로컬 경로와 서버 주소가 포함될 수 있으므로 프로젝트 `.gitignore`에 `.steercards/`를 추가하고 설치 기록을 다른 프로젝트·컴퓨터로 복사하지 마세요. 절대 경로가 달라진 설치에는 해당 기록을 그대로 재사용할 수 없습니다.
|
|
16
|
+
|
|
17
|
+
다른 MCP 설정·주석·사용자 파일은 보존합니다. 이전 개별 설치의 MCP 관리 필드와 Skill 파일이 현재 생성할 내용과 일치하면 관리 기록을 만들 수 있습니다. 그 외의 관리 기록 없는 충돌이나 관리 설정·Skill의 사용자 수정은 쓰기 전에 거부합니다. 일반적인 쓰기 실패 시 복구를 시도하지만 전원 차단 등 모든 중단에서 원자적 복구를 보장하지 않습니다. 중요한 사용자 설정은 별도로 백업하세요.
|
|
18
|
+
|
|
19
|
+
## 인증과 데이터
|
|
20
|
+
|
|
21
|
+
- `STEERCARDS_AGENT_KEY`는 로컬 환경 변수 또는 프로젝트 `.env`로 공급합니다. Git, MCP 설정 조각, 이슈, 프롬프트에 키를 붙이지 마세요.
|
|
22
|
+
- 프로젝트 `.env`는 지정한 `--cwd`에서 읽습니다. 신뢰할 수 있는 프로젝트와 환경 파일만 사용하세요.
|
|
23
|
+
- 요청은 설정한 MCP URL로 전송됩니다. `--url`이나 `STEERCARDS_MCP_URL`을 바꿀 때는 신뢰하는 서버인지 확인하세요.
|
|
24
|
+
- Agent Key의 권한과 접근 가능한 워크스페이스는 원격 Steercards 서버가 결정합니다. 이 패키지는 별도 계정·워크스페이스 권한을 부여하지 않습니다.
|
|
25
|
+
- `compact` 모드의 범용 호출 도구는 쓰기와 삭제를 포함한 원격 기능을 실행할 수 있습니다. 읽기 전용 모드나 권한 샌드박스가 아닙니다. 클라이언트의 도구 승인 정책을 사용하고 호출 전에 실제 스키마와 대상을 확인하세요.
|
|
26
|
+
- 도구 결과에는 사용자 데이터가 들어갈 수 있습니다. 키 마스킹만으로 모든 출력의 개인정보가 제거되는 것은 아닙니다.
|
|
27
|
+
|
|
28
|
+
초기 0.1.x 단계에서는 최신 공개 릴리스에 수정 사항을 제공하는 것을 목표로 합니다. 별도 장기 지원 브랜치나 서비스 수준 보장은 없습니다.
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { parseArgs } from 'node:util';
|
|
3
|
+
import { readFile } from 'node:fs/promises';
|
|
4
|
+
import { resolve } from 'node:path';
|
|
5
|
+
import { createInterface } from 'node:readline/promises';
|
|
6
|
+
import { loadConfig } from './config.js';
|
|
7
|
+
import { Runtime } from './runtime.js';
|
|
8
|
+
import { startServer } from './server.js';
|
|
9
|
+
import { clientConfig, installSkill, exportSkill, packageInfo } from './install.js';
|
|
10
|
+
import { setup } from './setup.js';
|
|
11
|
+
const help = `Steercards agent tools ${packageInfo.version}
|
|
12
|
+
|
|
13
|
+
steercards setup [--client CLIENT] [--local | --npx] [--dry-run]
|
|
14
|
+
steercards serve [--mode compact|full]
|
|
15
|
+
steercards tools [query] [--limit 10]
|
|
16
|
+
steercards describe NAME
|
|
17
|
+
steercards call NAME [--json JSON | --file PATH | --stdin]
|
|
18
|
+
steercards doctor [--connect]
|
|
19
|
+
steercards config CLIENT [--local] [--mode compact|full]
|
|
20
|
+
steercards skill install --client CLIENT [--global]
|
|
21
|
+
steercards skill export --output PATH.zip
|
|
22
|
+
|
|
23
|
+
Connection options: --cwd PATH --env-file PATH --url URL
|
|
24
|
+
Default .env: exactly --cwd/.env (otherwise current directory).
|
|
25
|
+
Environment: STEERCARDS_AGENT_KEY, optional STEERCARDS_MCP_URL.
|
|
26
|
+
Clients: claude-code, codex, codex-app, codex-cli, cursor, claude-desktop.
|
|
27
|
+
setup installs MCP configuration and the skill together; rerun to update both.
|
|
28
|
+
setup uses project scope (Desktop uses its user configuration and a project ZIP).
|
|
29
|
+
--npx explicitly switches an existing local setup to a pinned npm package.
|
|
30
|
+
--dry-run previews setup without writing files. No key is needed for setup.
|
|
31
|
+
config only prints a snippet and never edits host settings.
|
|
32
|
+
--local uses this installation's absolute Node/CLI paths (works before npm release).
|
|
33
|
+
Claude Desktop: upload the skill ZIP, use compact get_guide, or full guide resources.
|
|
34
|
+
Full tool responses are JSON; tool/product errors exit nonzero. Writes are never retried.
|
|
35
|
+
`;
|
|
36
|
+
function output(value) { process.stdout.write(JSON.stringify(value, null, 2) + '\n'); }
|
|
37
|
+
function isFailure(result) {
|
|
38
|
+
if (!result || typeof result !== 'object')
|
|
39
|
+
return false;
|
|
40
|
+
const r = result;
|
|
41
|
+
if (r.isError === true || r.structuredContent?.ok === false)
|
|
42
|
+
return true;
|
|
43
|
+
if (Array.isArray(r.content))
|
|
44
|
+
for (const item of r.content) {
|
|
45
|
+
if (item.type === 'text') {
|
|
46
|
+
try {
|
|
47
|
+
if (JSON.parse(item.text)?.ok === false)
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
catch { }
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
async function stdinText() {
|
|
56
|
+
const chunks = [];
|
|
57
|
+
let size = 0;
|
|
58
|
+
for await (const chunk of process.stdin) {
|
|
59
|
+
const bytes = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
60
|
+
size += bytes.length;
|
|
61
|
+
if (size > 7 * 1024 * 1024)
|
|
62
|
+
throw new Error('JSON input exceeds 7 MiB.');
|
|
63
|
+
chunks.push(bytes);
|
|
64
|
+
}
|
|
65
|
+
return Buffer.concat(chunks).toString('utf8');
|
|
66
|
+
}
|
|
67
|
+
let secret = process.env.STEERCARDS_AGENT_KEY;
|
|
68
|
+
async function main() {
|
|
69
|
+
const { values, positionals } = parseArgs({ allowPositionals: true, strict: true, options: {
|
|
70
|
+
cwd: { type: 'string' }, 'env-file': { type: 'string' }, url: { type: 'string' }, mode: { type: 'string' },
|
|
71
|
+
json: { type: 'string' }, file: { type: 'string' }, stdin: { type: 'boolean' },
|
|
72
|
+
client: { type: 'string' }, global: { type: 'boolean' }, output: { type: 'string' },
|
|
73
|
+
limit: { type: 'string' }, connect: { type: 'boolean' }, local: { type: 'boolean' },
|
|
74
|
+
'dry-run': { type: 'boolean' }, npx: { type: 'boolean' },
|
|
75
|
+
help: { type: 'boolean', short: 'h' }, version: { type: 'boolean', short: 'v' },
|
|
76
|
+
} });
|
|
77
|
+
if (values.version) {
|
|
78
|
+
process.stdout.write(packageInfo.version + '\n');
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (values.help || positionals.length === 0) {
|
|
82
|
+
process.stdout.write(help);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const [command, name, ...extra] = positionals;
|
|
86
|
+
const options = { cwd: values.cwd, envFile: values['env-file'], url: values.url };
|
|
87
|
+
if (extra.length)
|
|
88
|
+
throw new Error('Unexpected extra arguments. Use --help.');
|
|
89
|
+
if (command === 'setup') {
|
|
90
|
+
if (name)
|
|
91
|
+
throw new Error('Use setup --client CLIENT.');
|
|
92
|
+
for (const option of ['json', 'file', 'stdin', 'limit', 'output', 'connect']) {
|
|
93
|
+
if (values[option] !== undefined)
|
|
94
|
+
throw new Error(`--${option} is not supported by setup.`);
|
|
95
|
+
}
|
|
96
|
+
if (values.global)
|
|
97
|
+
throw new Error('setup uses project scope; omit --global. Claude Desktop configuration is user-scoped.');
|
|
98
|
+
if (values.local && values.npx)
|
|
99
|
+
throw new Error('Choose only one of --local or --npx.');
|
|
100
|
+
let client = values.client;
|
|
101
|
+
if (!client) {
|
|
102
|
+
if (!process.stdin.isTTY || !process.stderr.isTTY)
|
|
103
|
+
throw new Error('Noninteractive setup requires --client: codex, claude-code, cursor, or claude-desktop.');
|
|
104
|
+
const choices = ['codex', 'claude-code', 'cursor', 'claude-desktop'];
|
|
105
|
+
const prompt = createInterface({ input: process.stdin, output: process.stderr });
|
|
106
|
+
try {
|
|
107
|
+
process.stderr.write('Choose a client:\n1. Codex app / CLI\n2. Claude Code\n3. Cursor\n4. Claude Desktop\n');
|
|
108
|
+
const answer = (await prompt.question('Client [1-4 or name]: ')).trim();
|
|
109
|
+
client = /^[1-4]$/.test(answer) ? choices[Number(answer) - 1] : answer;
|
|
110
|
+
}
|
|
111
|
+
finally {
|
|
112
|
+
prompt.close();
|
|
113
|
+
}
|
|
114
|
+
if (!client)
|
|
115
|
+
throw new Error('No client selected. Nothing was installed.');
|
|
116
|
+
}
|
|
117
|
+
output(await setup({ ...options, client, local: values.npx ? false : values.local, mode: values.mode, dryRun: values['dry-run'] }));
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
if (values['dry-run'] || values.npx)
|
|
121
|
+
throw new Error('--dry-run and --npx are only supported by setup.');
|
|
122
|
+
if (command === 'config') {
|
|
123
|
+
if (!name)
|
|
124
|
+
throw new Error('Choose a client. Use --help.');
|
|
125
|
+
process.stdout.write(clientConfig(name, { ...options, local: values.local, mode: values.mode }));
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
if (command === 'skill') {
|
|
129
|
+
if (name === 'install') {
|
|
130
|
+
if (!values.client)
|
|
131
|
+
throw new Error('skill install requires --client.');
|
|
132
|
+
output(await installSkill({ client: values.client, cwd: values.cwd, global: values.global }));
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
if (name === 'export') {
|
|
136
|
+
if (!values.output)
|
|
137
|
+
throw new Error('skill export requires --output PATH.zip.');
|
|
138
|
+
output({ path: await exportSkill(resolve(values.cwd ?? process.cwd(), values.output)) });
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
throw new Error('Use skill install or skill export.');
|
|
142
|
+
}
|
|
143
|
+
if (!['serve', 'tools', 'describe', 'call', 'doctor'].includes(command))
|
|
144
|
+
throw new Error('Unknown command. Use --help.');
|
|
145
|
+
if (['serve', 'doctor'].includes(command) && name)
|
|
146
|
+
throw new Error('Unexpected positional argument.');
|
|
147
|
+
if (['describe', 'call'].includes(command) && !name)
|
|
148
|
+
throw new Error(`${command} requires a tool name.`);
|
|
149
|
+
if (values.mode && !['compact', 'full'].includes(values.mode))
|
|
150
|
+
throw new Error('Mode must be compact or full.');
|
|
151
|
+
const limit = values.limit === undefined ? 10 : Number(values.limit);
|
|
152
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > 100)
|
|
153
|
+
throw new Error('--limit must be an integer from 1 to 100.');
|
|
154
|
+
let args = {};
|
|
155
|
+
if (command === 'call') {
|
|
156
|
+
if ([values.json !== undefined, values.file !== undefined, values.stdin === true].filter(Boolean).length > 1)
|
|
157
|
+
throw new Error('Choose only one of --json, --file, or --stdin.');
|
|
158
|
+
const source = values.json ?? (values.file !== undefined ? await readFile(resolve(values.cwd ?? process.cwd(), values.file), 'utf8') : values.stdin ? await stdinText() : '{}');
|
|
159
|
+
if (Buffer.byteLength(source) > 7 * 1024 * 1024)
|
|
160
|
+
throw new Error('JSON input exceeds 7 MiB.');
|
|
161
|
+
try {
|
|
162
|
+
args = JSON.parse(source);
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
throw new Error('Invalid JSON arguments.');
|
|
166
|
+
}
|
|
167
|
+
if (args === null || typeof args !== 'object' || Array.isArray(args))
|
|
168
|
+
throw new Error('Tool arguments must be a JSON object.');
|
|
169
|
+
}
|
|
170
|
+
const config = await loadConfig(options);
|
|
171
|
+
secret = config.agentKey;
|
|
172
|
+
if (command === 'doctor' && !values.connect) {
|
|
173
|
+
output({ ok: true, cwd: config.cwd, envFile: config.envFile, url: config.url, keySource: config.keySource, keyPresent: true, connected: false });
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
const runtime = new Runtime(config);
|
|
177
|
+
if (command === 'serve') {
|
|
178
|
+
const server = await startServer(runtime, { mode: (values.mode ?? 'compact') });
|
|
179
|
+
let closing = false;
|
|
180
|
+
const close = async () => { if (closing)
|
|
181
|
+
return; closing = true; await server.close(); await runtime.close(); };
|
|
182
|
+
process.once('SIGINT', () => { void close(); });
|
|
183
|
+
process.once('SIGTERM', () => { void close(); });
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
try {
|
|
187
|
+
if (command === 'tools') {
|
|
188
|
+
output(name ? await runtime.searchTools(name, limit) : (await runtime.listTools()).map(tool => ({ name: tool.name, description: tool.description?.split('\n')[0] })));
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
if (command === 'describe') {
|
|
192
|
+
output(await runtime.describeTool(name));
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
if (command === 'doctor') {
|
|
196
|
+
const catalog = await runtime.listTools();
|
|
197
|
+
const result = await runtime.callTool('list_workspaces', {});
|
|
198
|
+
output({ ok: !isFailure(result), connected: !isFailure(result), toolCount: catalog.length, keySource: config.keySource, result });
|
|
199
|
+
if (isFailure(result))
|
|
200
|
+
process.exitCode = 1;
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
const result = await runtime.callTool(name, args);
|
|
204
|
+
output(result);
|
|
205
|
+
if (isFailure(result))
|
|
206
|
+
process.exitCode = 1;
|
|
207
|
+
}
|
|
208
|
+
finally {
|
|
209
|
+
await runtime.close();
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
main().catch(error => {
|
|
213
|
+
const message = error instanceof Error ? error.message : 'Unexpected failure.';
|
|
214
|
+
const safe = secret ? message.split(secret).join('[REDACTED]') : message;
|
|
215
|
+
process.stderr.write(JSON.stringify({ ok: false, error: safe }) + '\n');
|
|
216
|
+
process.exitCode = 1;
|
|
217
|
+
});
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** Verified against the product HTTP route and production deployment workflow. */
|
|
2
|
+
export declare const DEFAULT_MCP_URL = "https://steercards.com/api/mcp";
|
|
3
|
+
export interface Config {
|
|
4
|
+
url: string;
|
|
5
|
+
agentKey: string;
|
|
6
|
+
cwd: string;
|
|
7
|
+
envFile: string;
|
|
8
|
+
keySource: 'environment' | 'env-file';
|
|
9
|
+
}
|
|
10
|
+
export interface ConfigOptions {
|
|
11
|
+
cwd?: string;
|
|
12
|
+
envFile?: string;
|
|
13
|
+
url?: string;
|
|
14
|
+
/** Supply an isolated environment for embedding or tests. Never mutated. */
|
|
15
|
+
env?: NodeJS.ProcessEnv;
|
|
16
|
+
}
|
|
17
|
+
export declare class ConfigError extends Error {
|
|
18
|
+
constructor(message: string);
|
|
19
|
+
}
|
|
20
|
+
export declare function validateMcpUrl(value: string): string;
|
|
21
|
+
/** Read one selected file only; do not traverse parents or hydrate process.env. */
|
|
22
|
+
export declare function loadConfig(options?: ConfigOptions): Promise<Config>;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { readFile, stat } from 'node:fs/promises';
|
|
2
|
+
import { isAbsolute, resolve } from 'node:path';
|
|
3
|
+
import { parse } from 'dotenv';
|
|
4
|
+
/** Verified against the product HTTP route and production deployment workflow. */
|
|
5
|
+
export const DEFAULT_MCP_URL = 'https://steercards.com/api/mcp';
|
|
6
|
+
export class ConfigError extends Error {
|
|
7
|
+
constructor(message) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.name = 'ConfigError';
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export function validateMcpUrl(value) {
|
|
13
|
+
let url;
|
|
14
|
+
try {
|
|
15
|
+
url = new URL(value);
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
throw new ConfigError('STEERCARDS_MCP_URL must be an absolute HTTP(S) URL.');
|
|
19
|
+
}
|
|
20
|
+
if (url.username || url.password || url.search || url.hash) {
|
|
21
|
+
throw new ConfigError('STEERCARDS_MCP_URL must not contain credentials, a query, or a fragment.');
|
|
22
|
+
}
|
|
23
|
+
const loopback = ['localhost', '127.0.0.1', '[::1]'].includes(url.hostname);
|
|
24
|
+
if (url.protocol !== 'https:' && !(url.protocol === 'http:' && loopback)) {
|
|
25
|
+
throw new ConfigError('STEERCARDS_MCP_URL requires HTTPS, except for localhost.');
|
|
26
|
+
}
|
|
27
|
+
return url.href;
|
|
28
|
+
}
|
|
29
|
+
/** Read one selected file only; do not traverse parents or hydrate process.env. */
|
|
30
|
+
export async function loadConfig(options = {}) {
|
|
31
|
+
const cwd = resolve(options.cwd ?? process.cwd());
|
|
32
|
+
try {
|
|
33
|
+
if (!(await stat(cwd)).isDirectory())
|
|
34
|
+
throw new Error();
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
throw new ConfigError('The selected working directory does not exist or is not a directory.');
|
|
38
|
+
}
|
|
39
|
+
const envFile = options.envFile && isAbsolute(options.envFile)
|
|
40
|
+
? options.envFile : resolve(cwd, options.envFile ?? '.env');
|
|
41
|
+
let file = {};
|
|
42
|
+
try {
|
|
43
|
+
file = parse(await readFile(envFile));
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
if (options.envFile !== undefined || error.code !== 'ENOENT') {
|
|
47
|
+
throw new ConfigError('Unable to read the selected environment file.');
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const env = options.env ?? process.env;
|
|
51
|
+
const fromEnvironment = env.STEERCARDS_AGENT_KEY !== undefined;
|
|
52
|
+
const agentKey = fromEnvironment ? env.STEERCARDS_AGENT_KEY : file.STEERCARDS_AGENT_KEY;
|
|
53
|
+
if (!agentKey || /\s/.test(agentKey)) {
|
|
54
|
+
throw new ConfigError('Set STEERCARDS_AGENT_KEY to a nonempty Agent Key without whitespace.');
|
|
55
|
+
}
|
|
56
|
+
const url = validateMcpUrl(options.url ?? env.STEERCARDS_MCP_URL ?? file.STEERCARDS_MCP_URL ?? DEFAULT_MCP_URL);
|
|
57
|
+
return { url, agentKey, cwd, envFile, keySource: fromEnvironment ? 'environment' : 'env-file' };
|
|
58
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { loadConfig } from './config.js';
|
|
2
|
+
export { Runtime } from './runtime.js';
|
|
3
|
+
export { createServer, startServer } from './server.js';
|
|
4
|
+
export type { Config, ConfigOptions } from './config.js';
|
|
5
|
+
export type { ToolSummary } from './runtime.js';
|
|
6
|
+
export { getGuide } from './server.js';
|
|
7
|
+
export { setup } from './setup.js';
|
|
8
|
+
export type { SetupOptions, SetupReport } from './setup.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export { packageRoot, packageInfo } from './package.js';
|
|
2
|
+
export declare const skillRoot: string;
|
|
3
|
+
export declare const clients: readonly ["claude-code", "codex", "codex-app", "codex-cli", "cursor", "claude-desktop"];
|
|
4
|
+
export type Client = typeof clients[number];
|
|
5
|
+
export declare function clientConfig(client: string, options?: {
|
|
6
|
+
cwd?: string;
|
|
7
|
+
local?: boolean;
|
|
8
|
+
mode?: string;
|
|
9
|
+
url?: string;
|
|
10
|
+
envFile?: string;
|
|
11
|
+
}): string;
|
|
12
|
+
export declare function installSkill(options: {
|
|
13
|
+
client: string;
|
|
14
|
+
cwd?: string;
|
|
15
|
+
global?: boolean;
|
|
16
|
+
home?: string;
|
|
17
|
+
source?: string;
|
|
18
|
+
}): Promise<{
|
|
19
|
+
path: string;
|
|
20
|
+
status: 'installed' | 'unchanged';
|
|
21
|
+
}>;
|
|
22
|
+
export declare function exportSkill(output: string, source?: string): Promise<string>;
|