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.
Files changed (4) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +51 -0
  3. package/bin/cli.js +128 -0
  4. 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
+ }