@vucinatim/agentic-devtools 0.1.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.
- package/LICENSE +21 -0
- package/README.md +202 -0
- package/SECURITY.md +47 -0
- package/adapters/claude/namecheap/README.md +13 -0
- package/adapters/claude/npm/README.md +11 -0
- package/adapters/claude/railway/README.md +11 -0
- package/adapters/codex/namecheap/.codex-plugin/plugin.json +40 -0
- package/adapters/codex/namecheap/.mcp.json +21 -0
- package/adapters/codex/namecheap/SKILL.md +40 -0
- package/adapters/codex/npm/.codex-plugin/plugin.json +41 -0
- package/adapters/codex/npm/.mcp.json +18 -0
- package/adapters/codex/npm/SKILL.md +54 -0
- package/adapters/codex/railway/.codex-plugin/plugin.json +39 -0
- package/adapters/codex/railway/.mcp.json +20 -0
- package/adapters/codex/railway/SKILL.md +44 -0
- package/docs/README.md +14 -0
- package/docs/architecture.md +208 -0
- package/docs/auth-and-setup-guidelines.md +261 -0
- package/docs/migration-plan.md +55 -0
- package/docs/open-source-readiness.md +119 -0
- package/docs/publishing.md +211 -0
- package/docs/testing.md +61 -0
- package/docs/usage.md +144 -0
- package/package.json +78 -0
- package/src/cli.mjs +158 -0
- package/src/core/config-store.mjs +106 -0
- package/src/core/result.mjs +13 -0
- package/src/core/tool-registry.mjs +29 -0
- package/src/index.mjs +47 -0
- package/src/tools/namecheap/auth.mjs +429 -0
- package/src/tools/namecheap/client.mjs +655 -0
- package/src/tools/namecheap/mcp.mjs +298 -0
- package/src/tools/npm/auth.mjs +367 -0
- package/src/tools/npm/client.mjs +317 -0
- package/src/tools/npm/mcp.mjs +343 -0
- package/src/tools/railway/auth.mjs +402 -0
- package/src/tools/railway/client.mjs +388 -0
- package/src/tools/railway/mcp.mjs +282 -0
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
# Publishing
|
|
2
|
+
|
|
3
|
+
Agentic Devtools should publish to npm from GitHub Actions using npm Trusted
|
|
4
|
+
Publishing.
|
|
5
|
+
|
|
6
|
+
The package should be published primarily for `npx` MCP execution:
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npx -y @vucinatim/agentic-devtools mcp railway
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Library imports are supported, but they are not the main user onboarding path.
|
|
13
|
+
|
|
14
|
+
## Recommended Flow
|
|
15
|
+
|
|
16
|
+
Use:
|
|
17
|
+
|
|
18
|
+
- GitHub public repo: `vucinatim/agentic-devtools`
|
|
19
|
+
- npm package: `@vucinatim/agentic-devtools`
|
|
20
|
+
- GitHub Actions CI
|
|
21
|
+
- npm Trusted Publishing through OIDC
|
|
22
|
+
- provenance attestations
|
|
23
|
+
|
|
24
|
+
Do not use long-lived npm automation tokens unless Trusted Publishing is blocked.
|
|
25
|
+
|
|
26
|
+
## Why Trusted Publishing
|
|
27
|
+
|
|
28
|
+
npm Trusted Publishing creates a trust relationship between npm and the CI
|
|
29
|
+
provider through OIDC. For GitHub Actions, the workflow needs `id-token: write`
|
|
30
|
+
permission so npm can verify the workflow identity.
|
|
31
|
+
|
|
32
|
+
npm also publishes provenance attestations automatically when Trusted Publishing
|
|
33
|
+
is used from supported CI.
|
|
34
|
+
|
|
35
|
+
References:
|
|
36
|
+
|
|
37
|
+
- <https://docs.npmjs.com/trusted-publishers>
|
|
38
|
+
- <https://docs.npmjs.com/generating-provenance-statements>
|
|
39
|
+
- <https://docs.github.com/actions/automating-your-workflow-with-github-actions/publishing-nodejs-packages>
|
|
40
|
+
|
|
41
|
+
## Release Management Recommendation
|
|
42
|
+
|
|
43
|
+
Start simple.
|
|
44
|
+
|
|
45
|
+
Phase 1:
|
|
46
|
+
|
|
47
|
+
- manually bump `package.json` version in a PR
|
|
48
|
+
- merge after CI passes
|
|
49
|
+
- publish from a manual GitHub Actions workflow
|
|
50
|
+
- create a GitHub release for the version tag
|
|
51
|
+
|
|
52
|
+
This avoids heavy release machinery while the package API is still settling.
|
|
53
|
+
|
|
54
|
+
Phase 2:
|
|
55
|
+
|
|
56
|
+
- add Changesets once releases become frequent
|
|
57
|
+
- require a changeset for user-visible package changes
|
|
58
|
+
- let the release PR update version and changelog
|
|
59
|
+
- publish after the release PR lands
|
|
60
|
+
|
|
61
|
+
Changesets is a good fit later because it makes the changelog user-facing rather
|
|
62
|
+
than deriving release notes only from commit messages.
|
|
63
|
+
|
|
64
|
+
Reference:
|
|
65
|
+
|
|
66
|
+
- <https://github.com/changesets/action>
|
|
67
|
+
|
|
68
|
+
## Air Jam Reference
|
|
69
|
+
|
|
70
|
+
Air Jam has a more advanced public package release system:
|
|
71
|
+
|
|
72
|
+
- `release:public`
|
|
73
|
+
- `release:public:next`
|
|
74
|
+
- tag-triggered publishing
|
|
75
|
+
- selected package publishing
|
|
76
|
+
- release validation gates
|
|
77
|
+
- GitHub release creation
|
|
78
|
+
- `pnpm publish --provenance`
|
|
79
|
+
|
|
80
|
+
That is a strong setup for a multi-package repo. Agentic Devtools should borrow
|
|
81
|
+
the quality bar and provenance posture, not the full custom release machinery
|
|
82
|
+
yet.
|
|
83
|
+
|
|
84
|
+
For this repo, one package means a smaller workflow is cleaner.
|
|
85
|
+
|
|
86
|
+
## Initial CI
|
|
87
|
+
|
|
88
|
+
CI should run on pull requests and pushes to `main`:
|
|
89
|
+
|
|
90
|
+
```yaml
|
|
91
|
+
name: CI
|
|
92
|
+
|
|
93
|
+
on:
|
|
94
|
+
pull_request:
|
|
95
|
+
push:
|
|
96
|
+
branches:
|
|
97
|
+
- main
|
|
98
|
+
|
|
99
|
+
jobs:
|
|
100
|
+
checks:
|
|
101
|
+
runs-on: ubuntu-latest
|
|
102
|
+
steps:
|
|
103
|
+
- uses: actions/checkout@v5
|
|
104
|
+
- uses: actions/setup-node@v5
|
|
105
|
+
with:
|
|
106
|
+
node-version: "24"
|
|
107
|
+
cache: "npm"
|
|
108
|
+
- run: npm ci
|
|
109
|
+
- run: npm run check
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
This repo currently uses npm because it is a single package. If it later moves
|
|
113
|
+
to pnpm, mirror Air Jam's `corepack` pattern.
|
|
114
|
+
|
|
115
|
+
## Initial Publish Workflow
|
|
116
|
+
|
|
117
|
+
The first publish workflow should be manual:
|
|
118
|
+
|
|
119
|
+
```yaml
|
|
120
|
+
name: Publish
|
|
121
|
+
|
|
122
|
+
on:
|
|
123
|
+
workflow_dispatch:
|
|
124
|
+
inputs:
|
|
125
|
+
tag:
|
|
126
|
+
description: "npm dist-tag"
|
|
127
|
+
required: true
|
|
128
|
+
default: "latest"
|
|
129
|
+
type: choice
|
|
130
|
+
options:
|
|
131
|
+
- latest
|
|
132
|
+
- next
|
|
133
|
+
|
|
134
|
+
permissions:
|
|
135
|
+
contents: write
|
|
136
|
+
id-token: write
|
|
137
|
+
|
|
138
|
+
jobs:
|
|
139
|
+
publish:
|
|
140
|
+
runs-on: ubuntu-latest
|
|
141
|
+
steps:
|
|
142
|
+
- uses: actions/checkout@v5
|
|
143
|
+
- uses: actions/setup-node@v5
|
|
144
|
+
with:
|
|
145
|
+
node-version: "24"
|
|
146
|
+
registry-url: "https://registry.npmjs.org"
|
|
147
|
+
cache: "npm"
|
|
148
|
+
- run: npm ci
|
|
149
|
+
- run: npm run check
|
|
150
|
+
- run: npm publish --access public --tag "${{ github.event.inputs.tag }}"
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
After npm Trusted Publishing is configured for this exact repo and workflow,
|
|
154
|
+
`npm publish` should authenticate through OIDC without an npm token.
|
|
155
|
+
|
|
156
|
+
## npm Trusted Publisher Setup
|
|
157
|
+
|
|
158
|
+
In npm package settings, configure a trusted publisher for:
|
|
159
|
+
|
|
160
|
+
- provider: GitHub Actions
|
|
161
|
+
- organization/user: `vucinatim`
|
|
162
|
+
- repository: `agentic-devtools`
|
|
163
|
+
- workflow file: `.github/workflows/publish.yml`
|
|
164
|
+
- environment: only if the workflow uses one
|
|
165
|
+
|
|
166
|
+
The workflow must keep:
|
|
167
|
+
|
|
168
|
+
```yaml
|
|
169
|
+
permissions:
|
|
170
|
+
id-token: write
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Package Metadata
|
|
174
|
+
|
|
175
|
+
The public package should include:
|
|
176
|
+
|
|
177
|
+
```json
|
|
178
|
+
{
|
|
179
|
+
"name": "@vucinatim/agentic-devtools",
|
|
180
|
+
"version": "0.1.0",
|
|
181
|
+
"private": false,
|
|
182
|
+
"description": "MCP-first devtools for AI agents.",
|
|
183
|
+
"type": "module",
|
|
184
|
+
"license": "MIT",
|
|
185
|
+
"repository": {
|
|
186
|
+
"type": "git",
|
|
187
|
+
"url": "git+https://github.com/vucinatim/agentic-devtools.git"
|
|
188
|
+
},
|
|
189
|
+
"homepage": "https://github.com/vucinatim/agentic-devtools#readme",
|
|
190
|
+
"bugs": {
|
|
191
|
+
"url": "https://github.com/vucinatim/agentic-devtools/issues"
|
|
192
|
+
},
|
|
193
|
+
"publishConfig": {
|
|
194
|
+
"access": "public"
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## Pre-Publish Checks
|
|
200
|
+
|
|
201
|
+
Before every release:
|
|
202
|
+
|
|
203
|
+
- run tests
|
|
204
|
+
- run typecheck
|
|
205
|
+
- run build
|
|
206
|
+
- inspect `npm pack --dry-run`
|
|
207
|
+
- verify no credential files are included
|
|
208
|
+
- verify CLI entrypoint works from packed output
|
|
209
|
+
- verify README examples are current
|
|
210
|
+
|
|
211
|
+
`npm pack --dry-run` is mandatory before first publish.
|
package/docs/testing.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Testing
|
|
2
|
+
|
|
3
|
+
Agentic Devtools uses Vitest for package tests.
|
|
4
|
+
|
|
5
|
+
The test suite should validate three layers:
|
|
6
|
+
|
|
7
|
+
- service clients and auth resolution
|
|
8
|
+
- shared core helpers and registry behavior
|
|
9
|
+
- public package surfaces such as MCP-first CLI commands and exports
|
|
10
|
+
|
|
11
|
+
## Commands
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm test
|
|
15
|
+
npm run test:namecheap
|
|
16
|
+
npm run test:railway
|
|
17
|
+
npm run coverage
|
|
18
|
+
npm run check
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
`npm run check` is the CI gate. It runs:
|
|
22
|
+
|
|
23
|
+
1. syntax validation for JavaScript source and test files
|
|
24
|
+
2. Vitest with coverage thresholds
|
|
25
|
+
3. production dependency audit
|
|
26
|
+
4. package dry-run validation
|
|
27
|
+
|
|
28
|
+
## Coverage Scope
|
|
29
|
+
|
|
30
|
+
Coverage measures library code under `src/`, excluding:
|
|
31
|
+
|
|
32
|
+
- `src/cli.mjs`
|
|
33
|
+
- `src/tools/*/mcp.mjs`
|
|
34
|
+
|
|
35
|
+
Those files are integration entrypoints. Their behavior should be covered by
|
|
36
|
+
CLI smoke tests and MCP-level tests, not line-by-line unit coverage.
|
|
37
|
+
|
|
38
|
+
Current minimum thresholds:
|
|
39
|
+
|
|
40
|
+
- statements: 65%
|
|
41
|
+
- branches: 50%
|
|
42
|
+
- functions: 65%
|
|
43
|
+
- lines: 65%
|
|
44
|
+
|
|
45
|
+
Raise these as the browser auth flow and MCP entrypoints get more direct test
|
|
46
|
+
coverage.
|
|
47
|
+
|
|
48
|
+
## Package Validation
|
|
49
|
+
|
|
50
|
+
`npm run validate:package` runs `npm pack --dry-run --json` and verifies that
|
|
51
|
+
the public tarball:
|
|
52
|
+
|
|
53
|
+
- includes required runtime files
|
|
54
|
+
- excludes tests
|
|
55
|
+
- excludes GitHub workflow files
|
|
56
|
+
- excludes local auth files
|
|
57
|
+
- excludes environment files
|
|
58
|
+
- excludes generated tarballs
|
|
59
|
+
|
|
60
|
+
This is mandatory for a public package because package contents are part of the
|
|
61
|
+
security boundary.
|
package/docs/usage.md
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# Usage
|
|
2
|
+
|
|
3
|
+
Agentic Devtools is primarily an MCP server package.
|
|
4
|
+
|
|
5
|
+
The default user should configure their agent host to run a specific tool with
|
|
6
|
+
`npx`. They do not need to add Agentic Devtools to their application
|
|
7
|
+
dependencies.
|
|
8
|
+
|
|
9
|
+
Run guided setup once if you want credentials stored locally instead of inline
|
|
10
|
+
in MCP host config:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npx -y @vucinatim/agentic-devtools connect railway
|
|
14
|
+
npx -y @vucinatim/agentic-devtools connect namecheap
|
|
15
|
+
npx -y @vucinatim/agentic-devtools connect npm
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Primary: MCP Host With `npx`
|
|
19
|
+
|
|
20
|
+
Use this for Codex, Claude, or any MCP-compatible host.
|
|
21
|
+
|
|
22
|
+
Railway:
|
|
23
|
+
|
|
24
|
+
```json
|
|
25
|
+
{
|
|
26
|
+
"mcpServers": {
|
|
27
|
+
"railway": {
|
|
28
|
+
"command": "npx",
|
|
29
|
+
"args": ["-y", "@vucinatim/agentic-devtools", "mcp", "railway"],
|
|
30
|
+
"env": {
|
|
31
|
+
"RAILWAY_API_TOKEN": "..."
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
If `connect railway` has already saved a token locally, omit the `env` block.
|
|
39
|
+
|
|
40
|
+
Namecheap:
|
|
41
|
+
|
|
42
|
+
```json
|
|
43
|
+
{
|
|
44
|
+
"mcpServers": {
|
|
45
|
+
"namecheap": {
|
|
46
|
+
"command": "npx",
|
|
47
|
+
"args": ["-y", "@vucinatim/agentic-devtools", "mcp", "namecheap"],
|
|
48
|
+
"env": {
|
|
49
|
+
"NAMECHEAP_API_USER": "...",
|
|
50
|
+
"NAMECHEAP_API_KEY": "...",
|
|
51
|
+
"NAMECHEAP_USERNAME": "...",
|
|
52
|
+
"NAMECHEAP_CLIENT_IP": "..."
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
If `connect namecheap` has already saved credentials locally, omit the `env`
|
|
60
|
+
block.
|
|
61
|
+
|
|
62
|
+
npm:
|
|
63
|
+
|
|
64
|
+
```json
|
|
65
|
+
{
|
|
66
|
+
"mcpServers": {
|
|
67
|
+
"npm": {
|
|
68
|
+
"command": "npx",
|
|
69
|
+
"args": ["-y", "@vucinatim/agentic-devtools", "mcp", "npm"]
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Use `connect npm` for guided token setup when package inspection or token
|
|
76
|
+
operations require authentication.
|
|
77
|
+
|
|
78
|
+
## Secondary: Global CLI
|
|
79
|
+
|
|
80
|
+
Install globally only if you want repeated terminal access without `npx`:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
npm install -g @vucinatim/agentic-devtools
|
|
84
|
+
agentic-devtools tools
|
|
85
|
+
agentic-devtools connect railway
|
|
86
|
+
agentic-devtools connect npm
|
|
87
|
+
agentic-devtools auth-status railway
|
|
88
|
+
agentic-devtools test-connection railway
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Tertiary: Project Dependency
|
|
92
|
+
|
|
93
|
+
Install into a project only when you want to build custom automation using the
|
|
94
|
+
service clients:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
npm install @vucinatim/agentic-devtools
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
```js
|
|
101
|
+
import { createRailwayClient } from "@vucinatim/agentic-devtools";
|
|
102
|
+
import { createNamecheapClient } from "@vucinatim/agentic-devtools";
|
|
103
|
+
import { createNpmClient } from "@vucinatim/agentic-devtools";
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Auth
|
|
107
|
+
|
|
108
|
+
Railway supports:
|
|
109
|
+
|
|
110
|
+
- guided local setup through `agentic-devtools connect railway`
|
|
111
|
+
- `RAILWAY_PROJECT_TOKEN` for project-scoped inspection
|
|
112
|
+
- `RAILWAY_API_TOKEN` or `RAILWAY_TOKEN` for account-scoped inspection
|
|
113
|
+
- `RAILWAY_PROJECT_ID` as an optional default project id
|
|
114
|
+
|
|
115
|
+
Namecheap supports:
|
|
116
|
+
|
|
117
|
+
- guided local setup through `agentic-devtools connect namecheap`
|
|
118
|
+
- `NAMECHEAP_API_USER`
|
|
119
|
+
- `NAMECHEAP_API_KEY`
|
|
120
|
+
- `NAMECHEAP_USERNAME`
|
|
121
|
+
- `NAMECHEAP_CLIENT_IP`
|
|
122
|
+
- `NAMECHEAP_API_SANDBOX=1` for sandbox usage
|
|
123
|
+
- `NAMECHEAP_API_BASE_URL` for an explicit endpoint override
|
|
124
|
+
|
|
125
|
+
npm supports:
|
|
126
|
+
|
|
127
|
+
- guided local setup through `agentic-devtools connect npm`
|
|
128
|
+
- `NPM_TOKEN`
|
|
129
|
+
- `NODE_AUTH_TOKEN`
|
|
130
|
+
- `.npmrc` auth token resolution
|
|
131
|
+
- `NPM_CONFIG_REGISTRY` for registry override
|
|
132
|
+
|
|
133
|
+
For publishing, prefer GitHub Actions Trusted Publishing. Local publishing is
|
|
134
|
+
available through the npm MCP client but defaults to dry-run and requires an
|
|
135
|
+
explicit confirmation string for real publishes.
|
|
136
|
+
|
|
137
|
+
## Usage Philosophy
|
|
138
|
+
|
|
139
|
+
This package should feel like a focused tool belt for agents:
|
|
140
|
+
|
|
141
|
+
- MCP execution via `npx` is the normal path
|
|
142
|
+
- global CLI is a convenience path
|
|
143
|
+
- project dependency usage is for custom builders
|
|
144
|
+
- host adapters should stay thin and point back to the same package runtime
|
package/package.json
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vucinatim/agentic-devtools",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "MCP-first devtools for AI agents.",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"author": {
|
|
9
|
+
"name": "Tim Vucina",
|
|
10
|
+
"email": "tim@vucina.com",
|
|
11
|
+
"url": "https://github.com/vucinatim"
|
|
12
|
+
},
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/vucinatim/agentic-devtools.git"
|
|
16
|
+
},
|
|
17
|
+
"homepage": "https://github.com/vucinatim/agentic-devtools#readme",
|
|
18
|
+
"bugs": {
|
|
19
|
+
"url": "https://github.com/vucinatim/agentic-devtools/issues"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"agentic-devtools",
|
|
23
|
+
"mcp",
|
|
24
|
+
"mcp-server",
|
|
25
|
+
"agents",
|
|
26
|
+
"ai-agents",
|
|
27
|
+
"namecheap",
|
|
28
|
+
"railway",
|
|
29
|
+
"npm",
|
|
30
|
+
"developer-tools"
|
|
31
|
+
],
|
|
32
|
+
"bin": {
|
|
33
|
+
"agentic-devtools": "src/cli.mjs"
|
|
34
|
+
},
|
|
35
|
+
"exports": {
|
|
36
|
+
".": "./src/index.mjs",
|
|
37
|
+
"./namecheap": "./src/tools/namecheap/client.mjs",
|
|
38
|
+
"./railway": "./src/tools/railway/client.mjs",
|
|
39
|
+
"./npm": "./src/tools/npm/client.mjs"
|
|
40
|
+
},
|
|
41
|
+
"files": [
|
|
42
|
+
"src",
|
|
43
|
+
"adapters",
|
|
44
|
+
"docs",
|
|
45
|
+
"README.md",
|
|
46
|
+
"LICENSE",
|
|
47
|
+
"SECURITY.md"
|
|
48
|
+
],
|
|
49
|
+
"publishConfig": {
|
|
50
|
+
"access": "public"
|
|
51
|
+
},
|
|
52
|
+
"engines": {
|
|
53
|
+
"node": ">=20"
|
|
54
|
+
},
|
|
55
|
+
"scripts": {
|
|
56
|
+
"build": "node scripts/check-syntax.mjs",
|
|
57
|
+
"check": "npm run build && npm run coverage && npm run audit && npm run validate:package",
|
|
58
|
+
"coverage": "vitest run --coverage",
|
|
59
|
+
"audit": "npm audit --omit=dev",
|
|
60
|
+
"pack:dry": "npm pack --dry-run",
|
|
61
|
+
"test": "vitest run",
|
|
62
|
+
"test:watch": "vitest",
|
|
63
|
+
"test:namecheap": "vitest run tests/tools/namecheap",
|
|
64
|
+
"test:railway": "vitest run tests/tools/railway",
|
|
65
|
+
"validate:package": "node scripts/validate-package.mjs"
|
|
66
|
+
},
|
|
67
|
+
"dependencies": {
|
|
68
|
+
"@modelcontextprotocol/sdk": "1.29.0",
|
|
69
|
+
"fast-xml-parser": "^5.8.0",
|
|
70
|
+
"zod": "^4.2.1"
|
|
71
|
+
},
|
|
72
|
+
"devDependencies": {
|
|
73
|
+
"@emnapi/core": "^1.10.0",
|
|
74
|
+
"@emnapi/runtime": "^1.10.0",
|
|
75
|
+
"@vitest/coverage-v8": "^4.1.6",
|
|
76
|
+
"vitest": "^4.1.6"
|
|
77
|
+
}
|
|
78
|
+
}
|
package/src/cli.mjs
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { printJson } from "./core/result.mjs";
|
|
4
|
+
import { getTool, listTools } from "./core/tool-registry.mjs";
|
|
5
|
+
|
|
6
|
+
const usage = () => `Usage:
|
|
7
|
+
agentic-devtools tools
|
|
8
|
+
agentic-devtools mcp <namecheap|railway|npm>
|
|
9
|
+
agentic-devtools connect <namecheap|railway|npm>
|
|
10
|
+
agentic-devtools disconnect <namecheap|railway|npm>
|
|
11
|
+
agentic-devtools auth-status <namecheap|railway|npm>
|
|
12
|
+
agentic-devtools test-connection <namecheap|railway|npm>
|
|
13
|
+
|
|
14
|
+
Environment:
|
|
15
|
+
Namecheap: NAMECHEAP_API_USER, NAMECHEAP_API_KEY, NAMECHEAP_USERNAME, NAMECHEAP_CLIENT_IP
|
|
16
|
+
Railway: RAILWAY_PROJECT_TOKEN or RAILWAY_API_TOKEN / RAILWAY_TOKEN
|
|
17
|
+
npm: NPM_TOKEN or NODE_AUTH_TOKEN
|
|
18
|
+
`;
|
|
19
|
+
|
|
20
|
+
const args = process.argv.slice(2);
|
|
21
|
+
|
|
22
|
+
if (args.length === 0 || args[0] === "--help" || args[0] === "-h") {
|
|
23
|
+
process.stdout.write(usage());
|
|
24
|
+
process.exit(0);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (args[0] === "tools") {
|
|
28
|
+
printJson(listTools());
|
|
29
|
+
process.exit(0);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (args[0] === "mcp") {
|
|
33
|
+
const toolName = args[1];
|
|
34
|
+
if (!toolName) {
|
|
35
|
+
throw new Error("Missing tool name for mcp command.");
|
|
36
|
+
}
|
|
37
|
+
const tool = getTool(toolName);
|
|
38
|
+
await import(tool.mcpModule);
|
|
39
|
+
process.exit(0);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (args[0] === "auth-status") {
|
|
43
|
+
const toolName = args[1];
|
|
44
|
+
if (toolName === "namecheap") {
|
|
45
|
+
const { getAuthStatus } = await import("./tools/namecheap/auth.mjs");
|
|
46
|
+
printJson(await getAuthStatus());
|
|
47
|
+
process.exit(0);
|
|
48
|
+
}
|
|
49
|
+
if (toolName === "railway") {
|
|
50
|
+
const { getRailwayAuthStatus } = await import("./tools/railway/client.mjs");
|
|
51
|
+
printJson(getRailwayAuthStatus());
|
|
52
|
+
process.exit(0);
|
|
53
|
+
}
|
|
54
|
+
if (toolName === "npm") {
|
|
55
|
+
const { getNpmAuthStatus } = await import("./tools/npm/auth.mjs");
|
|
56
|
+
printJson(getNpmAuthStatus());
|
|
57
|
+
process.exit(0);
|
|
58
|
+
}
|
|
59
|
+
throw new Error("auth-status expects one of: namecheap, railway, npm");
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (args[0] === "connect") {
|
|
63
|
+
const toolName = args[1];
|
|
64
|
+
if (toolName === "namecheap") {
|
|
65
|
+
const { runBrowserAuthFlow } = await import("./tools/namecheap/auth.mjs");
|
|
66
|
+
process.stderr.write("Opening Namecheap browser setup flow...\n");
|
|
67
|
+
printJson(await runBrowserAuthFlow());
|
|
68
|
+
process.exit(0);
|
|
69
|
+
}
|
|
70
|
+
if (toolName === "railway") {
|
|
71
|
+
const { runRailwayBrowserAuthFlow } = await import(
|
|
72
|
+
"./tools/railway/auth.mjs"
|
|
73
|
+
);
|
|
74
|
+
process.stderr.write("Opening Railway browser setup flow...\n");
|
|
75
|
+
printJson(await runRailwayBrowserAuthFlow());
|
|
76
|
+
process.exit(0);
|
|
77
|
+
}
|
|
78
|
+
if (toolName === "npm") {
|
|
79
|
+
const { runNpmBrowserAuthFlow } = await import("./tools/npm/auth.mjs");
|
|
80
|
+
process.stderr.write("Opening npm browser setup flow...\n");
|
|
81
|
+
printJson(
|
|
82
|
+
await runNpmBrowserAuthFlow({
|
|
83
|
+
onReady: ({ url }) => {
|
|
84
|
+
process.stderr.write(`npm setup URL: ${url}\n`);
|
|
85
|
+
},
|
|
86
|
+
}),
|
|
87
|
+
);
|
|
88
|
+
process.exit(0);
|
|
89
|
+
}
|
|
90
|
+
throw new Error("connect expects one of: namecheap, railway, npm");
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (args[0] === "disconnect") {
|
|
94
|
+
const toolName = args[1];
|
|
95
|
+
if (toolName === "namecheap") {
|
|
96
|
+
const { disconnectNamecheap } = await import("./tools/namecheap/auth.mjs");
|
|
97
|
+
printJson(await disconnectNamecheap());
|
|
98
|
+
process.exit(0);
|
|
99
|
+
}
|
|
100
|
+
if (toolName === "railway") {
|
|
101
|
+
const { disconnectRailway } = await import("./tools/railway/auth.mjs");
|
|
102
|
+
printJson(await disconnectRailway());
|
|
103
|
+
process.exit(0);
|
|
104
|
+
}
|
|
105
|
+
if (toolName === "npm") {
|
|
106
|
+
const { disconnectNpm } = await import("./tools/npm/auth.mjs");
|
|
107
|
+
printJson(await disconnectNpm());
|
|
108
|
+
process.exit(0);
|
|
109
|
+
}
|
|
110
|
+
throw new Error("disconnect expects one of: namecheap, railway, npm");
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (args[0] === "test-connection") {
|
|
114
|
+
const toolName = args[1];
|
|
115
|
+
if (toolName === "namecheap") {
|
|
116
|
+
const { createResolvedNamecheapClient } = await import(
|
|
117
|
+
"./tools/namecheap/client.mjs"
|
|
118
|
+
);
|
|
119
|
+
const client = await createResolvedNamecheapClient();
|
|
120
|
+
const result = await client.listDomains({ page: 1, pageSize: 1 });
|
|
121
|
+
printJson({
|
|
122
|
+
ok: true,
|
|
123
|
+
domainCount: result.paging.totalItems,
|
|
124
|
+
sampleDomains: result.domains.slice(0, 1).map((domain) => domain.name),
|
|
125
|
+
baseUrl: client.baseUrl,
|
|
126
|
+
});
|
|
127
|
+
process.exit(0);
|
|
128
|
+
}
|
|
129
|
+
if (toolName === "railway") {
|
|
130
|
+
const { createRailwayClient } = await import("./tools/railway/client.mjs");
|
|
131
|
+
const client = createRailwayClient();
|
|
132
|
+
const result =
|
|
133
|
+
client.auth.kind === "project"
|
|
134
|
+
? await client.getProjectTokenContext()
|
|
135
|
+
: await client.getCurrentViewer();
|
|
136
|
+
printJson({
|
|
137
|
+
ok: true,
|
|
138
|
+
tokenSource: client.auth.source,
|
|
139
|
+
tokenKind: client.auth.kind,
|
|
140
|
+
result,
|
|
141
|
+
});
|
|
142
|
+
process.exit(0);
|
|
143
|
+
}
|
|
144
|
+
if (toolName === "npm") {
|
|
145
|
+
const { createNpmClient } = await import("./tools/npm/client.mjs");
|
|
146
|
+
const client = createNpmClient();
|
|
147
|
+
printJson({
|
|
148
|
+
ok: true,
|
|
149
|
+
tokenSource: client.auth.source,
|
|
150
|
+
registry: client.registry,
|
|
151
|
+
user: await client.getCurrentUser(),
|
|
152
|
+
});
|
|
153
|
+
process.exit(0);
|
|
154
|
+
}
|
|
155
|
+
throw new Error("test-connection expects one of: namecheap, railway, npm");
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
throw new Error(`Unknown command "${args[0]}".\n\n${usage()}`);
|