@numa-tech/numa 1.19.0 → 1.20.1
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 +57 -3
- package/dist/ai-registry/bridge.js +3 -2
- package/dist/ai-registry/bridge.js.map +1 -1
- package/dist/ai-registry/client.d.ts +8 -1
- package/dist/ai-registry/client.js +11 -1
- package/dist/ai-registry/client.js.map +1 -1
- package/dist/ai-registry/commands.d.ts +3 -0
- package/dist/ai-registry/commands.js +48 -36
- package/dist/ai-registry/commands.js.map +1 -1
- package/dist/ai-registry/mcp-management.d.ts +2 -0
- package/dist/ai-registry/mcp-management.js +74 -0
- package/dist/ai-registry/mcp-management.js.map +1 -0
- package/dist/ai-registry/mcp-runtime-commands.d.ts +15 -0
- package/dist/ai-registry/mcp-runtime-commands.js +101 -0
- package/dist/ai-registry/mcp-runtime-commands.js.map +1 -0
- package/dist/ai-registry/mcp-runtime.d.ts +37 -0
- package/dist/ai-registry/mcp-runtime.js +134 -0
- package/dist/ai-registry/mcp-runtime.js.map +1 -0
- package/dist/ai-registry/mcp-stdio.d.ts +2 -0
- package/dist/ai-registry/mcp-stdio.js +18 -0
- package/dist/ai-registry/mcp-stdio.js.map +1 -0
- package/dist/authorization/application-client.d.ts +1271 -0
- package/dist/authorization/application-client.js +391 -0
- package/dist/authorization/application-client.js.map +1 -0
- package/dist/authorization/application-commands.d.ts +15 -0
- package/dist/authorization/application-commands.js +240 -0
- package/dist/authorization/application-commands.js.map +1 -0
- package/dist/authorization/application-schemas.d.ts +731 -0
- package/dist/authorization/application-schemas.js +521 -0
- package/dist/authorization/application-schemas.js.map +1 -0
- package/dist/authorization/{client.d.ts → bootstrap-client.d.ts} +5 -26
- package/dist/authorization/{client.js → bootstrap-client.js} +4 -27
- package/dist/authorization/bootstrap-client.js.map +1 -0
- package/dist/authorization/commands.d.ts +6 -21
- package/dist/authorization/commands.js +8 -130
- package/dist/authorization/commands.js.map +1 -1
- package/dist/authorization/enrollment-client.d.ts +40 -0
- package/dist/authorization/enrollment-client.js +56 -0
- package/dist/authorization/enrollment-client.js.map +1 -0
- package/dist/authorization/enrollment-commands.d.ts +5 -0
- package/dist/authorization/enrollment-commands.js +30 -0
- package/dist/authorization/enrollment-commands.js.map +1 -0
- package/dist/authorization/enrollment.d.ts +2 -2
- package/dist/authorization/enrollment.js +2 -2
- package/dist/authorization/enrollment.js.map +1 -1
- package/dist/authorization/schemas.d.ts +0 -90
- package/dist/authorization/schemas.js +0 -48
- package/dist/authorization/schemas.js.map +1 -1
- package/dist/backend.d.ts +1 -0
- package/dist/backend.js +4 -1
- package/dist/backend.js.map +1 -1
- package/dist/business-issuer.d.ts +4 -0
- package/dist/business-issuer.js +30 -0
- package/dist/business-issuer.js.map +1 -0
- package/dist/cli.js +61 -30
- package/dist/cli.js.map +1 -1
- package/dist/cloud/bootstrap.js +1 -1
- package/dist/cloud/bootstrap.js.map +1 -1
- package/dist/command-catalog.js +11 -36
- package/dist/command-catalog.js.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.js +15 -6
- package/dist/config.js.map +1 -1
- package/dist/login-configuration.d.ts +8 -0
- package/dist/login-configuration.js +17 -0
- package/dist/login-configuration.js.map +1 -0
- package/dist/login-recovery.d.ts +2 -0
- package/dist/login-recovery.js +15 -0
- package/dist/login-recovery.js.map +1 -0
- package/dist/mcp/commands.js +12 -2
- package/dist/mcp/commands.js.map +1 -1
- package/dist/mcp-gateway/commands.d.ts +2 -0
- package/dist/mcp-gateway/commands.js +11 -0
- package/dist/mcp-gateway/commands.js.map +1 -1
- package/dist/oss/commands.d.ts +2 -1
- package/dist/oss/commands.js +55 -37
- package/dist/oss/commands.js.map +1 -1
- package/dist/oss/file-operations.d.ts +57 -0
- package/dist/oss/file-operations.js +269 -0
- package/dist/oss/file-operations.js.map +1 -0
- package/dist/oss/local-picker.d.ts +2 -0
- package/dist/oss/local-picker.js +6 -0
- package/dist/oss/local-picker.js.map +1 -1
- package/dist/oss/tools.js +1 -1
- package/dist/oss/tools.js.map +1 -1
- package/dist/oss/transfer-queue.js +1 -1
- package/dist/oss/transfer-queue.js.map +1 -1
- package/dist/oss/transfers.d.ts +7 -0
- package/dist/oss/transfers.js +87 -0
- package/dist/oss/transfers.js.map +1 -1
- package/dist/oss/web-page.js +365 -30
- package/dist/oss/web-page.js.map +1 -1
- package/dist/oss/web-service.d.ts +45 -0
- package/dist/oss/web-service.js +107 -0
- package/dist/oss/web-service.js.map +1 -0
- package/dist/oss/web.d.ts +10 -0
- package/dist/oss/web.js +117 -15
- package/dist/oss/web.js.map +1 -1
- package/dist/platform-profile.d.ts +22 -2
- package/dist/platform-profile.js +67 -6
- package/dist/platform-profile.js.map +1 -1
- package/docs/application-default-groups.md +73 -0
- package/examples/cloud-bootstrap/README.md +1 -1
- package/examples/mcp/README.md +108 -0
- package/examples/mcp/management-smoke.py +154 -0
- package/examples/mcp/runtime-smoke.mjs +187 -0
- package/examples/mcp/server.json +17 -0
- package/examples/oss/README.md +78 -0
- package/examples/oss/__pycache__/roundtrip.cpython-314.pyc +0 -0
- package/examples/oss/__pycache__/test_roundtrip.cpython-314.pyc +0 -0
- package/examples/oss/roundtrip.py +84 -0
- package/examples/oss/test_roundtrip.py +66 -0
- package/package.json +6 -5
- package/dist/authorization/client.js.map +0 -1
- package/dist/authorization/group-client.d.ts +0 -169
- package/dist/authorization/group-client.js +0 -129
- package/dist/authorization/group-client.js.map +0 -1
- package/dist/authorization/group-commands.d.ts +0 -25
- package/dist/authorization/group-commands.js +0 -155
- package/dist/authorization/group-commands.js.map +0 -1
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Local MVP acceptance. Identity/profile/cache are supplied through the normal Numa environment.
|
|
3
|
+
// No credentials are printed or written by this runner.
|
|
4
|
+
import assert from "node:assert/strict";
|
|
5
|
+
import { spawn } from "node:child_process";
|
|
6
|
+
import { parseArgs } from "node:util";
|
|
7
|
+
import { readFile } from "node:fs/promises";
|
|
8
|
+
import { resolve } from "node:path";
|
|
9
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
10
|
+
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
11
|
+
|
|
12
|
+
const { values } = parseArgs({ options: {
|
|
13
|
+
cli: { type: "string", default: "dist/cli.js" },
|
|
14
|
+
namespace: { type: "string", default: "mcp-lab-a" },
|
|
15
|
+
instance: { type: "string" },
|
|
16
|
+
server: { type: "string", default: "catalog-mcp" },
|
|
17
|
+
tool: { type: "string", default: "search_products" },
|
|
18
|
+
"denied-tool": { type: "string", default: "update_product" },
|
|
19
|
+
"error-tool": { type: "string", default: "search_failure" },
|
|
20
|
+
"reader-env-file": { type: "string" },
|
|
21
|
+
"writer-env-file": { type: "string" },
|
|
22
|
+
"denied-env-file": { type: "string" },
|
|
23
|
+
"other-namespace": { type: "string", default: "mcp-lab-b" },
|
|
24
|
+
extended: { type: "boolean", default: false }
|
|
25
|
+
} });
|
|
26
|
+
async function identityEnvironment(path) {
|
|
27
|
+
const provided = path ? JSON.parse(await readFile(path, "utf8")) : {};
|
|
28
|
+
if (!provided || typeof provided !== "object" || Array.isArray(provided)
|
|
29
|
+
|| Object.values(provided).some(value => typeof value !== "string")) throw new Error("Identity environment must be a string map.");
|
|
30
|
+
const environment = { ...process.env, ...provided };
|
|
31
|
+
const base = environment.NUMA_BACKEND_BASE_URL;
|
|
32
|
+
const parsed = base ? new URL(base) : undefined;
|
|
33
|
+
if (!parsed || !["http:", "https:"].includes(parsed.protocol) || parsed.username || parsed.password || parsed.search || parsed.hash
|
|
34
|
+
|| !["localhost", "127.0.0.1", "[::1]"].includes(parsed.hostname)) {
|
|
35
|
+
throw new Error("This runner requires NUMA_BACKEND_BASE_URL to explicitly select the local MVP.");
|
|
36
|
+
}
|
|
37
|
+
return environment;
|
|
38
|
+
}
|
|
39
|
+
const readerEnvironment = await identityEnvironment(values["reader-env-file"]);
|
|
40
|
+
const writerEnvironment = values["writer-env-file"] ? await identityEnvironment(values["writer-env-file"]) : undefined;
|
|
41
|
+
const deniedEnvironment = values["denied-env-file"] ? await identityEnvironment(values["denied-env-file"]) : undefined;
|
|
42
|
+
const cli = resolve(values.cli);
|
|
43
|
+
const namespaceOptions = (name = values.namespace) => ["--namespace", name, ...(values.instance ? ["--instance", values.instance] : [])];
|
|
44
|
+
const checks = [];
|
|
45
|
+
let lastOperation;
|
|
46
|
+
async function invoke(args, environment = readerEnvironment, targetNamespace = values.namespace) {
|
|
47
|
+
const child = spawn(process.execPath, [cli, ...args, ...namespaceOptions(targetNamespace), "--json"], {
|
|
48
|
+
env: environment, stdio: ["ignore", "pipe", "pipe"]
|
|
49
|
+
});
|
|
50
|
+
let stdout = "";
|
|
51
|
+
child.stdout.on("data", chunk => { stdout += chunk; });
|
|
52
|
+
child.stderr.resume();
|
|
53
|
+
const timer = setTimeout(() => child.kill("SIGTERM"), 45_000);
|
|
54
|
+
const code = await new Promise((resolveCode, reject) => { child.once("error", reject); child.once("close", resolveCode); });
|
|
55
|
+
clearTimeout(timer);
|
|
56
|
+
let body;
|
|
57
|
+
try { body = JSON.parse(stdout); } catch { throw new Error("CLI did not return valid JSON; inspect local diagnostics."); }
|
|
58
|
+
lastOperation = { command: args.slice(0, 4).join(" "), namespace: targetNamespace, exitCode: code,
|
|
59
|
+
ok: body.ok, errorCode: body.error?.code, httpStatus: body.error?.details?.status ?? body.error?.status };
|
|
60
|
+
return { code, body };
|
|
61
|
+
}
|
|
62
|
+
async function viaProxy(operation, environment = readerEnvironment, server = values.server, targetNamespace = values.namespace) {
|
|
63
|
+
lastOperation = { command: "mcp proxy", server, namespace: targetNamespace };
|
|
64
|
+
const transport = new StdioClientTransport({ command: process.execPath,
|
|
65
|
+
args: [cli, "mcp", "proxy", server, ...namespaceOptions(targetNamespace)],
|
|
66
|
+
env: Object.fromEntries(Object.entries(environment).filter(([, value]) => value !== undefined)), stderr: "pipe" });
|
|
67
|
+
transport.stderr?.resume();
|
|
68
|
+
const client = new Client({ name: "numa-local-mvp-acceptance", version: "1" }, { capabilities: {} });
|
|
69
|
+
try { await client.connect(transport, { timeout: 30_000 }); return await operation(client); }
|
|
70
|
+
finally { await client.close(); }
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
const tools = await invoke(["mcp", "tools", values.server]);
|
|
74
|
+
assert.equal(tools.code, 0);
|
|
75
|
+
assert.equal(tools.body.ok, true);
|
|
76
|
+
const names = tools.body.tools.map(tool => tool.name);
|
|
77
|
+
assert(names.includes(values.tool));
|
|
78
|
+
assert(!names.includes(values["denied-tool"]));
|
|
79
|
+
checks.push("CLI tools uses gateway-filtered list");
|
|
80
|
+
|
|
81
|
+
const call = await invoke(["mcp", "call", values.server, values.tool, "--args", "{}"]);
|
|
82
|
+
assert.equal(call.code, 0);
|
|
83
|
+
assert.equal(call.body.ok, true);
|
|
84
|
+
assert(call.body.result.content?.length > 0);
|
|
85
|
+
checks.push("CLI tool call completes through gateway and upstream");
|
|
86
|
+
|
|
87
|
+
const forbidden = await invoke(["mcp", "call", values.server, values["denied-tool"], "--args", "{}"]);
|
|
88
|
+
assert.notEqual(forbidden.code, 0);
|
|
89
|
+
assert.equal(forbidden.body.ok, false);
|
|
90
|
+
assert.equal(forbidden.body.error.code, "ai_registry_mcp_forbidden");
|
|
91
|
+
checks.push("CLI forbidden tool is denied by gateway");
|
|
92
|
+
|
|
93
|
+
const error = await invoke(["mcp", "call", values.server, values["error-tool"], "--args", "{}"]);
|
|
94
|
+
assert.notEqual(error.code, 0);
|
|
95
|
+
assert.equal(error.body.ok, false);
|
|
96
|
+
assert.equal(error.body.result.isError, true);
|
|
97
|
+
checks.push("CLI preserves executed tool isError and exits nonzero");
|
|
98
|
+
|
|
99
|
+
await viaProxy(async client => {
|
|
100
|
+
assert(client.getServerCapabilities()?.tools);
|
|
101
|
+
const listed = await client.listTools();
|
|
102
|
+
const proxyNames = listed.tools.map(tool => tool.name);
|
|
103
|
+
assert(proxyNames.includes(values.tool));
|
|
104
|
+
assert(!proxyNames.includes(values["denied-tool"]));
|
|
105
|
+
checks.push("stdio proxy negotiates real server and retains filtered tools");
|
|
106
|
+
const result = await client.callTool({ name: values.tool, arguments: {} });
|
|
107
|
+
assert(!result.isError);
|
|
108
|
+
assert(result.content?.length > 0);
|
|
109
|
+
checks.push("stdio MCP client invokes real remote tool via CLI proxy");
|
|
110
|
+
const failed = await client.callTool({ name: values["error-tool"], arguments: {} });
|
|
111
|
+
assert.equal(failed.isError, true);
|
|
112
|
+
checks.push("stdio proxy preserves protocol tool errors");
|
|
113
|
+
});
|
|
114
|
+
let denied = false; let initialized = false;
|
|
115
|
+
try {
|
|
116
|
+
await viaProxy(client => { initialized = true; return client.callTool({ name: values["denied-tool"], arguments: {} }, undefined, { timeout: 15_000 }); });
|
|
117
|
+
} catch { denied = true; }
|
|
118
|
+
assert(initialized && denied);
|
|
119
|
+
checks.push("stdio proxy cannot bypass gateway tool authorization");
|
|
120
|
+
if (values.extended) {
|
|
121
|
+
for (const [server, tool, args, expected] of [
|
|
122
|
+
["notes-mcp", "list_notes", {}, "credentialVerified"],
|
|
123
|
+
["stdio-mcp", "calculate_total", { unit_price: 12.5, quantity: 2 }, '"total":25']
|
|
124
|
+
]) {
|
|
125
|
+
const call = await invoke(["mcp", "call", server, tool, "--args", JSON.stringify(args)]);
|
|
126
|
+
assert.equal(call.code, 0);
|
|
127
|
+
assert.equal(call.body.ok, true);
|
|
128
|
+
const serialized = JSON.stringify(call.body.result).replaceAll(/\s/gu, "").replaceAll('\\"', '"');
|
|
129
|
+
assert(serialized.includes(expected));
|
|
130
|
+
checks.push(`CLI reaches ${server} real upstream adapter`);
|
|
131
|
+
await viaProxy(async client => {
|
|
132
|
+
const tools = await client.listTools();
|
|
133
|
+
assert(tools.tools.some(item => item.name === tool));
|
|
134
|
+
const result = await client.callTool({ name: tool, arguments: args });
|
|
135
|
+
assert(!result.isError);
|
|
136
|
+
const serialized = JSON.stringify(result).replaceAll(/\s/gu, "").replaceAll('\\"', '"');
|
|
137
|
+
assert(serialized.includes(expected));
|
|
138
|
+
}, readerEnvironment, server);
|
|
139
|
+
checks.push(`local stdio proxy reaches ${server} real upstream adapter`);
|
|
140
|
+
}
|
|
141
|
+
await viaProxy(async client => {
|
|
142
|
+
const first = await client.listTools();
|
|
143
|
+
const second = await client.callTool({ name: values.tool, arguments: {} });
|
|
144
|
+
assert(first.tools.some(tool => tool.name === values.tool));
|
|
145
|
+
assert(!second.isError);
|
|
146
|
+
}, readerEnvironment, "session-mcp");
|
|
147
|
+
checks.push("stdio proxy retains stateful upstream session across requests");
|
|
148
|
+
}
|
|
149
|
+
if (writerEnvironment) {
|
|
150
|
+
const write = await invoke(["mcp", "call", values.server, values["denied-tool"], "--args", '{"name":"numa-local-acceptance"}'], writerEnvironment);
|
|
151
|
+
assert.equal(write.code, 0);
|
|
152
|
+
assert.equal(write.body.ok, true);
|
|
153
|
+
checks.push("writer CLI executes authorized fixture write");
|
|
154
|
+
await viaProxy(async client => {
|
|
155
|
+
const tools = await client.listTools();
|
|
156
|
+
assert(tools.tools.some(tool => tool.name === values["denied-tool"]));
|
|
157
|
+
const written = await client.callTool({ name: values["denied-tool"], arguments: { name: "numa-stdio-acceptance" } });
|
|
158
|
+
assert(!written.isError);
|
|
159
|
+
}, writerEnvironment);
|
|
160
|
+
checks.push("writer stdio proxy executes authorized fixture write");
|
|
161
|
+
const unclassified = await invoke(["mcp", "call", values.server, "unclassified_operation", "--args", "{}"], writerEnvironment);
|
|
162
|
+
assert.notEqual(unclassified.code, 0);
|
|
163
|
+
assert.equal(unclassified.body.error.code, "ai_registry_mcp_forbidden");
|
|
164
|
+
checks.push("writer still cannot invoke unclassified tool");
|
|
165
|
+
const readOther = await invoke(["mcp", "call", values.server, values.tool, "--args", "{}"], readerEnvironment, values["other-namespace"]);
|
|
166
|
+
assert.notEqual(readOther.code, 0);
|
|
167
|
+
assert.equal(readOther.body.ok, false);
|
|
168
|
+
assert.match(readOther.body.error.code, /forbidden/u);
|
|
169
|
+
checks.push("reader cannot cross into another namespace");
|
|
170
|
+
const writerOther = await invoke(["mcp", "call", values.server, values.tool, "--args", "{}"], writerEnvironment, values["other-namespace"]);
|
|
171
|
+
assert.equal(writerOther.code, 0);
|
|
172
|
+
assert.equal(writerOther.body.ok, true);
|
|
173
|
+
checks.push("explicitly granted writer can call another namespace");
|
|
174
|
+
}
|
|
175
|
+
if (deniedEnvironment) {
|
|
176
|
+
const denied = await invoke(["mcp", "tools", values.server], deniedEnvironment);
|
|
177
|
+
assert.notEqual(denied.code, 0);
|
|
178
|
+
assert.equal(denied.body.ok, false);
|
|
179
|
+
assert(denied.body.error.details?.status === 403 || /forbidden/u.test(denied.body.error.code));
|
|
180
|
+
checks.push("ungranted identity cannot discover callable server");
|
|
181
|
+
}
|
|
182
|
+
process.stdout.write(JSON.stringify({ ok: true, checks }, null, 2) + "\n");
|
|
183
|
+
} catch {
|
|
184
|
+
process.stderr.write(JSON.stringify({ ok: false, completedChecks: checks, lastOperation,
|
|
185
|
+
message: "MCP runtime acceptance failed; credential-bearing responses were withheld." }, null, 2) + "\n");
|
|
186
|
+
process.exitCode = 1;
|
|
187
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"serverSpecification": {
|
|
3
|
+
"name": "cli-local-example",
|
|
4
|
+
"description": "Local CLI registration example; gateway access requires a separate binding and authorization.",
|
|
5
|
+
"protocol": "mcp-streamable",
|
|
6
|
+
"frontProtocol": "mcp-streamable",
|
|
7
|
+
"enabled": false,
|
|
8
|
+
"versionDetail": { "version": "1.0.0" },
|
|
9
|
+
"remoteServerConfig": { "exportPath": "/mcp" }
|
|
10
|
+
},
|
|
11
|
+
"toolSpecification": {
|
|
12
|
+
"tools": [{ "name": "echo", "description": "Example metadata only", "inputSchema": { "type": "object", "properties": {} } }],
|
|
13
|
+
"toolsMeta": {}
|
|
14
|
+
},
|
|
15
|
+
"endpointSpecification": { "type": "DIRECT", "data": { "address": "127.0.0.1", "port": "8080" } },
|
|
16
|
+
"latest": true
|
|
17
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# OSS CLI list / write / read example
|
|
2
|
+
|
|
3
|
+
Use the local build only. Nothing here publishes to npm or changes a global installation.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
cd /Users/changhz/source/numa-business-issuers
|
|
7
|
+
npm run build
|
|
8
|
+
# A local binary still reads the global configuration unless this is set.
|
|
9
|
+
export NUMA_CONFIG_DIR="$PWD/tmp/issuer-mvp-cli"
|
|
10
|
+
export NUMA_PROFILE_URL='http://localhost:28080/public/v1/client-configurations/issuer-mvp'
|
|
11
|
+
node dist/cli.js config --set profileUrl="$NUMA_PROFILE_URL" profileId=issuer-mvp apiBaseUrl=http://localhost:28080 checkUpdates=false
|
|
12
|
+
node dist/cli.js login --no-console --no-config
|
|
13
|
+
node dist/cli.js oss grants --json
|
|
14
|
+
# Replace 123 with the exact ACTIVE, synced/verified read/write grant shown above.
|
|
15
|
+
python3 examples/oss/roundtrip.py --grant-id 123
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
For interactive commands, `./scripts/mvp-cli.sh login --issuer cluster-b
|
|
19
|
+
--no-console --no-config` and `./scripts/mvp-cli.sh oss grants --issuer cluster-b`
|
|
20
|
+
set up the same isolated local directory automatically. They never change
|
|
21
|
+
`~/.config/numa`. Merely setting NUMA_PROFILE_URL with your global configuration
|
|
22
|
+
can still leave its pinned profileId pointing at numa-realm.
|
|
23
|
+
|
|
24
|
+
The local profile must first be created and published in DevOps. Its platform
|
|
25
|
+
issuer is fixed; `login` uses the business default. To explicitly select another
|
|
26
|
+
business issuer, use the same selector for login and the example:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
node dist/cli.js login --issuer cluster-b --no-console --no-config
|
|
30
|
+
node dist/cli.js oss grants --issuer cluster-b --json
|
|
31
|
+
python3 examples/oss/roundtrip.py --issuer cluster-b --grant-id 123
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
`--cli /absolute/path/dist/cli.js` selects another local build. The script never
|
|
35
|
+
runs npx, downloads packages, chooses a grant automatically or changes permissions.
|
|
36
|
+
It queries Grant/STS APIs through Numa, uses the STS-backed OSS client to list up
|
|
37
|
+
to ten objects, uploads a small unique object, checks metadata, downloads it and
|
|
38
|
+
compares bytes. Both read and write permission are required. `--prefix` must be
|
|
39
|
+
inside the selected grant's scope. No existing object is overwritten. The remote
|
|
40
|
+
test object is retained and its key is printed; temporary local files are removed.
|
|
41
|
+
Credentials are handled internally by the CLI, never printed by the script.
|
|
42
|
+
|
|
43
|
+
Machine identities use the selected issuer too. Configure
|
|
44
|
+
`NUMA_KEYCLOAK_AUTH_MODE=client_credentials`, the dedicated
|
|
45
|
+
`NUMA_KEYCLOAK_CLIENT_ID`, and `NUMA_KEYCLOAK_CLIENT_SECRET_FILE` (owner-only file).
|
|
46
|
+
Do not run browser login in machine mode. The backend still requires the canonical
|
|
47
|
+
OSS role and a grant for this exact issuer/subject.
|
|
48
|
+
|
|
49
|
+
For the local acceptance run, the published `issuer-mvp` Profile defaults to
|
|
50
|
+
cluster-a. Its existing fixture grants are intentionally unpublished/read-only
|
|
51
|
+
and cannot run the write example. Select a separately verified read/write grant
|
|
52
|
+
before executing the example against real OSS.
|
|
53
|
+
|
|
54
|
+
`oss grants` lists authorization records, including records whose cloud policy is
|
|
55
|
+
not yet synced/verified. Its count is not a count of grants ready for object access.
|
|
56
|
+
The normal output shows each grant ID, bucket/prefix, permission and sync state.
|
|
57
|
+
For example, the local MVP fixture Grant 2 has `cloudPolicySynced=false` and
|
|
58
|
+
`permissionLevel=READ_ONLY`: it cannot run this roundtrip. The unified API returns
|
|
59
|
+
`actions` and `effect`; the CLI authorizes operations from those fields, never
|
|
60
|
+
from the template label. `oss ls` only requires Allow + `oss:ListObjects`; stat/get
|
|
61
|
+
require `oss:GetObject`, and upload requires `oss:PutObject`. The roundtrip requires
|
|
62
|
+
all three Actions. System ADMIN uses `oss:*`, which is broader than selecting all
|
|
63
|
+
currently editable object Actions.
|
|
64
|
+
The roundtrip reports all status/permission blockers before requesting STS or
|
|
65
|
+
performing any object operations; it never publishes policies or expands access.
|
|
66
|
+
|
|
67
|
+
If `oss ls` fails with `OSS_STS_BROKER_NOT_CONFIGURED` (HTTP 503), the platform
|
|
68
|
+
account lacks an active STS broker RAM-user AK. A synced OSS policy alone does
|
|
69
|
+
not make STS ready. A platform administrator must configure the dedicated broker
|
|
70
|
+
identity and its managed AK, permission to assume the selected RAM Role, and the
|
|
71
|
+
Role's trust policy. The default management AK is separate from the broker AK.
|
|
72
|
+
`OSS_STS_ASSUME_ROLE_FAILED` means the STS call failed after broker selection;
|
|
73
|
+
check broker credentials, trust, permissions and connectivity. Neither error is
|
|
74
|
+
fixed by logging in with another issuer or changing the grant's read/write level.
|
|
75
|
+
|
|
76
|
+
The imported OSS development branch had a hard-coded machine test bucket. This
|
|
77
|
+
build uses server-authorized Grant/STS scope for both user and machine identities;
|
|
78
|
+
SDK prefix and permission checks remain enabled.
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Exercise Grant/STS APIs and OSS list/write/read using an unpublished local Numa build."""
|
|
3
|
+
import argparse
|
|
4
|
+
import hashlib
|
|
5
|
+
import json
|
|
6
|
+
import pathlib
|
|
7
|
+
import subprocess
|
|
8
|
+
import tempfile
|
|
9
|
+
import uuid
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def main():
|
|
13
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
14
|
+
parser.add_argument('--cli', type=pathlib.Path, default=pathlib.Path(__file__).resolve().parents[2] / 'dist/cli.js', help='Local dist/cli.js; never downloads or installs a CLI')
|
|
15
|
+
parser.add_argument('--issuer', help='Business issuer code from the selected Profile; omit to use its default')
|
|
16
|
+
parser.add_argument('--grant-id', required=True, type=int, help='An exact grant ID from numa oss grants')
|
|
17
|
+
parser.add_argument('--prefix', help='Optional test prefix inside the grant scope')
|
|
18
|
+
args = parser.parse_args()
|
|
19
|
+
if not args.cli.is_file():
|
|
20
|
+
parser.error('Build the local CLI first (npm run build), or pass --cli /absolute/path/dist/cli.js')
|
|
21
|
+
command = ['node', str(args.cli.resolve())]
|
|
22
|
+
if args.issuer:
|
|
23
|
+
command += ['--issuer', args.issuer]
|
|
24
|
+
|
|
25
|
+
def cli(*arguments):
|
|
26
|
+
result = subprocess.run(command + list(arguments) + ['--json'], capture_output=True, text=True)
|
|
27
|
+
try:
|
|
28
|
+
value = json.loads(result.stdout)
|
|
29
|
+
except ValueError:
|
|
30
|
+
raise RuntimeError('CLI did not return JSON; check the local build and Profile configuration') from None
|
|
31
|
+
if result.returncode or not value.get('ok'):
|
|
32
|
+
# Do not echo arbitrary stdout, stderr, API responses or credentials.
|
|
33
|
+
error = value.get('error', {})
|
|
34
|
+
code = error.get('code', 'command_failed') if isinstance(error, dict) else 'command_failed'
|
|
35
|
+
raise RuntimeError(f'CLI command {arguments[0]} {arguments[1]} failed: {code}')
|
|
36
|
+
return value
|
|
37
|
+
|
|
38
|
+
grants = cli('oss', 'grants')['grants']
|
|
39
|
+
grant = next((g for g in grants if g['grantId'] == args.grant_id), None)
|
|
40
|
+
if not grant:
|
|
41
|
+
parser.error(f'Grant {args.grant_id} 未出现在当前身份的授权列表中;请使用相同 --issuer 执行 oss grants 查看授权 ID')
|
|
42
|
+
blockers = []
|
|
43
|
+
if grant['status'] != 'ACTIVE':
|
|
44
|
+
blockers.append('授权未启用(status=' + json.dumps(grant['status'], ensure_ascii=False) + ')')
|
|
45
|
+
if not grant['cloudPolicySynced']:
|
|
46
|
+
blockers.append('云端策略未同步/验证(cloudPolicySynced=false)')
|
|
47
|
+
required_actions = {'oss:ListObjects', 'oss:GetObject', 'oss:PutObject'}
|
|
48
|
+
actions = grant.get('actions')
|
|
49
|
+
permitted = grant.get('effect') == 'Allow' and isinstance(actions, list) and (required_actions.issubset(set(actions)) or 'oss:*' in actions)
|
|
50
|
+
if not permitted:
|
|
51
|
+
blockers.append('读写示例需要 Allow 且同时包含 ListObjects、GetObject、PutObject,当前 actions=' + json.dumps(actions, ensure_ascii=False))
|
|
52
|
+
if blockers:
|
|
53
|
+
parser.error(f'Grant {args.grant_id} 无法运行读写示例:' + ';'.join(blockers) + '。尚未申请 STS 或执行 OSS 对象操作。请选择已同步/验证且具有读写权限的授权。')
|
|
54
|
+
scope = grant['scopeType']
|
|
55
|
+
allowed = grant.get('objectPrefix') or ''
|
|
56
|
+
if scope not in ('BUCKET', 'PREFIX') or scope == 'PREFIX' and not allowed:
|
|
57
|
+
parser.error('Grant scope is incomplete')
|
|
58
|
+
prefix = args.prefix if args.prefix is not None else allowed
|
|
59
|
+
if scope == 'PREFIX' and not prefix.startswith(allowed):
|
|
60
|
+
parser.error('--prefix must be inside the granted objectPrefix')
|
|
61
|
+
if prefix and not prefix.endswith('/'):
|
|
62
|
+
prefix += '/'
|
|
63
|
+
key = prefix + 'numa-cli-example-' + uuid.uuid4().hex + '.txt'
|
|
64
|
+
grant_id = str(args.grant_id)
|
|
65
|
+
print(json.dumps({'bucket': grant['bucketName'], 'object_key': key, 'issuer': args.issuer or 'profile-default'}, ensure_ascii=False))
|
|
66
|
+
cli('oss', 'ls', grant_id, prefix, '--limit', '10')
|
|
67
|
+
with tempfile.TemporaryDirectory(prefix='numa-oss-example-') as directory:
|
|
68
|
+
source = pathlib.Path(directory) / 'source.txt'
|
|
69
|
+
downloaded = pathlib.Path(directory) / 'downloaded.txt'
|
|
70
|
+
source.write_text('Numa OSS CLI roundtrip\n' + str(uuid.uuid4()) + '\n', encoding='utf-8')
|
|
71
|
+
cli('oss', 'put', grant_id, key, str(source)) # No --overwrite.
|
|
72
|
+
cli('oss', 'stat', grant_id, key)
|
|
73
|
+
cli('oss', 'get', grant_id, key, '--output', str(downloaded))
|
|
74
|
+
if source.read_bytes() != downloaded.read_bytes():
|
|
75
|
+
raise RuntimeError('Downloaded contents do not match the uploaded file')
|
|
76
|
+
print(json.dumps({'ok': True, 'verified': ['list', 'write', 'read'], 'sha256': hashlib.sha256(downloaded.read_bytes()).hexdigest(), 'retained_object_key': key}))
|
|
77
|
+
# Deliberately retain the unique remote object. There is no implicit delete.
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
if __name__ == '__main__':
|
|
81
|
+
try:
|
|
82
|
+
main()
|
|
83
|
+
except (RuntimeError, OSError) as error:
|
|
84
|
+
raise SystemExit(str(error)) from None
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""Contract tests for the runnable example; all CLI/cloud responses are simulated."""
|
|
2
|
+
import contextlib
|
|
3
|
+
import importlib.util
|
|
4
|
+
import io
|
|
5
|
+
import json
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
import subprocess
|
|
8
|
+
import sys
|
|
9
|
+
import tempfile
|
|
10
|
+
import unittest
|
|
11
|
+
from unittest.mock import patch
|
|
12
|
+
|
|
13
|
+
spec=importlib.util.spec_from_file_location('roundtrip',Path(__file__).with_name('roundtrip.py'))
|
|
14
|
+
module=importlib.util.module_from_spec(spec);spec.loader.exec_module(module)
|
|
15
|
+
|
|
16
|
+
class RoundtripTest(unittest.TestCase):
|
|
17
|
+
def exercise(self,permission='READ_WRITE',prefix=None,corrupt=False,synced=True,status='ACTIVE',missing=False,blocked_message=None):
|
|
18
|
+
calls=[];storage={}
|
|
19
|
+
with tempfile.TemporaryDirectory() as directory:
|
|
20
|
+
entry=Path(directory)/'cli.js';entry.touch()
|
|
21
|
+
argv=['roundtrip','--cli',str(entry),'--grant-id','7','--issuer','cluster-b']
|
|
22
|
+
if prefix is not None:argv += ['--prefix',prefix]
|
|
23
|
+
def run(command,**kwargs):
|
|
24
|
+
self.assertEqual(command[2:4],['--issuer','cluster-b'])
|
|
25
|
+
args=command[4:-1];calls.append(args)
|
|
26
|
+
self.assertEqual(args[0],'oss');self.assertNotIn('--overwrite',args)
|
|
27
|
+
if args[1]=='grants': payload={'grants':[] if missing else [{'grantId':7,'status':status,'cloudPolicySynced':synced,'permissionLevel':permission,'effect':'Allow','actions':['oss:ListObjects','oss:GetObject']+([] if permission=='READ_ONLY' else ['oss:PutObject']),'scopeType':'PREFIX','objectPrefix':'tenant/kb/','bucketName':'example-bucket'}]}
|
|
28
|
+
elif args[1]=='put': storage[args[3]]=Path(args[4]).read_bytes();payload={}
|
|
29
|
+
elif args[1]=='get': Path(args[5]).write_bytes(b'wrong' if corrupt else storage[args[3]]);payload={}
|
|
30
|
+
elif args[1] in ('ls','stat'): payload={}
|
|
31
|
+
else:raise AssertionError('Unexpected object mutation: '+args[1])
|
|
32
|
+
return subprocess.CompletedProcess(command,0,json.dumps({'ok':True,**payload}),'')
|
|
33
|
+
output=io.StringIO();errors=io.StringIO()
|
|
34
|
+
with patch.object(sys,'argv',argv),patch.object(module.subprocess,'run',run),contextlib.redirect_stdout(output),contextlib.redirect_stderr(errors):
|
|
35
|
+
if blocked_message is None:
|
|
36
|
+
module.main()
|
|
37
|
+
else:
|
|
38
|
+
with self.assertRaises(SystemExit) as error:module.main()
|
|
39
|
+
self.assertEqual(error.exception.code,2)
|
|
40
|
+
self.assertRegex(errors.getvalue(),blocked_message)
|
|
41
|
+
self.assertEqual([c[1] for c in calls],['grants'])
|
|
42
|
+
self.assertEqual(storage,{})
|
|
43
|
+
return calls,storage,output.getvalue()
|
|
44
|
+
|
|
45
|
+
def test_roundtrip_selects_one_issuer_and_keeps_unique_object(self):
|
|
46
|
+
calls,storage,output=self.exercise()
|
|
47
|
+
self.assertEqual([c[1] for c in calls],['grants','ls','put','stat','get'])
|
|
48
|
+
key=next(iter(storage));self.assertTrue(key.startswith('tenant/kb/numa-cli-example-'))
|
|
49
|
+
self.assertEqual(json.loads(output.splitlines()[-1])['retained_object_key'],key)
|
|
50
|
+
|
|
51
|
+
def test_refuses_readonly_and_out_of_scope_before_write(self):
|
|
52
|
+
with self.assertRaises(SystemExit):self.exercise(permission='READ_ONLY')
|
|
53
|
+
with self.assertRaises(SystemExit):self.exercise(prefix='another-tenant/')
|
|
54
|
+
|
|
55
|
+
def test_detects_corrupted_download(self):
|
|
56
|
+
with self.assertRaisesRegex(RuntimeError,'do not match'):self.exercise(corrupt=True)
|
|
57
|
+
|
|
58
|
+
def test_reports_all_fixture_blockers_without_requesting_sts_or_objects(self):
|
|
59
|
+
self.exercise(permission='READ_ONLY',synced=False,blocked_message=r'Grant 7.*cloudPolicySynced=false.*actions=.*oss:GetObject.*尚未申请 STS')
|
|
60
|
+
|
|
61
|
+
def test_distinguishes_missing_inactive_and_synced_readonly_grants(self):
|
|
62
|
+
self.exercise(missing=True,blocked_message=r'Grant 7 未出现在当前身份')
|
|
63
|
+
self.exercise(status='DISABLED',blocked_message=r'授权未启用.*DISABLED')
|
|
64
|
+
self.exercise(permission='READ_ONLY',blocked_message=r'需要 Allow.*ListObjects.*GetObject.*PutObject.*actions=')
|
|
65
|
+
|
|
66
|
+
if __name__=='__main__':unittest.main()
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@numa-tech/numa",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.20.1",
|
|
4
4
|
"description": "Cross-platform CLI for the Numa internal developer platform with Keycloak authentication and MCP support.",
|
|
5
5
|
"author": "numa-tech",
|
|
6
6
|
"keywords": [
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
"dist",
|
|
23
23
|
"README.md",
|
|
24
24
|
"docs/wecom-messaging.md",
|
|
25
|
+
"docs/application-default-groups.md",
|
|
25
26
|
"docs/module-maintenance-and-skills-updates.md",
|
|
26
27
|
"examples",
|
|
27
28
|
"skills",
|
|
@@ -35,9 +36,9 @@
|
|
|
35
36
|
"root:typecheck": "tsc --noEmit",
|
|
36
37
|
"test": "turbo run test root:test",
|
|
37
38
|
"dev:oss-web": "tsx src/cli.ts oss web",
|
|
38
|
-
"test:oss-web": "node --import tsx --test src/oss/web.test.ts src/oss/web-session.test.ts src/oss/web-transfers.test.ts src/oss/web-command.test.ts src/oss/local-picker.test.ts src/oss/transfer-paths.test.ts src/oss/transfer-worker.test.ts src/oss/transfer-queue.test.ts src/oss/web-page.test.ts",
|
|
39
|
+
"test:oss-web": "node --import tsx --test src/oss/web.test.ts src/oss/web-session.test.ts src/oss/web-transfers.test.ts src/oss/web-command.test.ts src/oss/local-picker.test.ts src/oss/transfer-paths.test.ts src/oss/transfer-worker.test.ts src/oss/transfer-queue.test.ts src/oss/web-page.test.ts src/oss/file-operations.test.ts",
|
|
39
40
|
"test:oss-auth-code": "node scripts/test-oss-auth-code.mjs",
|
|
40
|
-
"root:test": "node --import tsx --test --test-concurrency=4 src/mcp-gateway/profile.test.ts src/mcp-gateway/runtime.test.ts src/mcp-gateway/install.test.ts src/branding.test.ts src/app-config.test.ts src/platform-profile.test.ts src/identity.test.ts src/backend.test.ts src/oauth.test.ts src/web-console.test.ts src/cli-options.test.ts src/mail/client.test.ts src/wecom/client.test.ts src/wecom/commands.test.ts src/wecom/tools.test.ts src/ai-registry/client.test.ts src/ai-registry/bootstrap.test.ts src/ai-registry/install-defaults.test.ts src/ai-registry/workspace.test.ts src/ai-registry/namespace.test.ts src/ai-registry/sync.test.ts src/ai-registry/bridge.test.ts src/ai-registry/skill-installer.test.ts src/ai-registry/skill-uninstaller.test.ts src/ai-registry/skill-dependencies.test.ts src/ai-registry/updates.test.ts src/maintenance/scheduler.test.ts src/maintenance/codex.test.ts src/ai-registry/mcp-installer.test.ts src/media/client.test.ts src/media/commands.test.ts src/media/transfers.test.ts src/oss/client.test.ts src/oss/commands.test.ts src/oss/auth-code.test.ts src/oss/clipboard.test.ts src/oss/web.test.ts src/oss/web-session.test.ts src/oss/web-transfers.test.ts src/oss/web-command.test.ts src/oss/local-picker.test.ts src/oss/transfer-paths.test.ts src/oss/transfer-worker.test.ts src/oss/transfer-queue.test.ts src/oss/web-page.test.ts src/oss/bootstrap.test.ts src/oss/transfers.test.ts src/oss/search.test.ts src/oss/tools.test.ts src/mcp/install.test.ts src/mcp/catalog.test.ts src/interactive/wizard.test.ts src/pipeline/client.test.ts src/pipeline/commands.test.ts src/gitops/client.test.ts src/gitops/commands.test.ts src/repositories/client.test.ts src/repositories/commands.test.ts src/publications/scanner.test.ts src/publications/client.test.ts src/publications/commands.test.ts src/jenkins-jobs/client.test.ts src/jenkins-jobs/commands.test.ts src/clusters/client.test.ts src/clusters/commands.test.ts src/clusters/kubeconfig-discovery.test.ts src/teams/client.test.ts src/teams/commands.test.ts src/authorization/client.test.ts src/authorization/commands.test.ts src/authorization/access-request-client.test.ts src/authorization/access-request-commands.test.ts src/application-candidates/client.test.ts src/application-candidates/commands.test.ts src/application-onboarding/client.test.ts src/application-onboarding/commands.test.ts src/application-onboarding/tui.test.ts src/chatgpt-desktop.test.ts src/codex-integration.test.ts scripts/release-all.test.mjs src/authorization/enrollment.test.ts src/authorization/
|
|
41
|
+
"root:test": "node --import tsx --test --test-concurrency=4 src/mcp-gateway/profile.test.ts src/mcp-gateway/runtime.test.ts src/mcp-gateway/install.test.ts src/branding.test.ts src/app-config.test.ts src/platform-profile.test.ts src/identity.test.ts src/backend.test.ts src/oauth.test.ts src/web-console.test.ts src/cli-options.test.ts src/mail/client.test.ts src/wecom/client.test.ts src/wecom/commands.test.ts src/wecom/tools.test.ts src/ai-registry/client.test.ts src/ai-registry/bootstrap.test.ts src/ai-registry/install-defaults.test.ts src/ai-registry/workspace.test.ts src/ai-registry/namespace.test.ts src/ai-registry/sync.test.ts src/ai-registry/bridge.test.ts src/ai-registry/skill-installer.test.ts src/ai-registry/skill-uninstaller.test.ts src/ai-registry/skill-dependencies.test.ts src/ai-registry/updates.test.ts src/maintenance/scheduler.test.ts src/maintenance/codex.test.ts src/ai-registry/mcp-installer.test.ts src/media/client.test.ts src/media/commands.test.ts src/media/transfers.test.ts src/oss/client.test.ts src/oss/commands.test.ts src/oss/auth-code.test.ts src/oss/clipboard.test.ts src/oss/web.test.ts src/oss/web-session.test.ts src/oss/web-transfers.test.ts src/oss/web-command.test.ts src/oss/local-picker.test.ts src/oss/transfer-paths.test.ts src/oss/transfer-worker.test.ts src/oss/transfer-queue.test.ts src/oss/web-page.test.ts src/oss/file-operations.test.ts src/oss/bootstrap.test.ts src/oss/transfers.test.ts src/oss/search.test.ts src/oss/tools.test.ts src/mcp/install.test.ts src/mcp/catalog.test.ts src/interactive/wizard.test.ts src/pipeline/client.test.ts src/pipeline/commands.test.ts src/gitops/client.test.ts src/gitops/commands.test.ts src/repositories/client.test.ts src/repositories/commands.test.ts src/publications/scanner.test.ts src/publications/client.test.ts src/publications/commands.test.ts src/jenkins-jobs/client.test.ts src/jenkins-jobs/commands.test.ts src/clusters/client.test.ts src/clusters/commands.test.ts src/clusters/kubeconfig-discovery.test.ts src/teams/client.test.ts src/teams/commands.test.ts src/authorization/bootstrap-client.test.ts src/authorization/commands.test.ts src/authorization/access-request-client.test.ts src/authorization/access-request-commands.test.ts src/application-candidates/client.test.ts src/application-candidates/commands.test.ts src/application-onboarding/client.test.ts src/application-onboarding/commands.test.ts src/application-onboarding/tui.test.ts src/chatgpt-desktop.test.ts src/codex-integration.test.ts scripts/release-all.test.mjs src/authorization/enrollment.test.ts src/authorization/application-commands.test.ts src/authorization/application-client.test.ts src/authorization/application-schemas.test.ts src/authorization/enrollment-client.test.ts src/notion/client.test.ts src/notion/commands.test.ts src/notion/tools.test.ts src/notion/machine-cli.test.ts src/cloud/accounts.test.ts src/cloud/bootstrap.test.ts src/cloud/business-bootstrap.test.ts src/cloud/maintenance.test.ts src/cloud/wizard.test.ts src/cloud/oss-bootstrap.test.ts src/business-issuer.test.ts src/login-configuration.test.ts src/login-recovery.test.ts src/ai-registry/mcp-management.test.ts src/ai-registry/mcp-runtime.test.ts src/ai-registry/mcp-stdio.test.ts",
|
|
41
42
|
"pack:check": "turbo run pack:check root:pack:check",
|
|
42
43
|
"root:pack:check": "node scripts/check-root-package.mjs",
|
|
43
44
|
"boundaries": "node scripts/check-workspace-boundaries.mjs",
|
|
@@ -60,8 +61,8 @@
|
|
|
60
61
|
"dependencies": {
|
|
61
62
|
"@clack/prompts": "^1.7.0",
|
|
62
63
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
63
|
-
"@numa-tech/cli-auth": "1.
|
|
64
|
-
"@tokensrc/codex": "1.
|
|
64
|
+
"@numa-tech/cli-auth": "1.20.1",
|
|
65
|
+
"@tokensrc/codex": "1.20.1",
|
|
65
66
|
"ali-oss": "^6.23.0",
|
|
66
67
|
"commander": "^14.0.3",
|
|
67
68
|
"ink": "^6.8.0",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/authorization/client.ts"],"names":[],"mappings":"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"}
|