seyhunakyurek 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.
- package/LICENSE +21 -0
- package/README.md +51 -0
- package/bin/cli.js +128 -0
- package/package.json +19 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Seyhun Akyurek
|
|
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
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# seyhunakyurek — CLI
|
|
2
|
+
|
|
3
|
+
CLI for [Seyhun Akyurek](https://seyhunakyurek.com) portfolio — AI Architect & Delivery Lead (Dubai, UAE). It is a zero-install, agent-friendly client for the site's public WebMCP portfolio API.
|
|
4
|
+
|
|
5
|
+
## Quick start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx seyhunakyurek --help
|
|
9
|
+
npx seyhunakyurek projects --json
|
|
10
|
+
npx seyhunakyurek project pact --json
|
|
11
|
+
npx seyhunakyurek mcp --json
|
|
12
|
+
npx seyhunakyurek profile --json
|
|
13
|
+
npx seyhunakyurek openapi --json
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Commands emit machine-readable JSON when `--json` is used. Read-only requests require no API key. For a local checkout, point the same client at a development server with `--base-url http://localhost:3000` or `SEYHUNAKYUREK_API=http://localhost:3000`.
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
Install from npm (after the package is published):
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm i -g seyhunakyurek
|
|
25
|
+
# or
|
|
26
|
+
npx seyhunakyurek --help
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## API
|
|
30
|
+
|
|
31
|
+
- REST: `GET https://seyhunakyurek.com/api/v1/webmcp/projects` (also `GET /api/webmcp/projects`)
|
|
32
|
+
- Headers: `API-Version: v1`, `RateLimit-*`, `Retry-After` on 429, `Sunset`/`Deprecation` on version changes
|
|
33
|
+
- OpenAPI: `https://seyhunakyurek.com/openapi.json` (alias `/api/openapi.json`)
|
|
34
|
+
- MCP: `POST https://seyhunakyurek.com/api/mcp` (Streamable HTTP, protocol 2024-11-05)
|
|
35
|
+
- Docs: `https://seyhunakyurek.com/developers`
|
|
36
|
+
|
|
37
|
+
## Source
|
|
38
|
+
|
|
39
|
+
https://github.com/seyhunak/seyhunakyurek-cli
|
|
40
|
+
|
|
41
|
+
## Repository
|
|
42
|
+
|
|
43
|
+
This CLI is maintained as a standalone public repository so it can be installed and audited independently of the portfolio site.
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
git clone https://github.com/seyhunak/seyhunakyurek-cli.git
|
|
47
|
+
cd seyhunakyurek-cli
|
|
48
|
+
node bin/cli.js --help
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
To publish a new npm release, maintainers with npm publish access can run `npm publish` from the repository root.
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* seyhunakyurek CLI — https://seyhunakyurek.com
|
|
4
|
+
* Thin wrapper over the public portfolio API + MCP discovery.
|
|
5
|
+
* Usage: npx seyhunakyurek [projects|project <slug>|profile|mcp] [--json]
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const API = (process.env.SEYHUNAKYUREK_API || "https://seyhunakyurek.com").replace(/\/$/, "");
|
|
9
|
+
const args = process.argv.slice(2);
|
|
10
|
+
const jsonFlag = args.includes("--json");
|
|
11
|
+
const cmd = args.find(a => !a.startsWith("-") && !a.startsWith("http://") && !a.startsWith("https://")) || "help";
|
|
12
|
+
const baseUrlIndex = args.indexOf("--base-url");
|
|
13
|
+
const baseUrl = baseUrlIndex !== -1 ? args[baseUrlIndex + 1] : API;
|
|
14
|
+
if (baseUrlIndex !== -1 && !baseUrl) {
|
|
15
|
+
console.error("--base-url requires a URL");
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function printHelp() {
|
|
20
|
+
console.log(`seyhunakyurek — CLI for https://seyhunakyurek.com
|
|
21
|
+
Usage:
|
|
22
|
+
npx seyhunakyurek projects [--json] [--category <cat>]
|
|
23
|
+
npx seyhunakyurek project <slug> [--json]
|
|
24
|
+
npx seyhunakyurek profile [--json]
|
|
25
|
+
npx seyhunakyurek mcp [--json]
|
|
26
|
+
npx seyhunakyurek openapi [--json]
|
|
27
|
+
npx seyhunakyurek --base-url http://localhost:3000 projects --json
|
|
28
|
+
npx seyhunakyurek --help
|
|
29
|
+
|
|
30
|
+
Docs: https://seyhunakyurek.com/developers
|
|
31
|
+
OpenAPI: https://seyhunakyurek.com/openapi.json
|
|
32
|
+
MCP: https://seyhunakyurek.com/api/mcp
|
|
33
|
+
`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function fetchJson(path) {
|
|
37
|
+
const res = await fetch(`${baseUrl}${path}`, { headers: { "Accept": "application/json" }});
|
|
38
|
+
let body;
|
|
39
|
+
try { body = await res.json(); } catch { body = {}; }
|
|
40
|
+
const rl = {
|
|
41
|
+
limit: res.headers.get("RateLimit-Limit"),
|
|
42
|
+
remaining: res.headers.get("RateLimit-Remaining"),
|
|
43
|
+
reset: res.headers.get("RateLimit-Reset"),
|
|
44
|
+
version: res.headers.get("API-Version"),
|
|
45
|
+
};
|
|
46
|
+
if (!res.ok) {
|
|
47
|
+
const err = body?.error?.message || res.statusText;
|
|
48
|
+
throw new Error(`${res.status} ${err} (RateLimit: ${rl.remaining}/${rl.limit})`);
|
|
49
|
+
}
|
|
50
|
+
return { body, rl };
|
|
51
|
+
}
|
|
52
|
+
async function fetchWithFallback(v1Path, unversionedPath) {
|
|
53
|
+
try {
|
|
54
|
+
return await fetchJson(v1Path);
|
|
55
|
+
} catch (e) {
|
|
56
|
+
if (String(e.message).startsWith("404")) return await fetchJson(unversionedPath);
|
|
57
|
+
throw e;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async function main() {
|
|
62
|
+
if (args.includes("--help") || args.includes("-h") || cmd === "help") {
|
|
63
|
+
printHelp();
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (cmd === "projects") {
|
|
67
|
+
const catIdx = args.indexOf("--category");
|
|
68
|
+
const cat = catIdx !== -1 ? args[catIdx+1] : null;
|
|
69
|
+
const q = cat ? `?category=${encodeURIComponent(cat)}` : "";
|
|
70
|
+
// Prefer versioned endpoint, fallback to unversioned until deployed
|
|
71
|
+
const { body, rl } = await fetchWithFallback(`/api/v1/webmcp/projects${q}`, `/api/webmcp/projects${q}`);
|
|
72
|
+
if (jsonFlag) console.log(JSON.stringify(body, null, 2));
|
|
73
|
+
else {
|
|
74
|
+
console.log(`Seyhun Akyurek — ${body.count}/${body.total} projects (v1) RateLimit ${rl.remaining}/${rl.limit}`);
|
|
75
|
+
for (const p of body.projects) console.log(`- ${p.slug} ${p.title} [${p.category}] ${API}${p.href}`);
|
|
76
|
+
console.log(`\nCategories: ${body.categories.join(", ")}`);
|
|
77
|
+
}
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
if (cmd === "project") {
|
|
81
|
+
const slug = args[args.indexOf(cmd)+1];
|
|
82
|
+
if (!slug || slug.startsWith("-")) { console.error("Missing slug. Usage: npx seyhunakyurek project <slug>"); process.exit(1); }
|
|
83
|
+
const { body } = await fetchWithFallback(`/api/v1/webmcp/projects/${encodeURIComponent(slug)}`, `/api/webmcp/projects/${encodeURIComponent(slug)}`);
|
|
84
|
+
if (jsonFlag) console.log(JSON.stringify(body, null, 2));
|
|
85
|
+
else {
|
|
86
|
+
console.log(`${body.title} — ${body.subtitle}\nCategory: ${body.category}\n${body.description}\n\nTech: ${(body.techStack||[]).join(", ")}\nURL: ${API}/projects/${body.slug}`);
|
|
87
|
+
}
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
if (cmd === "profile") {
|
|
91
|
+
const { body } = await fetchJson(`/api/mcp`); // discovery as proxy for profile
|
|
92
|
+
// Use MCP tool get_site_profile via POST
|
|
93
|
+
const res = await fetch(`${baseUrl}/api/mcp`, {
|
|
94
|
+
method: "POST",
|
|
95
|
+
headers: { "Content-Type": "application/json" },
|
|
96
|
+
body: JSON.stringify({ jsonrpc:"2.0", id:1, method:"tools/call", params:{ name:"get_site_profile", arguments:{} }})
|
|
97
|
+
});
|
|
98
|
+
const data = await res.json();
|
|
99
|
+
const profile = data.result?.structuredContent || data.result;
|
|
100
|
+
if (jsonFlag) console.log(JSON.stringify(profile, null, 2));
|
|
101
|
+
else console.log(JSON.stringify(profile, null, 2));
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
if (cmd === "mcp") {
|
|
105
|
+
const { body } = await fetchJson(`/api/mcp`);
|
|
106
|
+
if (jsonFlag) console.log(JSON.stringify(body, null, 2));
|
|
107
|
+
else {
|
|
108
|
+
console.log(`MCP discovery — ${API}/api/mcp (Streamable HTTP, Seyhun Akyurek)`);
|
|
109
|
+
console.log(JSON.stringify(body, null, 2));
|
|
110
|
+
}
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
if (cmd === "openapi") {
|
|
114
|
+
const { body } = await fetchJson(`/openapi.json`);
|
|
115
|
+
const output = { openapi: body.openapi, info: body.info, version: body.info?.version };
|
|
116
|
+
if (jsonFlag) console.log(JSON.stringify(output, null, 2));
|
|
117
|
+
else {
|
|
118
|
+
console.log(`${baseUrl}/openapi.json (alias ${baseUrl}/api/openapi.json)`);
|
|
119
|
+
console.log(JSON.stringify(output, null, 2));
|
|
120
|
+
}
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
console.error(`Unknown command: ${cmd}`);
|
|
124
|
+
printHelp();
|
|
125
|
+
process.exit(1);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
main().catch(e => { console.error(e.message); process.exit(1); });
|
package/package.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "seyhunakyurek",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Agent-friendly CLI for the Seyhun Akyurek WebMCP portfolio API",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"seyhunakyurek": "./bin/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "node --test",
|
|
11
|
+
"prepublishOnly": "npm test && node --check bin/cli.js"
|
|
12
|
+
},
|
|
13
|
+
"keywords": ["webmcp", "mcp", "ai-agent", "cli", "portfolio", "seyhunakyurek"],
|
|
14
|
+
"author": "Seyhun Akyurek",
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"files": ["bin", "README.md", "LICENSE"],
|
|
17
|
+
"engines": { "node": ">=18" },
|
|
18
|
+
"publishConfig": { "access": "public" }
|
|
19
|
+
}
|