@storyclaw/talenthub 0.3.4 → 0.3.6
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/dist/cli.js +1 -0
- package/dist/commands/agent-install.d.ts +1 -0
- package/dist/commands/agent-install.js +18 -2
- package/dist/commands/agent-publish.js +3 -0
- package/dist/commands/login.js +16 -7
- package/dist/lib/auth.d.ts +6 -0
- package/dist/lib/auth.js +15 -0
- package/dist/lib/registry.d.ts +2 -2
- package/dist/lib/registry.js +8 -8
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -34,6 +34,7 @@ agent
|
|
|
34
34
|
.command("install <name>")
|
|
35
35
|
.description("Install an agent and its skills")
|
|
36
36
|
.option("-f, --force", "Overwrite existing agent", false)
|
|
37
|
+
.option("-t, --token <token>", "Authenticate with a th_* token for private agents")
|
|
37
38
|
.action(agentInstall);
|
|
38
39
|
agent
|
|
39
40
|
.command("update [name]")
|
|
@@ -1,19 +1,35 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import { verifyToken } from "../lib/auth.js";
|
|
3
4
|
import { installAllSkills } from "../lib/skills.js";
|
|
4
5
|
import { addOrUpdateAgent, findAgentEntry, readConfig, writeConfig } from "../lib/config.js";
|
|
5
6
|
import { fetchCatalog, fetchManifest } from "../lib/registry.js";
|
|
6
7
|
import { resolveWorkspaceDir } from "../lib/paths.js";
|
|
7
8
|
import { markInstalled } from "../lib/state.js";
|
|
8
9
|
export async function agentInstall(name, options) {
|
|
10
|
+
const token = options.token;
|
|
11
|
+
if (token) {
|
|
12
|
+
if (!token.startsWith("th_")) {
|
|
13
|
+
console.error("Invalid token format. Token must start with 'th_'.");
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
console.log("Verifying token...");
|
|
17
|
+
try {
|
|
18
|
+
await verifyToken(token);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
console.error("Token verification failed. Please check your token and try again.");
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
9
25
|
console.log(`Looking up agent "${name}"...`);
|
|
10
|
-
const catalog = await fetchCatalog();
|
|
26
|
+
const catalog = await fetchCatalog(token);
|
|
11
27
|
if (!catalog.agents[name]) {
|
|
12
28
|
const available = Object.keys(catalog.agents).join(", ");
|
|
13
29
|
console.error(`Agent "${name}" not found. Available: ${available}`);
|
|
14
30
|
process.exit(1);
|
|
15
31
|
}
|
|
16
|
-
const manifest = await fetchManifest(name);
|
|
32
|
+
const manifest = await fetchManifest(name, token);
|
|
17
33
|
console.log(`Found ${manifest.emoji} ${manifest.name} v${manifest.version} (${manifest.skills.length} skills)`);
|
|
18
34
|
const cfg = readConfig();
|
|
19
35
|
const existing = findAgentEntry(cfg, name);
|
|
@@ -103,6 +103,9 @@ export async function agentPublish(name, opts = {}) {
|
|
|
103
103
|
min_openclaw_version: manifest.minOpenClawVersion || null,
|
|
104
104
|
avatar_url: manifest.avatarUrl || null,
|
|
105
105
|
is_public: true,
|
|
106
|
+
...(manifest.i18n && typeof manifest.i18n === "object"
|
|
107
|
+
? { i18n: manifest.i18n }
|
|
108
|
+
: {}),
|
|
106
109
|
};
|
|
107
110
|
console.log(`\nPublishing ${payload.emoji || ""} ${payload.name} v${finalVersion}...`);
|
|
108
111
|
const base = getRegistryBaseUrl();
|
package/dist/commands/login.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { execSync } from "node:child_process";
|
|
2
|
-
import { readAuth, requestDeviceCode, pollForToken, exchangeToken, writeAuth } from "../lib/auth.js";
|
|
2
|
+
import { readAuth, requestDeviceCode, pollForToken, exchangeToken, verifyToken, writeAuth } from "../lib/auth.js";
|
|
3
3
|
function openUrl(url) {
|
|
4
4
|
try {
|
|
5
5
|
const cmd = process.platform === "darwin"
|
|
@@ -14,14 +14,23 @@ function openUrl(url) {
|
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
export async function login(options) {
|
|
17
|
-
// Direct token exchange: skip device-code flow entirely
|
|
18
17
|
if (options.token) {
|
|
19
|
-
console.log("Exchanging token...");
|
|
20
18
|
try {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
19
|
+
if (options.token.startsWith("th_")) {
|
|
20
|
+
console.log("Verifying token...");
|
|
21
|
+
const { user_id } = await verifyToken(options.token);
|
|
22
|
+
writeAuth({ token: options.token, user_id, expires_at: "" });
|
|
23
|
+
console.log(`✓ Logged in successfully.`);
|
|
24
|
+
console.log(` User ID: ${user_id}`);
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
// sc_token from web session — exchange for a CLI token
|
|
28
|
+
console.log("Exchanging token...");
|
|
29
|
+
const { access_token, user_id, expires_at } = await exchangeToken(options.token);
|
|
30
|
+
writeAuth({ token: access_token, user_id, expires_at });
|
|
31
|
+
console.log(`✓ Logged in successfully.`);
|
|
32
|
+
console.log(` User ID: ${user_id}`);
|
|
33
|
+
}
|
|
25
34
|
}
|
|
26
35
|
catch (err) {
|
|
27
36
|
console.error(`✗ Login failed: ${err instanceof Error ? err.message : err}`);
|
package/dist/lib/auth.d.ts
CHANGED
|
@@ -24,4 +24,10 @@ export type TokenResponse = {
|
|
|
24
24
|
* Exchange an sc_token (web session cookie) for a CLI-compatible th_* token.
|
|
25
25
|
*/
|
|
26
26
|
export declare function exchangeToken(scToken: string): Promise<TokenResponse>;
|
|
27
|
+
/**
|
|
28
|
+
* Verify a th_* CLI token against the registry and return the user_id.
|
|
29
|
+
*/
|
|
30
|
+
export declare function verifyToken(token: string): Promise<{
|
|
31
|
+
user_id: string;
|
|
32
|
+
}>;
|
|
27
33
|
export declare function pollForToken(deviceCode: string, interval: number, maxWaitMs: number): Promise<TokenResponse>;
|
package/dist/lib/auth.js
CHANGED
|
@@ -64,6 +64,21 @@ export async function exchangeToken(scToken) {
|
|
|
64
64
|
}
|
|
65
65
|
return res.json();
|
|
66
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* Verify a th_* CLI token against the registry and return the user_id.
|
|
69
|
+
*/
|
|
70
|
+
export async function verifyToken(token) {
|
|
71
|
+
const base = getRegistryBaseUrl();
|
|
72
|
+
const res = await fetchRetry(`${base}/api/talenthub/auth/me`, {
|
|
73
|
+
method: "GET",
|
|
74
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
75
|
+
});
|
|
76
|
+
if (!res.ok) {
|
|
77
|
+
const body = await res.json().catch(() => ({ error: "unknown" }));
|
|
78
|
+
throw new Error(`Token verification failed (${res.status}): ${body.error ?? "unknown error"}`);
|
|
79
|
+
}
|
|
80
|
+
return res.json();
|
|
81
|
+
}
|
|
67
82
|
export async function pollForToken(deviceCode, interval, maxWaitMs) {
|
|
68
83
|
const base = getRegistryBaseUrl();
|
|
69
84
|
const deadline = Date.now() + maxWaitMs;
|
package/dist/lib/registry.d.ts
CHANGED
|
@@ -27,5 +27,5 @@ export type AgentManifest = {
|
|
|
27
27
|
avatarUrl: string | null;
|
|
28
28
|
files: Record<string, string>;
|
|
29
29
|
};
|
|
30
|
-
export declare function fetchCatalog(): Promise<Catalog>;
|
|
31
|
-
export declare function fetchManifest(agentId: string): Promise<AgentManifest>;
|
|
30
|
+
export declare function fetchCatalog(token?: string): Promise<Catalog>;
|
|
31
|
+
export declare function fetchManifest(agentId: string, token?: string): Promise<AgentManifest>;
|
package/dist/lib/registry.js
CHANGED
|
@@ -4,24 +4,24 @@ function apiUrl(path) {
|
|
|
4
4
|
const base = getRegistryBaseUrl().replace(/\/$/, "");
|
|
5
5
|
return `${base}/api/talenthub/registry${path}`;
|
|
6
6
|
}
|
|
7
|
-
function authHeaders() {
|
|
8
|
-
const
|
|
9
|
-
if (
|
|
10
|
-
return { Authorization: `Bearer ${
|
|
7
|
+
function authHeaders(token) {
|
|
8
|
+
const t = token ?? readAuth()?.token;
|
|
9
|
+
if (t) {
|
|
10
|
+
return { Authorization: `Bearer ${t}` };
|
|
11
11
|
}
|
|
12
12
|
return {};
|
|
13
13
|
}
|
|
14
|
-
export async function fetchCatalog() {
|
|
14
|
+
export async function fetchCatalog(token) {
|
|
15
15
|
const url = apiUrl("/catalog");
|
|
16
|
-
const res = await fetchRetry(url, { headers: authHeaders() });
|
|
16
|
+
const res = await fetchRetry(url, { headers: authHeaders(token) });
|
|
17
17
|
if (!res.ok) {
|
|
18
18
|
throw new Error(`Failed to fetch catalog: ${res.status} ${res.statusText}`);
|
|
19
19
|
}
|
|
20
20
|
return res.json();
|
|
21
21
|
}
|
|
22
|
-
export async function fetchManifest(agentId) {
|
|
22
|
+
export async function fetchManifest(agentId, token) {
|
|
23
23
|
const url = apiUrl(`/${agentId}`);
|
|
24
|
-
const res = await fetchRetry(url, { headers: authHeaders() });
|
|
24
|
+
const res = await fetchRetry(url, { headers: authHeaders(token) });
|
|
25
25
|
if (!res.ok) {
|
|
26
26
|
throw new Error(`Agent "${agentId}" not found in registry (${res.status})`);
|
|
27
27
|
}
|