@nshipster/sosumi 1.0.9 → 1.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/README.md +48 -0
- package/package.json +1 -1
- package/public/SKILL.md +1 -0
- package/public/index.html +49 -4
- package/public/llms.txt +17 -2
- package/public/page.css +104 -0
- package/public/privacy.html +111 -0
- package/public/sitemap.xml +9 -0
- package/public/support.html +65 -0
- package/public/terms.html +73 -0
- package/src/index.ts +17 -0
- package/src/lib/hig/render.ts +1 -1
- package/src/lib/hig/types.ts +1 -1
- package/src/lib/mcp.ts +11 -1
- package/src/lib/reference/render.ts +47 -2
- package/src/lib/types.ts +11 -0
- package/wrangler.jsonc +3 -1
package/README.md
CHANGED
|
@@ -86,6 +86,28 @@ you can run this command to proxy over stdio:
|
|
|
86
86
|
|
|
87
87
|
See [the website](https://sosumi.ai/#clients) for client-specific instructions.
|
|
88
88
|
|
|
89
|
+
#### Plugin
|
|
90
|
+
|
|
91
|
+
The [`plugin`](plugin) folder packages the MCP server and the [agent skill](#ai-agent-skill)
|
|
92
|
+
for Claude Code, Cursor, and [Agent Plugins](https://agent-plugins.org) clients
|
|
93
|
+
such as ChatGPT and Codex.
|
|
94
|
+
|
|
95
|
+
In Claude Code, run:
|
|
96
|
+
|
|
97
|
+
```text
|
|
98
|
+
/plugin marketplace add NSHipster/sosumi.ai
|
|
99
|
+
/plugin install sosumi@sosumi-ai
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
`public/SKILL.md` is the source of the skill.
|
|
103
|
+
After you edit it, copy it into the plugin:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
cp public/SKILL.md plugin/skills/sosumi/SKILL.md
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
A test fails when the two files differ.
|
|
110
|
+
|
|
89
111
|
#### Available Tools
|
|
90
112
|
|
|
91
113
|
- `searchAppleDocumentation` - Searches Apple Developer documentation
|
|
@@ -334,6 +356,32 @@ Publishing is handled by `.github/workflows/release.yml`.
|
|
|
334
356
|
- Release step: `gh release create "$TAG_NAME" --generate-notes`
|
|
335
357
|
- Publish auth: npm trusted publishing via OIDC (`id-token: write`)
|
|
336
358
|
- Publish command: `npm publish --provenance --access public`
|
|
359
|
+
- MCP Registry: after `npm publish`, the workflow publishes `server.json`
|
|
360
|
+
to the [MCP Registry](https://registry.modelcontextprotocol.io)
|
|
361
|
+
as `ai.sosumi/sosumi`.
|
|
362
|
+
|
|
363
|
+
Keep `version` in `server.json` equal to `version` in `package.json`;
|
|
364
|
+
a test fails when they differ.
|
|
365
|
+
|
|
366
|
+
The registry step uses
|
|
367
|
+
[HTTP authentication](https://github.com/modelcontextprotocol/registry/blob/main/docs/modelcontextprotocol-io/authentication.mdx#http-authentication)
|
|
368
|
+
for the `sosumi.ai` domain.
|
|
369
|
+
It skips with a notice until the `MCP_REGISTRY_PRIVATE_KEY` secret is set.
|
|
370
|
+
To set it up, generate an Ed25519 key pair with OpenSSL 3
|
|
371
|
+
(macOS's LibreSSL does not support Ed25519):
|
|
372
|
+
|
|
373
|
+
```bash
|
|
374
|
+
openssl genpkey -algorithm Ed25519 -out key.pem
|
|
375
|
+
# Public key: add to "vars" in wrangler.jsonc as MCP_REGISTRY_PUBLIC_KEY, then deploy
|
|
376
|
+
openssl pkey -in key.pem -pubout -outform DER | tail -c 32 | base64
|
|
377
|
+
# Private key (hex): save as the MCP_REGISTRY_PRIVATE_KEY repository secret
|
|
378
|
+
openssl pkey -in key.pem -noout -text | grep -A3 "priv:" | tail -n +2 | tr -d ' :\n'
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
The Worker then serves `v=MCPv1; k=ed25519; p=<public key>`
|
|
382
|
+
at `/.well-known/mcp-registry-auth`.
|
|
383
|
+
Without the variable, that path returns 404.
|
|
384
|
+
Delete `key.pem` after you save both values.
|
|
337
385
|
|
|
338
386
|
## License
|
|
339
387
|
|
package/package.json
CHANGED
package/public/SKILL.md
CHANGED
|
@@ -85,6 +85,7 @@ Use these when Sosumi is configured as an MCP server (`https://sosumi.ai/mcp`):
|
|
|
85
85
|
- Fetch targeted symbol pages for coding questions.
|
|
86
86
|
- Keep source links in answers so users can verify details quickly.
|
|
87
87
|
- Use Sosumi paths directly in responses whenever referencing Apple documentation pages.
|
|
88
|
+
- Don't rely on conformance conditions, such as "Conforms when `Element` conforms to `Hashable`." Apple's documentation data leaves some out and gets some wrong. When a condition matters, read the declaration in the module's `.swiftinterface` file in the SDK.
|
|
88
89
|
|
|
89
90
|
## Troubleshooting
|
|
90
91
|
|
package/public/index.html
CHANGED
|
@@ -181,6 +181,29 @@
|
|
|
181
181
|
border: 1px solid var(--accent);
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
+
.install-buttons {
|
|
185
|
+
display: flex;
|
|
186
|
+
flex-wrap: wrap;
|
|
187
|
+
gap: 0.75rem;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
a.link-button {
|
|
191
|
+
display: inline-block;
|
|
192
|
+
padding: 0.375rem 0.875rem;
|
|
193
|
+
border-radius: 0.5rem;
|
|
194
|
+
border: 1px solid var(--border);
|
|
195
|
+
background: var(--surface);
|
|
196
|
+
color: var(--text);
|
|
197
|
+
font-weight: 500;
|
|
198
|
+
transition: border 0.2s;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
a.link-button:hover {
|
|
202
|
+
color: var(--text);
|
|
203
|
+
text-decoration: none;
|
|
204
|
+
border-color: var(--accent);
|
|
205
|
+
}
|
|
206
|
+
|
|
184
207
|
figure {
|
|
185
208
|
margin: 0;
|
|
186
209
|
}
|
|
@@ -726,7 +749,18 @@
|
|
|
726
749
|
|
|
727
750
|
<div class="tab-pane" id="vscode-tab">
|
|
728
751
|
<h3>VSCode</h3>
|
|
729
|
-
<p>
|
|
752
|
+
<p>Click a button below to install the sosumi MCP server:</p>
|
|
753
|
+
|
|
754
|
+
<p class="install-buttons">
|
|
755
|
+
<a class="link-button"
|
|
756
|
+
href="https://vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%257B%2522name%2522%253A%2522sosumi%2522%252C%2522type%2522%253A%2522http%2522%252C%2522url%2522%253A%2522https%253A%252F%252Fsosumi.ai%252Fmcp%2522%257D">Install
|
|
757
|
+
in VS Code</a>
|
|
758
|
+
<a class="link-button"
|
|
759
|
+
href="https://vscode.dev/redirect?url=vscode-insiders%3Amcp%2Finstall%3F%257B%2522name%2522%253A%2522sosumi%2522%252C%2522type%2522%253A%2522http%2522%252C%2522url%2522%253A%2522https%253A%252F%252Fsosumi.ai%252Fmcp%2522%257D">Install
|
|
760
|
+
in VS Code Insiders</a>
|
|
761
|
+
</p>
|
|
762
|
+
|
|
763
|
+
<p>Or create a <code>.vscode/mcp.json</code> file in your workspace and enter the following
|
|
730
764
|
configuration:</p>
|
|
731
765
|
|
|
732
766
|
<pre><code class="mcp-config"><span class="dimmed"><span class="punctuation">{</span></span>
|
|
@@ -761,11 +795,17 @@
|
|
|
761
795
|
|
|
762
796
|
<div class="tab-pane" id="claude-code-tab">
|
|
763
797
|
<h3>Claude Code</h3>
|
|
764
|
-
<p>
|
|
798
|
+
<p>Install the sosumi plugin, which adds the MCP server and the Sosumi skill.
|
|
799
|
+
Run these commands in Claude Code:</p>
|
|
800
|
+
<pre><code>/plugin marketplace add NSHipster/sosumi.ai
|
|
801
|
+
/plugin install sosumi@sosumi-ai</code></pre>
|
|
802
|
+
<p>To add only the MCP server, run this command in your terminal:</p>
|
|
765
803
|
<pre><code>claude mcp add --transport http sosumi https://sosumi.ai/mcp</code></pre>
|
|
766
|
-
<p>For more information, see the
|
|
804
|
+
<p>For more information, see the Claude Code documentation for
|
|
805
|
+
<a href="https://code.claude.com/docs/en/plugins/install"
|
|
806
|
+
rel="noopener noreferrer">plugins</a> and
|
|
767
807
|
<a href="https://docs.anthropic.com/en/docs/claude-code/mcp"
|
|
768
|
-
rel="noopener noreferrer">
|
|
808
|
+
rel="noopener noreferrer">MCP</a>.
|
|
769
809
|
</p>
|
|
770
810
|
</div>
|
|
771
811
|
|
|
@@ -1043,6 +1083,11 @@ curl -o ~/.agents/skills/sosumi/SKILL.md https://sosumi.ai/SKILL.md</code></pre>
|
|
|
1043
1083
|
<p>
|
|
1044
1084
|
<strong>Contact:</strong> <a href="mailto:info@sosumi.ai">info@sosumi.ai</a>
|
|
1045
1085
|
</p>
|
|
1086
|
+
<p>
|
|
1087
|
+
<a href="/privacy">Privacy</a> ·
|
|
1088
|
+
<a href="/terms">Terms</a> ·
|
|
1089
|
+
<a href="/support">Support</a>
|
|
1090
|
+
</p>
|
|
1046
1091
|
</div>
|
|
1047
1092
|
|
|
1048
1093
|
<aside>
|
package/public/llms.txt
CHANGED
|
@@ -64,7 +64,12 @@ Open this deep link to automatically install the sosumi MCP server:
|
|
|
64
64
|
|
|
65
65
|
### VSCode
|
|
66
66
|
|
|
67
|
-
|
|
67
|
+
Open one of these links to install the sosumi MCP server:
|
|
68
|
+
|
|
69
|
+
- [Install in VS Code](https://vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%257B%2522name%2522%253A%2522sosumi%2522%252C%2522type%2522%253A%2522http%2522%252C%2522url%2522%253A%2522https%253A%252F%252Fsosumi.ai%252Fmcp%2522%257D)
|
|
70
|
+
- [Install in VS Code Insiders](https://vscode.dev/redirect?url=vscode-insiders%3Amcp%2Finstall%3F%257B%2522name%2522%253A%2522sosumi%2522%252C%2522type%2522%253A%2522http%2522%252C%2522url%2522%253A%2522https%253A%252F%252Fsosumi.ai%252Fmcp%2522%257D)
|
|
71
|
+
|
|
72
|
+
Or create a `.vscode/mcp.json` file in your workspace and enter the following configuration:
|
|
68
73
|
|
|
69
74
|
```json
|
|
70
75
|
{
|
|
@@ -88,7 +93,15 @@ Create a `.vscode/mcp.json` file in your workspace and enter the following confi
|
|
|
88
93
|
|
|
89
94
|
### Claude Code
|
|
90
95
|
|
|
91
|
-
|
|
96
|
+
Install the sosumi plugin, which adds the MCP server and the Sosumi skill.
|
|
97
|
+
Run these commands in Claude Code:
|
|
98
|
+
|
|
99
|
+
```text
|
|
100
|
+
/plugin marketplace add NSHipster/sosumi.ai
|
|
101
|
+
/plugin install sosumi@sosumi-ai
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
To add only the MCP server, run this command in your terminal:
|
|
92
105
|
|
|
93
106
|
```shell
|
|
94
107
|
claude mcp add --transport http sosumi https://sosumi.ai/mcp
|
|
@@ -336,3 +349,5 @@ For external Swift-DocC hosts, sosumi honors `robots.txt` rules
|
|
|
336
349
|
and opt-out response directives such as `X-Robots-Tag: noai`.
|
|
337
350
|
|
|
338
351
|
**Contact:** <info@sosumi.ai>
|
|
352
|
+
|
|
353
|
+
[Privacy](https://sosumi.ai/privacy) · [Terms](https://sosumi.ai/terms) · [Support](https://sosumi.ai/support)
|
package/public/page.css
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/* Shared styles for the policy pages. Colors and type match index.html. */
|
|
2
|
+
:root {
|
|
3
|
+
color-scheme: light dark;
|
|
4
|
+
|
|
5
|
+
--font-sans: -apple-system, BlinkMacSystemFont, 'SF Pro Text', sans-serif;
|
|
6
|
+
--font-mono: 'SF Mono', monospace;
|
|
7
|
+
|
|
8
|
+
--text: oklch(15% 0 0);
|
|
9
|
+
--text-secondary: oklch(35% 0 0);
|
|
10
|
+
--text-tertiary: oklch(55% 0 0);
|
|
11
|
+
|
|
12
|
+
--surface: oklch(98% 0 0);
|
|
13
|
+
--surface-inset: oklch(95% 0.02 70);
|
|
14
|
+
|
|
15
|
+
--border: oklch(20% 0.1 70);
|
|
16
|
+
|
|
17
|
+
--link: oklch(65% 0.15 70);
|
|
18
|
+
--accent: oklch(78% 0.18 70);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@media (prefers-color-scheme: dark) {
|
|
22
|
+
:root {
|
|
23
|
+
--text: oklch(92% 0.02 70);
|
|
24
|
+
--text-secondary: oklch(75% 0.05 70);
|
|
25
|
+
--text-tertiary: oklch(55% 0.08 70);
|
|
26
|
+
|
|
27
|
+
--surface: oklch(18% 0 0);
|
|
28
|
+
--surface-inset: oklch(12% 0.02 70);
|
|
29
|
+
|
|
30
|
+
--border: oklch(25% 0.1 70);
|
|
31
|
+
--accent: oklch(85% 0.2 70);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
body {
|
|
36
|
+
font-family: var(--font-sans);
|
|
37
|
+
color: var(--text);
|
|
38
|
+
background-color: var(--surface);
|
|
39
|
+
max-width: 52rem;
|
|
40
|
+
margin: 3rem auto;
|
|
41
|
+
padding: 1.5rem;
|
|
42
|
+
line-height: 1.6;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
body > header {
|
|
46
|
+
margin-bottom: 2rem;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
body > header p {
|
|
50
|
+
margin: 0;
|
|
51
|
+
font-size: 1.5rem;
|
|
52
|
+
font-weight: bold;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
body > header a {
|
|
56
|
+
color: var(--text);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
h1 {
|
|
60
|
+
font-size: 2.5rem;
|
|
61
|
+
margin-bottom: 0.25rem;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
h2 {
|
|
65
|
+
margin-top: 2rem;
|
|
66
|
+
margin-bottom: 0.625rem;
|
|
67
|
+
color: var(--text-secondary);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.updated {
|
|
71
|
+
color: var(--text-tertiary);
|
|
72
|
+
margin-top: 0;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
code {
|
|
76
|
+
background: var(--surface-inset);
|
|
77
|
+
padding: 0.125rem;
|
|
78
|
+
font-family: var(--font-mono);
|
|
79
|
+
overflow-wrap: break-word;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
a {
|
|
83
|
+
color: var(--link);
|
|
84
|
+
text-decoration: none;
|
|
85
|
+
transition: color 0.2s ease;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
a:hover {
|
|
89
|
+
color: var(--accent);
|
|
90
|
+
text-decoration: underline;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
footer {
|
|
94
|
+
margin-top: 3.75rem;
|
|
95
|
+
padding-top: 1.25rem;
|
|
96
|
+
border-top: 1px solid var(--border);
|
|
97
|
+
color: var(--text-tertiary);
|
|
98
|
+
font-size: 0.875rem;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
::selection {
|
|
102
|
+
background-color: var(--accent);
|
|
103
|
+
color: var(--surface);
|
|
104
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
+
<title>Privacy Policy - sosumi.ai</title>
|
|
8
|
+
<meta name="description" content="What sosumi.ai collects, who receives it, and how long it is kept.">
|
|
9
|
+
<link rel="canonical" href="https://sosumi.ai/privacy">
|
|
10
|
+
<meta name="theme-color" content="#d68d6e" media="(prefers-color-scheme: light)">
|
|
11
|
+
<meta name="theme-color" content="#ec9b7f" media="(prefers-color-scheme: dark)">
|
|
12
|
+
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
|
|
13
|
+
<link rel="alternate icon" href="/favicon.ico">
|
|
14
|
+
<link rel="stylesheet" href="/page.css">
|
|
15
|
+
</head>
|
|
16
|
+
|
|
17
|
+
<body>
|
|
18
|
+
<header>
|
|
19
|
+
<p><a href="/">sosumi.ai</a></p>
|
|
20
|
+
</header>
|
|
21
|
+
|
|
22
|
+
<main>
|
|
23
|
+
<h1>Privacy Policy</h1>
|
|
24
|
+
<p class="updated">Last updated November 7, 2026</p>
|
|
25
|
+
|
|
26
|
+
<p>
|
|
27
|
+
Sosumi is a free service that converts Apple Developer documentation to Markdown.
|
|
28
|
+
It has no accounts, and it doesn't ask for your name, email address, or other personal information.
|
|
29
|
+
This page applies to the website, the HTTP API, and the MCP server at <code>https://sosumi.ai/mcp</code>.
|
|
30
|
+
</p>
|
|
31
|
+
|
|
32
|
+
<h2>What Sosumi keeps</h2>
|
|
33
|
+
<p>
|
|
34
|
+
Sosumi doesn't set cookies.
|
|
35
|
+
It doesn't have a database,
|
|
36
|
+
and it doesn't save the requests it receives or the pages it returns.
|
|
37
|
+
</p>
|
|
38
|
+
<p>
|
|
39
|
+
Sosumi runs on Cloudflare Workers with
|
|
40
|
+
<a href="https://developers.cloudflare.com/workers/observability/logs/workers-logs/" rel="noopener noreferrer">Workers Logs</a>
|
|
41
|
+
turned on.
|
|
42
|
+
For each request, Cloudflare logs the request's URL and other request and response details,
|
|
43
|
+
and it logs any errors that Sosumi reports.
|
|
44
|
+
A URL can include what you asked for, such as a documentation path or a search query.
|
|
45
|
+
Cloudflare keeps these logs for up to 7 days.
|
|
46
|
+
Sosumi's maintainers can read them to find and fix problems.
|
|
47
|
+
</p>
|
|
48
|
+
|
|
49
|
+
<h2>Who receives your requests</h2>
|
|
50
|
+
<p>
|
|
51
|
+
To answer a request, Sosumi's servers fetch the page from developer.apple.com
|
|
52
|
+
or send your search query to Apple's documentation search service.
|
|
53
|
+
For an external Swift-DocC page, Sosumi fetches from the host in the URL you give.
|
|
54
|
+
Those services receive the path, query, or URL from Sosumi's servers.
|
|
55
|
+
Sosumi makes these requests with its own headers.
|
|
56
|
+
It doesn't forward your IP address, cookies, or request headers.
|
|
57
|
+
</p>
|
|
58
|
+
<p>
|
|
59
|
+
When you use Sosumi through an MCP client or plugin,
|
|
60
|
+
your client sends Sosumi the tool's input,
|
|
61
|
+
such as a search query, documentation path, or URL.
|
|
62
|
+
Sosumi handles that input in the same way as any other request.
|
|
63
|
+
</p>
|
|
64
|
+
<p>
|
|
65
|
+
Responses include <code>Cache-Control</code> headers.
|
|
66
|
+
Cloudflare, your client, and proxies between you and Sosumi can keep a copy of a response
|
|
67
|
+
for as long as those headers allow.
|
|
68
|
+
For documentation and search responses, that is at most 24 hours.
|
|
69
|
+
</p>
|
|
70
|
+
<p>
|
|
71
|
+
The home page shows Cursor's install button images, which load from cursor.com.
|
|
72
|
+
When you view the home page, your browser requests those images from Cursor.
|
|
73
|
+
</p>
|
|
74
|
+
<p>
|
|
75
|
+
The <code>sosumi</code> command-line tool runs on your computer.
|
|
76
|
+
It fetches documentation directly from Apple and doesn't send requests to sosumi.ai.
|
|
77
|
+
</p>
|
|
78
|
+
|
|
79
|
+
<h2>Monitoring</h2>
|
|
80
|
+
<p>
|
|
81
|
+
A separate monitoring service checks that sosumi.ai works every 5 minutes.
|
|
82
|
+
It saves whether the last check passed.
|
|
83
|
+
When a check fails or recovers, it saves an alert email with the check's error message
|
|
84
|
+
until the email is sent to the maintainers.
|
|
85
|
+
It doesn't save anything about visitors.
|
|
86
|
+
</p>
|
|
87
|
+
|
|
88
|
+
<h2>Changes and questions</h2>
|
|
89
|
+
<p>
|
|
90
|
+
When this policy changes, the date at the top of this page changes too.
|
|
91
|
+
The page's history is public in the
|
|
92
|
+
<a href="https://github.com/NSHipster/sosumi.ai/commits/main/public/privacy.html" rel="noopener noreferrer">sosumi.ai repository</a>.
|
|
93
|
+
For questions, see <a href="/support">Support</a>.
|
|
94
|
+
</p>
|
|
95
|
+
</main>
|
|
96
|
+
|
|
97
|
+
<footer>
|
|
98
|
+
<p>
|
|
99
|
+
<a href="/privacy">Privacy</a> ·
|
|
100
|
+
<a href="/terms">Terms</a> ·
|
|
101
|
+
<a href="/support">Support</a> ·
|
|
102
|
+
<a href="https://github.com/NSHipster/sosumi.ai" rel="noopener noreferrer">GitHub</a>
|
|
103
|
+
</p>
|
|
104
|
+
<p>
|
|
105
|
+
Sosumi is an unofficial, independent project
|
|
106
|
+
and is not affiliated with or endorsed by Apple Inc.
|
|
107
|
+
</p>
|
|
108
|
+
</footer>
|
|
109
|
+
</body>
|
|
110
|
+
|
|
111
|
+
</html>
|
package/public/sitemap.xml
CHANGED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
+
<title>Support - sosumi.ai</title>
|
|
8
|
+
<meta name="description" content="How to get help with sosumi.ai and report problems.">
|
|
9
|
+
<link rel="canonical" href="https://sosumi.ai/support">
|
|
10
|
+
<meta name="theme-color" content="#d68d6e" media="(prefers-color-scheme: light)">
|
|
11
|
+
<meta name="theme-color" content="#ec9b7f" media="(prefers-color-scheme: dark)">
|
|
12
|
+
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
|
|
13
|
+
<link rel="alternate icon" href="/favicon.ico">
|
|
14
|
+
<link rel="stylesheet" href="/page.css">
|
|
15
|
+
</head>
|
|
16
|
+
|
|
17
|
+
<body>
|
|
18
|
+
<header>
|
|
19
|
+
<p><a href="/">sosumi.ai</a></p>
|
|
20
|
+
</header>
|
|
21
|
+
|
|
22
|
+
<main>
|
|
23
|
+
<h1>Support</h1>
|
|
24
|
+
|
|
25
|
+
<h2>Report a problem or ask a question</h2>
|
|
26
|
+
<p>
|
|
27
|
+
Open an issue on
|
|
28
|
+
<a href="https://github.com/NSHipster/sosumi.ai/issues" rel="noopener noreferrer">GitHub</a>.
|
|
29
|
+
Include the URL or MCP tool input that you used,
|
|
30
|
+
the client that you used (for example, Claude Code, Cursor, or ChatGPT),
|
|
31
|
+
and what you expected to see.
|
|
32
|
+
</p>
|
|
33
|
+
|
|
34
|
+
<h2>Contact</h2>
|
|
35
|
+
<p>
|
|
36
|
+
For anything you don't want to post in public, including security reports,
|
|
37
|
+
email <a href="mailto:info@sosumi.ai">info@sosumi.ai</a>.
|
|
38
|
+
This is the contact in
|
|
39
|
+
<a href="/.well-known/security.txt"><code>security.txt</code></a>.
|
|
40
|
+
</p>
|
|
41
|
+
|
|
42
|
+
<h2>Set up</h2>
|
|
43
|
+
<p>
|
|
44
|
+
Instructions for each MCP client, the command-line tool, and the agent skill are on the
|
|
45
|
+
<a href="/#mcp">home page</a>.
|
|
46
|
+
If your host serves Swift-DocC documentation and you want Sosumi to stop fetching it,
|
|
47
|
+
see <a href="/#bot">how Sosumi fetches pages</a>.
|
|
48
|
+
</p>
|
|
49
|
+
</main>
|
|
50
|
+
|
|
51
|
+
<footer>
|
|
52
|
+
<p>
|
|
53
|
+
<a href="/privacy">Privacy</a> ·
|
|
54
|
+
<a href="/terms">Terms</a> ·
|
|
55
|
+
<a href="/support">Support</a> ·
|
|
56
|
+
<a href="https://github.com/NSHipster/sosumi.ai" rel="noopener noreferrer">GitHub</a>
|
|
57
|
+
</p>
|
|
58
|
+
<p>
|
|
59
|
+
Sosumi is an unofficial, independent project
|
|
60
|
+
and is not affiliated with or endorsed by Apple Inc.
|
|
61
|
+
</p>
|
|
62
|
+
</footer>
|
|
63
|
+
</body>
|
|
64
|
+
|
|
65
|
+
</html>
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
+
<title>Terms of Use - sosumi.ai</title>
|
|
8
|
+
<meta name="description" content="The terms for using sosumi.ai.">
|
|
9
|
+
<link rel="canonical" href="https://sosumi.ai/terms">
|
|
10
|
+
<meta name="theme-color" content="#d68d6e" media="(prefers-color-scheme: light)">
|
|
11
|
+
<meta name="theme-color" content="#ec9b7f" media="(prefers-color-scheme: dark)">
|
|
12
|
+
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
|
|
13
|
+
<link rel="alternate icon" href="/favicon.ico">
|
|
14
|
+
<link rel="stylesheet" href="/page.css">
|
|
15
|
+
</head>
|
|
16
|
+
|
|
17
|
+
<body>
|
|
18
|
+
<header>
|
|
19
|
+
<p><a href="/">sosumi.ai</a></p>
|
|
20
|
+
</header>
|
|
21
|
+
|
|
22
|
+
<main>
|
|
23
|
+
<h1>Terms of Use</h1>
|
|
24
|
+
<p class="updated">Last updated November 7, 2026</p>
|
|
25
|
+
|
|
26
|
+
<p>
|
|
27
|
+
These terms apply to the website, the HTTP API, and the MCP server at <code>https://sosumi.ai/mcp</code>.
|
|
28
|
+
</p>
|
|
29
|
+
|
|
30
|
+
<h2>The service</h2>
|
|
31
|
+
<p>
|
|
32
|
+
Sosumi is free to use.
|
|
33
|
+
It is provided "as is", without warranty of any kind.
|
|
34
|
+
It can change, slow down, or stop at any time, and its output can be incomplete or wrong.
|
|
35
|
+
Check important details against the original page, which each response links to.
|
|
36
|
+
</p>
|
|
37
|
+
|
|
38
|
+
<h2>The code</h2>
|
|
39
|
+
<p>
|
|
40
|
+
Sosumi's source code is available under the
|
|
41
|
+
<a href="https://github.com/NSHipster/sosumi.ai/blob/main/LICENSE.md" rel="noopener noreferrer">MIT license</a>.
|
|
42
|
+
</p>
|
|
43
|
+
|
|
44
|
+
<h2>The documentation</h2>
|
|
45
|
+
<p>
|
|
46
|
+
Documentation content belongs to its owners.
|
|
47
|
+
Apple Inc. owns the content of Apple Developer documentation,
|
|
48
|
+
the Human Interface Guidelines, and Apple's videos.
|
|
49
|
+
The owners of external Swift-DocC sites own their content.
|
|
50
|
+
Sosumi converts a page only when you request it, and it doesn't grant you any rights to that content.
|
|
51
|
+
</p>
|
|
52
|
+
|
|
53
|
+
<h2>Your use</h2>
|
|
54
|
+
<p>
|
|
55
|
+
Your use of Sosumi must comply with Apple's terms of use, the terms of any other site you request, and applicable law.
|
|
56
|
+
</p>
|
|
57
|
+
</main>
|
|
58
|
+
|
|
59
|
+
<footer>
|
|
60
|
+
<p>
|
|
61
|
+
<a href="/privacy">Privacy</a> ·
|
|
62
|
+
<a href="/terms">Terms</a> ·
|
|
63
|
+
<a href="/support">Support</a> ·
|
|
64
|
+
<a href="https://github.com/NSHipster/sosumi.ai" rel="noopener noreferrer">GitHub</a>
|
|
65
|
+
</p>
|
|
66
|
+
<p>
|
|
67
|
+
Sosumi is an unofficial, independent project
|
|
68
|
+
and is not affiliated with or endorsed by Apple Inc.
|
|
69
|
+
</p>
|
|
70
|
+
</footer>
|
|
71
|
+
</body>
|
|
72
|
+
|
|
73
|
+
</html>
|
package/src/index.ts
CHANGED
|
@@ -64,6 +64,7 @@ interface Env {
|
|
|
64
64
|
EXTERNAL_DOC_HOST_BLOCKLIST?: string
|
|
65
65
|
WEB_BOT_AUTH_KEY?: string
|
|
66
66
|
SIGNATURE_AGENT?: string
|
|
67
|
+
MCP_REGISTRY_PUBLIC_KEY?: string
|
|
67
68
|
}
|
|
68
69
|
|
|
69
70
|
const app = new Hono<{ Bindings: Env }>()
|
|
@@ -276,6 +277,22 @@ app.get("/.well-known/security.txt", (c) => {
|
|
|
276
277
|
)
|
|
277
278
|
})
|
|
278
279
|
|
|
280
|
+
// Proves control of the sosumi.ai namespace to the MCP Registry
|
|
281
|
+
// (`mcp-publisher login http`). The registry doesn't follow redirects.
|
|
282
|
+
app.get("/.well-known/mcp-registry-auth", (c) => {
|
|
283
|
+
const publicKey = c.env.MCP_REGISTRY_PUBLIC_KEY?.trim()
|
|
284
|
+
const headers = {
|
|
285
|
+
"Content-Type": "text/plain; charset=utf-8",
|
|
286
|
+
"Cache-Control": "no-store",
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (!publicKey) {
|
|
290
|
+
return c.text("Not Found", 404, headers)
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
return c.text(`v=MCPv1; k=ed25519; p=${publicKey}`, 200, headers)
|
|
294
|
+
})
|
|
295
|
+
|
|
279
296
|
app.on("GET", ["/.well-known/ard.json", "/.well-known/ai-catalog.json"], (c) => {
|
|
280
297
|
const origin = new URL(c.req.url).origin
|
|
281
298
|
|
package/src/lib/hig/render.ts
CHANGED
|
@@ -516,7 +516,7 @@ function renderHIGTocItems(items: HIGTocItem[], headingLevel: number): string {
|
|
|
516
516
|
let markdown = ""
|
|
517
517
|
|
|
518
518
|
for (const item of items) {
|
|
519
|
-
if (item.type === "module" || item.type === "symbol") {
|
|
519
|
+
if (item.type === "module" || item.type === "symbol" || item.type === "collection") {
|
|
520
520
|
// Ensure blank line before heading when preceding content was a list
|
|
521
521
|
if (markdown && !markdown.endsWith("\n\n")) {
|
|
522
522
|
markdown += "\n"
|
package/src/lib/hig/types.ts
CHANGED
package/src/lib/mcp.ts
CHANGED
|
@@ -15,6 +15,16 @@ export const MCP_SERVER_INFO = {
|
|
|
15
15
|
version: "1.0.0",
|
|
16
16
|
} as const
|
|
17
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Guidance for clients, kept out of the documentation itself
|
|
20
|
+
* so that fetched pages stay 1:1 with Apple's content.
|
|
21
|
+
*/
|
|
22
|
+
export const MCP_SERVER_INSTRUCTIONS =
|
|
23
|
+
"Sosumi returns Apple's documentation as Markdown. " +
|
|
24
|
+
'The conformance conditions in Apple\'s data, such as "Conforms when `Element` conforms to `Hashable`.", ' +
|
|
25
|
+
"can be missing or wrong. " +
|
|
26
|
+
"When a condition matters, read the declaration in the module's `.swiftinterface` file in the SDK."
|
|
27
|
+
|
|
18
28
|
export interface ToolHttpBinding {
|
|
19
29
|
path?: string
|
|
20
30
|
pathFrom?: string
|
|
@@ -115,7 +125,7 @@ export const TOOL_DEFINITIONS = {
|
|
|
115
125
|
} satisfies Record<string, ToolMeta>
|
|
116
126
|
|
|
117
127
|
export function createMcpServer(externalPolicyEnv: ExternalPolicyEnv = {}) {
|
|
118
|
-
const server = new McpServer(MCP_SERVER_INFO)
|
|
128
|
+
const server = new McpServer(MCP_SERVER_INFO, { instructions: MCP_SERVER_INSTRUCTIONS })
|
|
119
129
|
|
|
120
130
|
const search = TOOL_DEFINITIONS.searchAppleDocumentation
|
|
121
131
|
server.registerTool(
|
|
@@ -614,7 +614,13 @@ function renderRelationships(
|
|
|
614
614
|
markdown += `## ${rel.title}\n\n`
|
|
615
615
|
for (const id of rel.identifiers) {
|
|
616
616
|
const { title, url } = resolveLink(id, variants, references, externalOrigin)
|
|
617
|
-
|
|
617
|
+
const condition = renderCondition(
|
|
618
|
+
references?.[id],
|
|
619
|
+
"conformancePrefix",
|
|
620
|
+
references,
|
|
621
|
+
externalOrigin,
|
|
622
|
+
)
|
|
623
|
+
markdown += `- [${title}](${url})${condition ? ` ${condition}` : ""}\n`
|
|
618
624
|
}
|
|
619
625
|
markdown += "\n"
|
|
620
626
|
}
|
|
@@ -623,6 +629,30 @@ function renderRelationships(
|
|
|
623
629
|
return markdown
|
|
624
630
|
}
|
|
625
631
|
|
|
632
|
+
/**
|
|
633
|
+
* Render the condition on a reference, or an empty string when it has none.
|
|
634
|
+
* Relationship sections use the conformance prefix
|
|
635
|
+
* ("Conforms when `Element` conforms to `Hashable`."),
|
|
636
|
+
* and topic and see also sections use the availability prefix
|
|
637
|
+
* ("Available when `Element` conforms to `Hashable`.").
|
|
638
|
+
*/
|
|
639
|
+
function renderCondition(
|
|
640
|
+
reference: ContentItem | undefined,
|
|
641
|
+
prefixKey: "conformancePrefix" | "availabilityPrefix",
|
|
642
|
+
references?: Record<string, ContentItem>,
|
|
643
|
+
externalOrigin?: string,
|
|
644
|
+
): string {
|
|
645
|
+
const constraints = reference?.conformance?.constraints
|
|
646
|
+
if (!constraints?.length) {
|
|
647
|
+
return ""
|
|
648
|
+
}
|
|
649
|
+
const prefix = reference?.conformance?.[prefixKey] ?? []
|
|
650
|
+
const inlineContent = prefix.length
|
|
651
|
+
? [...prefix, { type: "text", text: " " }, ...constraints]
|
|
652
|
+
: constraints
|
|
653
|
+
return renderInlineContent(inlineContent, references, 0, externalOrigin).trim()
|
|
654
|
+
}
|
|
655
|
+
|
|
626
656
|
/**
|
|
627
657
|
* Render topic sections
|
|
628
658
|
*/
|
|
@@ -652,6 +682,15 @@ function renderTopicSections(
|
|
|
652
682
|
if (abstract) {
|
|
653
683
|
markdown += ` ${abstract}`
|
|
654
684
|
}
|
|
685
|
+
const condition = renderCondition(
|
|
686
|
+
references?.[id],
|
|
687
|
+
"availabilityPrefix",
|
|
688
|
+
references,
|
|
689
|
+
externalOrigin,
|
|
690
|
+
)
|
|
691
|
+
if (condition) {
|
|
692
|
+
markdown += ` ${condition}`
|
|
693
|
+
}
|
|
655
694
|
markdown += "\n"
|
|
656
695
|
}
|
|
657
696
|
markdown += "\n"
|
|
@@ -730,7 +769,13 @@ function renderSeeAlso(
|
|
|
730
769
|
markdown += `## ${section.title}\n\n`
|
|
731
770
|
for (const id of section.identifiers) {
|
|
732
771
|
const { title, url } = resolveLink(id, variants, references, externalOrigin)
|
|
733
|
-
|
|
772
|
+
const condition = renderCondition(
|
|
773
|
+
references?.[id],
|
|
774
|
+
"availabilityPrefix",
|
|
775
|
+
references,
|
|
776
|
+
externalOrigin,
|
|
777
|
+
)
|
|
778
|
+
markdown += `- [${title}](${url})${condition ? ` ${condition}` : ""}\n`
|
|
734
779
|
}
|
|
735
780
|
markdown += "\n"
|
|
736
781
|
}
|
package/src/lib/types.ts
CHANGED
|
@@ -90,6 +90,17 @@ export interface ContentItem {
|
|
|
90
90
|
|
|
91
91
|
/** Present on reference entries for deprecated symbols. */
|
|
92
92
|
deprecated?: boolean
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Present on reference entries for conditional conformances and members
|
|
96
|
+
* (e.g. "Conforms when `Element` conforms to `Hashable`."
|
|
97
|
+
* or "Available when `Element` conforms to `Hashable`.").
|
|
98
|
+
*/
|
|
99
|
+
conformance?: {
|
|
100
|
+
conformancePrefix?: ContentItem[]
|
|
101
|
+
availabilityPrefix?: ContentItem[]
|
|
102
|
+
constraints?: ContentItem[]
|
|
103
|
+
}
|
|
93
104
|
}
|
|
94
105
|
|
|
95
106
|
// ============================================================================
|
package/wrangler.jsonc
CHANGED
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"/",
|
|
22
22
|
"/.well-known/agent-card.json",
|
|
23
23
|
"/.well-known/agent-skills/*",
|
|
24
|
+
"/.well-known/mcp-registry-auth",
|
|
24
25
|
"/.well-known/security.txt",
|
|
25
26
|
"/message:send",
|
|
26
27
|
"/message:stream",
|
|
@@ -33,6 +34,7 @@
|
|
|
33
34
|
"enabled": true
|
|
34
35
|
},
|
|
35
36
|
"vars": {
|
|
36
|
-
"NODE_ENV": "production"
|
|
37
|
+
"NODE_ENV": "production",
|
|
38
|
+
"MCP_REGISTRY_PUBLIC_KEY": "sL6l9eXq+RN7+VuAVWZGnSacjsgix0TVW5FDLYlBUpg="
|
|
37
39
|
}
|
|
38
40
|
}
|