@neus/sdk 1.2.0 → 1.2.2
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/cjs/index.cjs +13 -188
- package/cjs/mcp-hosts.cjs +3 -0
- package/cjs/runtime-mount.cjs +2 -2
- package/cli/neus.mjs +2635 -2475
- package/cli-commands.js +75 -0
- package/index.js +1 -10
- package/mcp-hosts.js +25 -0
- package/package.json +4 -1
- package/runtime-adapters.js +214 -0
- package/runtime-mount.js +522 -0
package/cli-commands.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NEUS CLI command strings — SSOT for docs, MCP context, product UI, and skills.
|
|
3
|
+
*
|
|
4
|
+
* Pattern (industry default):
|
|
5
|
+
* - Install once: `npm i -g @neus/sdk`
|
|
6
|
+
* - Daily use: `neus <command>` (short)
|
|
7
|
+
* - Zero-install try: `npx @neus/sdk <command>` (no global install)
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export const NEUS_PKG = '@neus/sdk';
|
|
11
|
+
|
|
12
|
+
/** Recommended one-time install for builders using the CLI regularly. */
|
|
13
|
+
export const NEUS_INSTALL_CLI = `npm i -g ${NEUS_PKG}`;
|
|
14
|
+
|
|
15
|
+
/** Zero-install prefix — works without global install. */
|
|
16
|
+
export const NEUS_NPX = `npx ${NEUS_PKG}`;
|
|
17
|
+
|
|
18
|
+
/** Short commands (after `NEUS_INSTALL_CLI`). */
|
|
19
|
+
export const NEUS_SETUP_CLI = 'neus setup';
|
|
20
|
+
export const NEUS_AUTH_CLI = 'neus auth';
|
|
21
|
+
export const NEUS_CHECK_CLI = 'neus check';
|
|
22
|
+
export const NEUS_DOCTOR_CLI = 'neus doctor --live';
|
|
23
|
+
export const NEUS_EXAMPLES_CLI = 'neus examples';
|
|
24
|
+
|
|
25
|
+
/** One-shot copy-paste (no global install required). */
|
|
26
|
+
export const NEUS_SETUP_NPX = `${NEUS_NPX} setup`;
|
|
27
|
+
export const NEUS_AUTH_NPX = `${NEUS_NPX} auth`;
|
|
28
|
+
export const NEUS_CHECK_NPX = `${NEUS_NPX} check`;
|
|
29
|
+
export const NEUS_DOCTOR_NPX = `${NEUS_NPX} doctor --live`;
|
|
30
|
+
export const NEUS_EXAMPLES_NPX = `${NEUS_NPX} examples`;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @param {string} agentId
|
|
34
|
+
* @param {'cursor' | 'claude' | 'codex'} [host]
|
|
35
|
+
*/
|
|
36
|
+
export function neusMountApply(agentId, host = 'cursor') {
|
|
37
|
+
const id = String(agentId || '').trim();
|
|
38
|
+
return `neus mount ${id} --apply ${host}`;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @param {string} agentId
|
|
43
|
+
* @param {'cursor' | 'claude' | 'codex'} [host]
|
|
44
|
+
*/
|
|
45
|
+
export function neusMountApplyNpx(agentId, host = 'cursor') {
|
|
46
|
+
const id = String(agentId || '').trim();
|
|
47
|
+
return `${NEUS_NPX} mount ${id} --apply ${host}`;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Docs / landing quick start (installed path). */
|
|
51
|
+
export const NEUS_QUICKSTART_INSTALLED = `${NEUS_INSTALL_CLI}
|
|
52
|
+
${NEUS_SETUP_CLI}
|
|
53
|
+
${NEUS_AUTH_CLI}`;
|
|
54
|
+
|
|
55
|
+
/** Docs quick try (zero-install). */
|
|
56
|
+
export const NEUS_QUICKSTART_NPX = NEUS_SETUP_NPX;
|
|
57
|
+
|
|
58
|
+
/** Per-repo agent bind (after auth on the machine). */
|
|
59
|
+
export const NEUS_MOUNT_WORKFLOW = `${NEUS_AUTH_CLI}
|
|
60
|
+
neus mount <agentId> --apply cursor
|
|
61
|
+
${NEUS_DOCTOR_CLI}`;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @param {string} subcommand
|
|
65
|
+
*/
|
|
66
|
+
export function neusCmd(subcommand) {
|
|
67
|
+
return `neus ${String(subcommand || '').trim()}`;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* @param {string} subcommand
|
|
72
|
+
*/
|
|
73
|
+
export function neusNpx(subcommand) {
|
|
74
|
+
return `${NEUS_NPX} ${String(subcommand || '').trim()}`;
|
|
75
|
+
}
|
package/index.js
CHANGED
|
@@ -72,16 +72,7 @@ export {
|
|
|
72
72
|
evaluateMountFileHealth
|
|
73
73
|
} from './runtime-mount.js';
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
MOUNT_MANIFEST_RELATIVE,
|
|
77
|
-
sanitizeAgentIdForFilename,
|
|
78
|
-
bundleToCursorRules,
|
|
79
|
-
bundleToClaudeMd,
|
|
80
|
-
bundleToCodexJson,
|
|
81
|
-
readMountManifest,
|
|
82
|
-
writeMountManifest,
|
|
83
|
-
applyRuntimeBundle
|
|
84
|
-
} from './runtime-adapters.js';
|
|
75
|
+
// Node-only adapters (fs/path): import `@neus/sdk/runtime-adapters` — not re-exported here (Next/webpack safe).
|
|
85
76
|
|
|
86
77
|
export {
|
|
87
78
|
SDKError,
|
package/mcp-hosts.js
CHANGED
|
@@ -57,11 +57,36 @@ export const IDE_HOST_BRAND_LOGOS = {
|
|
|
57
57
|
};
|
|
58
58
|
|
|
59
59
|
/**
|
|
60
|
+
* Build the MCP HTTP server config for an IDE/client.
|
|
61
|
+
*
|
|
62
|
+
* Two paths, one session model — same NEUS Profile/Account either way:
|
|
63
|
+
*
|
|
64
|
+
* - `npk_…` Profile access keys are durable (never expire). Written as a static
|
|
65
|
+
* `Authorization: Bearer npk_…` header. Used for operator IDEs, servers, CI,
|
|
66
|
+
* and automation where browser OAuth is unavailable.
|
|
67
|
+
* - OAuth (default for Cursor, VS Code, Claude Code, Codex): we return a URL-only
|
|
68
|
+
* config (no `headers`). The IDE MCP client discovers OAuth metadata from the
|
|
69
|
+
* server's `401 + WWW-Authenticate` challenge, then runs its own DCR + PKCE +
|
|
70
|
+
* silent-refresh lifecycle (matching Linear, GitHub, Notion). The access token
|
|
71
|
+
* is a short-lived JWT refreshed silently by the host for up to 30 days via the
|
|
72
|
+
* `offline_access` refresh token — the session is long-lived, the access token
|
|
73
|
+
* is not
|
|
74
|
+
*
|
|
75
|
+
* A raw OAuth access token (JWT) is never written as a static Bearer header: IDE
|
|
76
|
+
* MCP clients cannot refresh a static header, and writing one would create a
|
|
77
|
+
* session that dies when the access token expires. URL-only config is the correct
|
|
78
|
+
* OAuth path and is what `neus setup`/`neus auth` produce for browser-OAuth clients.
|
|
79
|
+
*
|
|
60
80
|
* @param {string | null | undefined} accessKey
|
|
61
81
|
* @returns {{ type: 'http'; url: string; headers?: { Authorization: string } }}
|
|
62
82
|
*/
|
|
63
83
|
export function buildNeusMcpHttpConfig(accessKey) {
|
|
64
84
|
const key = String(accessKey || '').trim();
|
|
85
|
+
// OAuth access tokens are JWTs (three dot-separated base64url segments). Never write
|
|
86
|
+
// them as a static Bearer header — return URL-only so the IDE runs OAuth itself.
|
|
87
|
+
if (key && !key.startsWith('npk_') && key.split('.').length === 3) {
|
|
88
|
+
return { type: 'http', url: NEUS_MCP_URL };
|
|
89
|
+
}
|
|
65
90
|
return {
|
|
66
91
|
type: 'http',
|
|
67
92
|
url: NEUS_MCP_URL,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neus/sdk",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.2",
|
|
4
4
|
"description": "NEUS makes trust portable across the internet — so people, apps, and AI agents can prove what is real before access, payout, or execution.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"neus": "cli/neus.mjs"
|
|
@@ -141,6 +141,7 @@
|
|
|
141
141
|
},
|
|
142
142
|
"files": [
|
|
143
143
|
"cli/neus.mjs",
|
|
144
|
+
"cli-commands.js",
|
|
144
145
|
"mcp-hosts.js",
|
|
145
146
|
"index.js",
|
|
146
147
|
"client.js",
|
|
@@ -148,6 +149,8 @@
|
|
|
148
149
|
"errors.js",
|
|
149
150
|
"gates.js",
|
|
150
151
|
"sponsor.js",
|
|
152
|
+
"runtime-mount.js",
|
|
153
|
+
"runtime-adapters.js",
|
|
151
154
|
"cjs/**",
|
|
152
155
|
"widgets.cjs",
|
|
153
156
|
"types.d.ts",
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime Mount adapters — apply proof-backed bundles to host workspaces.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import fs from 'node:fs';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import { RUNTIME_MOUNT_SCHEMA } from './runtime-mount.js';
|
|
8
|
+
|
|
9
|
+
export const MOUNT_MANIFEST_RELATIVE = path.join('.neus', 'mount.json');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @param {string} agentId
|
|
13
|
+
*/
|
|
14
|
+
export function sanitizeAgentIdForFilename(agentId) {
|
|
15
|
+
return String(agentId || 'agent')
|
|
16
|
+
.trim()
|
|
17
|
+
.toLowerCase()
|
|
18
|
+
.replace(/[^a-z0-9_-]+/g, '-')
|
|
19
|
+
.replace(/^-+|-+$/g, '')
|
|
20
|
+
.slice(0, 64) || 'agent';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @param {import('./runtime-mount.js').RuntimeBundle} bundle
|
|
25
|
+
*/
|
|
26
|
+
export function bundleToCursorRules(bundle) {
|
|
27
|
+
const id = bundle.identity.agentId;
|
|
28
|
+
const label = bundle.identity.agentLabel || id;
|
|
29
|
+
const skillsBlock = (bundle.identity.skills || [])
|
|
30
|
+
.map(skill => {
|
|
31
|
+
if (typeof skill === 'string') return `- ${skill}`;
|
|
32
|
+
const labelText = skill.label || skill.id || 'skill';
|
|
33
|
+
const kind = skill.kind || 'skill';
|
|
34
|
+
const provider = skill.provider ? ` / ${skill.provider}` : '';
|
|
35
|
+
return `- ${labelText} (${kind}${provider})`;
|
|
36
|
+
})
|
|
37
|
+
.join('\n');
|
|
38
|
+
|
|
39
|
+
const denied = (bundle.enforce.deniedActions || []).map(action => `- ${action}`).join('\n');
|
|
40
|
+
const capabilities = (bundle.identity.capabilities || []).map(cap => `- ${cap}`).join('\n');
|
|
41
|
+
const services = (bundle.identity.services || [])
|
|
42
|
+
.map(svc => `- ${svc.name}: ${svc.endpoint}${svc.version ? ` (v${svc.version})` : ''}`)
|
|
43
|
+
.join('\n');
|
|
44
|
+
|
|
45
|
+
return `---
|
|
46
|
+
description: NEUS proof-backed agent — ${label}
|
|
47
|
+
globs:
|
|
48
|
+
alwaysApply: true
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
# NEUS Agent — ${label}
|
|
52
|
+
|
|
53
|
+
You are **${label}** (\`${id}\`). This project mounted trust context from NEUS.
|
|
54
|
+
|
|
55
|
+
## Identity
|
|
56
|
+
${bundle.identity.description || bundle.identity.instructions || 'Follow the agent instructions below.'}
|
|
57
|
+
|
|
58
|
+
## Instructions
|
|
59
|
+
${bundle.identity.instructions || 'Use NEUS MCP for trust checks before sensitive actions.'}
|
|
60
|
+
|
|
61
|
+
## Capabilities
|
|
62
|
+
${capabilities || '- General purpose'}
|
|
63
|
+
|
|
64
|
+
## Skills
|
|
65
|
+
${skillsBlock || '- None configured'}
|
|
66
|
+
|
|
67
|
+
## Services
|
|
68
|
+
${services || '- None configured'}
|
|
69
|
+
|
|
70
|
+
## Scoped policy
|
|
71
|
+
${denied ? `Denied actions (do not perform without new approval):\n${denied}` : '- Follow delegation on file via NEUS MCP.'}
|
|
72
|
+
|
|
73
|
+
## Trust workflow
|
|
74
|
+
1. Call \`neus_context\` once per session when NEUS MCP is available.
|
|
75
|
+
2. Trust before action: \`neus_proofs_check\` then \`neus_verify_or_guide\`.
|
|
76
|
+
3. Do not invent qHashes, wallets, or receipt fields.
|
|
77
|
+
4. Summarize NEUS outcomes as Trust Result — never dump raw tool JSON.
|
|
78
|
+
|
|
79
|
+
## Proof references
|
|
80
|
+
- Identity: ${bundle.trust.identityProofUrl}
|
|
81
|
+
${bundle.trust.delegationProofUrl ? `- Delegation: ${bundle.trust.delegationProofUrl}` : '- Delegation: not on file — call `neus_agent_link` before acting as this agent.'}
|
|
82
|
+
`;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* @param {import('./runtime-mount.js').RuntimeBundle} bundle
|
|
87
|
+
*/
|
|
88
|
+
export function bundleToClaudeMd(bundle) {
|
|
89
|
+
const id = bundle.identity.agentId;
|
|
90
|
+
const label = bundle.identity.agentLabel || id;
|
|
91
|
+
return `# NEUS Agent — ${label}
|
|
92
|
+
|
|
93
|
+
Mounted from NEUS Runtime Mount (\`${RUNTIME_MOUNT_SCHEMA}\`).
|
|
94
|
+
|
|
95
|
+
## Identity
|
|
96
|
+
- **Agent ID:** ${id}
|
|
97
|
+
- **Label:** ${label}
|
|
98
|
+
|
|
99
|
+
## Description
|
|
100
|
+
${bundle.identity.description || 'Proof-backed agent on NEUS Network.'}
|
|
101
|
+
|
|
102
|
+
## Instructions
|
|
103
|
+
${bundle.identity.instructions || 'Use NEUS MCP before sensitive actions.'}
|
|
104
|
+
|
|
105
|
+
## Trust receipts
|
|
106
|
+
- Identity: \`${bundle.trust.identityQHash}\` — ${bundle.trust.identityProofUrl}
|
|
107
|
+
${bundle.trust.delegationQHash ? `- Delegation: \`${bundle.trust.delegationQHash}\` — ${bundle.trust.delegationProofUrl}` : ''}
|
|
108
|
+
|
|
109
|
+
## Policy
|
|
110
|
+
- Do not invent qHashes or verifier outcomes.
|
|
111
|
+
- Call \`neus_context\` once; use profile context when signed in.
|
|
112
|
+
`;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* @param {import('./runtime-mount.js').RuntimeBundle} bundle
|
|
117
|
+
*/
|
|
118
|
+
export function bundleToCodexJson(bundle) {
|
|
119
|
+
return JSON.stringify(
|
|
120
|
+
{
|
|
121
|
+
schema: RUNTIME_MOUNT_SCHEMA,
|
|
122
|
+
name: bundle.identity.agentLabel,
|
|
123
|
+
agentId: bundle.identity.agentId,
|
|
124
|
+
agentWallet: bundle.identity.agentWallet,
|
|
125
|
+
description: bundle.identity.description,
|
|
126
|
+
instructions: bundle.identity.instructions,
|
|
127
|
+
capabilities: bundle.identity.capabilities,
|
|
128
|
+
skills: bundle.identity.skills,
|
|
129
|
+
services: bundle.identity.services,
|
|
130
|
+
effectiveRuntime: bundle.effectiveRuntime,
|
|
131
|
+
enforce: bundle.enforce,
|
|
132
|
+
trust: bundle.trust,
|
|
133
|
+
mountedAt: bundle.mountedAt
|
|
134
|
+
},
|
|
135
|
+
null,
|
|
136
|
+
2
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* @param {string} cwd
|
|
142
|
+
*/
|
|
143
|
+
export function readMountManifest(cwd) {
|
|
144
|
+
const manifestPath = path.join(cwd, MOUNT_MANIFEST_RELATIVE);
|
|
145
|
+
if (!fs.existsSync(manifestPath)) return null;
|
|
146
|
+
try {
|
|
147
|
+
const parsed = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
|
|
148
|
+
return parsed?.schema === RUNTIME_MOUNT_SCHEMA ? parsed : null;
|
|
149
|
+
} catch {
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* @param {import('./runtime-mount.js').RuntimeBundle} bundle
|
|
156
|
+
* @param {string} cwd
|
|
157
|
+
*/
|
|
158
|
+
export function writeMountManifest(bundle, cwd) {
|
|
159
|
+
const dir = path.join(cwd, '.neus');
|
|
160
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
161
|
+
const manifestPath = path.join(dir, 'mount.json');
|
|
162
|
+
fs.writeFileSync(manifestPath, `${JSON.stringify(bundle, null, 2)}\n`, 'utf8');
|
|
163
|
+
return manifestPath;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* @param {'cursor' | 'claude' | 'codex'} flavor
|
|
168
|
+
* @param {import('./runtime-mount.js').RuntimeBundle} bundle
|
|
169
|
+
* @param {string} cwd
|
|
170
|
+
* @param {{ dryRun?: boolean }} [options]
|
|
171
|
+
*/
|
|
172
|
+
export function applyRuntimeBundle(flavor, bundle, cwd, options = {}) {
|
|
173
|
+
const dryRun = Boolean(options.dryRun);
|
|
174
|
+
const safeId = sanitizeAgentIdForFilename(bundle.identity.agentId);
|
|
175
|
+
const written = [];
|
|
176
|
+
|
|
177
|
+
const manifestPath = dryRun
|
|
178
|
+
? path.join(cwd, MOUNT_MANIFEST_RELATIVE)
|
|
179
|
+
: writeMountManifest(bundle, cwd);
|
|
180
|
+
written.push(manifestPath);
|
|
181
|
+
|
|
182
|
+
if (flavor === 'cursor') {
|
|
183
|
+
const rulesDir = path.join(cwd, '.cursor', 'rules');
|
|
184
|
+
const rulesPath = path.join(rulesDir, `neus-agent-${safeId}.mdc`);
|
|
185
|
+
if (!dryRun) {
|
|
186
|
+
fs.mkdirSync(rulesDir, { recursive: true });
|
|
187
|
+
fs.writeFileSync(rulesPath, bundleToCursorRules(bundle), 'utf8');
|
|
188
|
+
}
|
|
189
|
+
written.push(rulesPath);
|
|
190
|
+
return { flavor, written, primary: rulesPath, manifestPath };
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (flavor === 'claude') {
|
|
194
|
+
const claudePath = path.join(cwd, '.claude', 'NEUS_AGENT.md');
|
|
195
|
+
if (!dryRun) {
|
|
196
|
+
fs.mkdirSync(path.join(cwd, '.claude'), { recursive: true });
|
|
197
|
+
fs.writeFileSync(claudePath, bundleToClaudeMd(bundle), 'utf8');
|
|
198
|
+
}
|
|
199
|
+
written.push(claudePath);
|
|
200
|
+
return { flavor, written, primary: claudePath, manifestPath };
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (flavor === 'codex') {
|
|
204
|
+
const codexPath = path.join(cwd, '.neus', `codex-agent-${safeId}.json`);
|
|
205
|
+
if (!dryRun) {
|
|
206
|
+
fs.mkdirSync(path.join(cwd, '.neus'), { recursive: true });
|
|
207
|
+
fs.writeFileSync(codexPath, bundleToCodexJson(bundle), 'utf8');
|
|
208
|
+
}
|
|
209
|
+
written.push(codexPath);
|
|
210
|
+
return { flavor, written, primary: codexPath, manifestPath };
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
throw new Error(`Unsupported runtime adapter: ${flavor}`);
|
|
214
|
+
}
|