@neta-art/cohub-cli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -0
- package/bin/cohub.js +2 -0
- package/dist/auth.d.ts +9 -0
- package/dist/auth.js +35 -0
- package/dist/client.d.ts +2 -0
- package/dist/client.js +7 -0
- package/dist/commands/auth.d.ts +2 -0
- package/dist/commands/auth.js +51 -0
- package/dist/commands/channels.d.ts +2 -0
- package/dist/commands/channels.js +84 -0
- package/dist/commands/cron-jobs.d.ts +2 -0
- package/dist/commands/cron-jobs.js +136 -0
- package/dist/commands/models.d.ts +2 -0
- package/dist/commands/models.js +34 -0
- package/dist/commands/prompts.d.ts +2 -0
- package/dist/commands/prompts.js +33 -0
- package/dist/commands/session-access.d.ts +2 -0
- package/dist/commands/session-access.js +72 -0
- package/dist/commands/spaces.d.ts +2 -0
- package/dist/commands/spaces.js +675 -0
- package/dist/commands/tasks.d.ts +2 -0
- package/dist/commands/tasks.js +104 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +37 -0
- package/dist/output.d.ts +14 -0
- package/dist/output.js +91 -0
- package/package.json +29 -0
package/README.md
ADDED
package/bin/cohub.js
ADDED
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve auth token with priority:
|
|
3
|
+
* 1. COHUB_EXECUTION_TOKEN environment variable
|
|
4
|
+
* 2. ~/.config/cohub/token file
|
|
5
|
+
*/
|
|
6
|
+
export declare function resolveToken(): string | null;
|
|
7
|
+
export declare function saveToken(token: string): void;
|
|
8
|
+
export declare function clearToken(): void;
|
|
9
|
+
export declare function tokenSource(): "env" | "file" | null;
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { readFileSync, existsSync, mkdirSync, writeFileSync, rmSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
const TOKEN_DIR = join(homedir(), ".config", "cohub");
|
|
5
|
+
const TOKEN_PATH = join(TOKEN_DIR, "token");
|
|
6
|
+
/**
|
|
7
|
+
* Resolve auth token with priority:
|
|
8
|
+
* 1. COHUB_EXECUTION_TOKEN environment variable
|
|
9
|
+
* 2. ~/.config/cohub/token file
|
|
10
|
+
*/
|
|
11
|
+
export function resolveToken() {
|
|
12
|
+
if (process.env.COHUB_EXECUTION_TOKEN) {
|
|
13
|
+
return process.env.COHUB_EXECUTION_TOKEN.trim();
|
|
14
|
+
}
|
|
15
|
+
if (existsSync(TOKEN_PATH)) {
|
|
16
|
+
return readFileSync(TOKEN_PATH, "utf-8").trim();
|
|
17
|
+
}
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
export function saveToken(token) {
|
|
21
|
+
mkdirSync(TOKEN_DIR, { recursive: true });
|
|
22
|
+
writeFileSync(TOKEN_PATH, token.trim());
|
|
23
|
+
}
|
|
24
|
+
export function clearToken() {
|
|
25
|
+
if (existsSync(TOKEN_PATH)) {
|
|
26
|
+
rmSync(TOKEN_PATH);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export function tokenSource() {
|
|
30
|
+
if (process.env.COHUB_EXECUTION_TOKEN)
|
|
31
|
+
return "env";
|
|
32
|
+
if (existsSync(TOKEN_PATH))
|
|
33
|
+
return "file";
|
|
34
|
+
return null;
|
|
35
|
+
}
|
package/dist/client.d.ts
ADDED
package/dist/client.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { resolveToken, saveToken, clearToken, tokenSource } from "../auth.js";
|
|
2
|
+
import { createClient } from "../client.js";
|
|
3
|
+
import { table, json as outJson, ok, error, spinner, handleHttp } from "../output.js";
|
|
4
|
+
export function registerAuth(program) {
|
|
5
|
+
const auth = program.command("auth").description("Authentication management");
|
|
6
|
+
auth
|
|
7
|
+
.command("login <token>")
|
|
8
|
+
.description("Set auth token")
|
|
9
|
+
.action((token) => {
|
|
10
|
+
saveToken(token);
|
|
11
|
+
ok("Token saved to ~/.config/cohub/token");
|
|
12
|
+
});
|
|
13
|
+
auth
|
|
14
|
+
.command("whoami")
|
|
15
|
+
.description("Show current user info")
|
|
16
|
+
.option("--json", "Output as JSON")
|
|
17
|
+
.action(async (opts) => {
|
|
18
|
+
const token = resolveToken();
|
|
19
|
+
if (!token)
|
|
20
|
+
return error("Not authenticated", "Run 'cohub auth login <token>'");
|
|
21
|
+
const client = createClient(token);
|
|
22
|
+
const sp = spinner();
|
|
23
|
+
sp.start("Fetching user info");
|
|
24
|
+
try {
|
|
25
|
+
const user = await client.user.getMe();
|
|
26
|
+
sp.stop("Done");
|
|
27
|
+
if (opts.json)
|
|
28
|
+
return outJson(user);
|
|
29
|
+
const src = tokenSource();
|
|
30
|
+
const u = user;
|
|
31
|
+
console.log(` Auth source: ${src}\n`);
|
|
32
|
+
table([u], [
|
|
33
|
+
{ key: "id", label: "ID" },
|
|
34
|
+
{ key: "name", label: "Name" },
|
|
35
|
+
{ key: "email", label: "Email" },
|
|
36
|
+
{ key: "created_at", label: "Created" },
|
|
37
|
+
]);
|
|
38
|
+
}
|
|
39
|
+
catch (e) {
|
|
40
|
+
sp.stop("Failed");
|
|
41
|
+
handleHttp(e);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
auth
|
|
45
|
+
.command("logout")
|
|
46
|
+
.description("Clear stored token")
|
|
47
|
+
.action(() => {
|
|
48
|
+
clearToken();
|
|
49
|
+
ok("Token cleared");
|
|
50
|
+
});
|
|
51
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { resolveToken } from "../auth.js";
|
|
2
|
+
import { createClient } from "../client.js";
|
|
3
|
+
import { table, json as outJson, ok, error, handleHttp } from "../output.js";
|
|
4
|
+
export function registerChannels(program) {
|
|
5
|
+
const cmd = program.command("channels").description("Channel management");
|
|
6
|
+
cmd
|
|
7
|
+
.command("ls")
|
|
8
|
+
.alias("list")
|
|
9
|
+
.description("List channels")
|
|
10
|
+
.option("--json", "Output as JSON")
|
|
11
|
+
.action(async (opts) => {
|
|
12
|
+
const token = resolveToken();
|
|
13
|
+
if (!token)
|
|
14
|
+
return error("Not authenticated", "Run 'cohub auth login <token>'");
|
|
15
|
+
const client = createClient(token);
|
|
16
|
+
try {
|
|
17
|
+
const items = await client.channels.list();
|
|
18
|
+
if (opts.json)
|
|
19
|
+
return outJson(items);
|
|
20
|
+
if (items.length === 0)
|
|
21
|
+
return console.log(" (empty)");
|
|
22
|
+
table(items, [
|
|
23
|
+
{ key: "id", label: "ID" },
|
|
24
|
+
{ key: "provider", label: "Provider" },
|
|
25
|
+
{ key: "name", label: "Name" },
|
|
26
|
+
{ key: "status", label: "Status" },
|
|
27
|
+
]);
|
|
28
|
+
}
|
|
29
|
+
catch (e) {
|
|
30
|
+
handleHttp(e);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
cmd
|
|
34
|
+
.command("create")
|
|
35
|
+
.description("Create a channel")
|
|
36
|
+
.requiredOption("-p, --provider <provider>", "Channel provider")
|
|
37
|
+
.requiredOption("-n, --name <name>", "Channel name")
|
|
38
|
+
.option("--credentials <json>", "Credentials as JSON string")
|
|
39
|
+
.option("--json", "Output as JSON")
|
|
40
|
+
.action(async (opts) => {
|
|
41
|
+
const token = resolveToken();
|
|
42
|
+
if (!token)
|
|
43
|
+
return error("Not authenticated");
|
|
44
|
+
let credentials = {};
|
|
45
|
+
if (opts.credentials) {
|
|
46
|
+
try {
|
|
47
|
+
credentials = JSON.parse(opts.credentials);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return error("Invalid JSON", "--credentials must be valid JSON");
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const client = createClient(token);
|
|
54
|
+
try {
|
|
55
|
+
const result = await client.channels.create({
|
|
56
|
+
provider: opts.provider,
|
|
57
|
+
name: opts.name,
|
|
58
|
+
credentials,
|
|
59
|
+
});
|
|
60
|
+
if (opts.json)
|
|
61
|
+
return outJson(result);
|
|
62
|
+
ok("Channel created");
|
|
63
|
+
}
|
|
64
|
+
catch (e) {
|
|
65
|
+
handleHttp(e);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
cmd
|
|
69
|
+
.command("delete <id>")
|
|
70
|
+
.description("Delete a channel")
|
|
71
|
+
.action(async (id) => {
|
|
72
|
+
const token = resolveToken();
|
|
73
|
+
if (!token)
|
|
74
|
+
return error("Not authenticated");
|
|
75
|
+
const client = createClient(token);
|
|
76
|
+
try {
|
|
77
|
+
await client.channels.delete(id);
|
|
78
|
+
ok(`Channel deleted: ${id}`);
|
|
79
|
+
}
|
|
80
|
+
catch (e) {
|
|
81
|
+
handleHttp(e);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { resolveToken } from "../auth.js";
|
|
2
|
+
import { createClient } from "../client.js";
|
|
3
|
+
import { table, json as outJson, ok, error, handleHttp } from "../output.js";
|
|
4
|
+
export function registerCronJobs(program) {
|
|
5
|
+
const cmd = program.command("cron-jobs").description("Cron job management");
|
|
6
|
+
cmd
|
|
7
|
+
.command("ls [spaceId]")
|
|
8
|
+
.alias("list")
|
|
9
|
+
.description("List cron jobs")
|
|
10
|
+
.option("--json", "Output as JSON")
|
|
11
|
+
.action(async (spaceId, opts) => {
|
|
12
|
+
const token = resolveToken();
|
|
13
|
+
if (!token)
|
|
14
|
+
return error("Not authenticated", "Run 'cohub auth login <token>'");
|
|
15
|
+
const client = createClient(token);
|
|
16
|
+
try {
|
|
17
|
+
const result = await client.cronJobs.list(spaceId);
|
|
18
|
+
if (opts.json)
|
|
19
|
+
return outJson(result);
|
|
20
|
+
if (result.jobs.length === 0)
|
|
21
|
+
return console.log(" (empty)");
|
|
22
|
+
table(result.jobs, [
|
|
23
|
+
{ key: "id", label: "ID" },
|
|
24
|
+
{ key: "title", label: "Title" },
|
|
25
|
+
{ key: "cronExpression", label: "Schedule" },
|
|
26
|
+
{ key: "enabled", label: "Enabled" },
|
|
27
|
+
{ key: "spaceId", label: "Space" },
|
|
28
|
+
]);
|
|
29
|
+
}
|
|
30
|
+
catch (e) {
|
|
31
|
+
handleHttp(e);
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
cmd
|
|
35
|
+
.command("create")
|
|
36
|
+
.description("Create a cron job")
|
|
37
|
+
.requiredOption("-t, --title <title>", "Job title")
|
|
38
|
+
.requiredOption("--task-type <type>", "Task type")
|
|
39
|
+
.requiredOption("--cron <expression>", "Cron expression")
|
|
40
|
+
.option("--payload <json>", "Payload as JSON")
|
|
41
|
+
.option("--timezone <tz>", "Timezone", "UTC")
|
|
42
|
+
.option("--space <id>", "Space ID")
|
|
43
|
+
.option("--session <id>", "Session ID")
|
|
44
|
+
.option("--json", "Output as JSON")
|
|
45
|
+
.action(async (opts) => {
|
|
46
|
+
const token = resolveToken();
|
|
47
|
+
if (!token)
|
|
48
|
+
return error("Not authenticated");
|
|
49
|
+
let payload = {};
|
|
50
|
+
if (opts.payload) {
|
|
51
|
+
try {
|
|
52
|
+
payload = JSON.parse(opts.payload);
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return error("Invalid JSON", "--payload must be valid JSON");
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
const client = createClient(token);
|
|
59
|
+
try {
|
|
60
|
+
const result = await client.cronJobs.create({
|
|
61
|
+
title: opts.title,
|
|
62
|
+
taskType: opts.taskType,
|
|
63
|
+
cronExpression: opts.cron,
|
|
64
|
+
payload,
|
|
65
|
+
timezone: opts.timezone,
|
|
66
|
+
spaceId: opts.space,
|
|
67
|
+
sessionId: opts.session,
|
|
68
|
+
});
|
|
69
|
+
if (opts.json)
|
|
70
|
+
return outJson(result);
|
|
71
|
+
ok(`Cron job created: ${result.id}`);
|
|
72
|
+
}
|
|
73
|
+
catch (e) {
|
|
74
|
+
handleHttp(e);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
cmd
|
|
78
|
+
.command("delete <id>")
|
|
79
|
+
.description("Delete a cron job")
|
|
80
|
+
.action(async (id) => {
|
|
81
|
+
const token = resolveToken();
|
|
82
|
+
if (!token)
|
|
83
|
+
return error("Not authenticated");
|
|
84
|
+
const client = createClient(token);
|
|
85
|
+
try {
|
|
86
|
+
await client.cronJobs.delete(id);
|
|
87
|
+
ok(`Cron job deleted: ${id}`);
|
|
88
|
+
}
|
|
89
|
+
catch (e) {
|
|
90
|
+
handleHttp(e);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
cmd
|
|
94
|
+
.command("toggle <id> <on|off>")
|
|
95
|
+
.description("Enable or disable a cron job")
|
|
96
|
+
.action(async (id, state) => {
|
|
97
|
+
const token = resolveToken();
|
|
98
|
+
if (!token)
|
|
99
|
+
return error("Not authenticated");
|
|
100
|
+
const enabled = state === "on";
|
|
101
|
+
const client = createClient(token);
|
|
102
|
+
try {
|
|
103
|
+
await client.cronJobs.toggle(id, enabled);
|
|
104
|
+
ok(`Cron job ${enabled ? "enabled" : "disabled"}: ${id}`);
|
|
105
|
+
}
|
|
106
|
+
catch (e) {
|
|
107
|
+
handleHttp(e);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
cmd
|
|
111
|
+
.command("runs <id>")
|
|
112
|
+
.description("List cron job runs")
|
|
113
|
+
.option("--json", "Output as JSON")
|
|
114
|
+
.action(async (id, opts) => {
|
|
115
|
+
const token = resolveToken();
|
|
116
|
+
if (!token)
|
|
117
|
+
return error("Not authenticated");
|
|
118
|
+
const client = createClient(token);
|
|
119
|
+
try {
|
|
120
|
+
const result = await client.cronJobs.runs(id);
|
|
121
|
+
if (opts.json)
|
|
122
|
+
return outJson(result);
|
|
123
|
+
if (result.runs.length === 0)
|
|
124
|
+
return console.log(" (empty)");
|
|
125
|
+
table(result.runs, [
|
|
126
|
+
{ key: "id", label: "ID" },
|
|
127
|
+
{ key: "status", label: "Status" },
|
|
128
|
+
{ key: "startedAt", label: "Started" },
|
|
129
|
+
{ key: "finishedAt", label: "Finished" },
|
|
130
|
+
]);
|
|
131
|
+
}
|
|
132
|
+
catch (e) {
|
|
133
|
+
handleHttp(e);
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { resolveToken } from "../auth.js";
|
|
2
|
+
import { createClient } from "../client.js";
|
|
3
|
+
import { table, json as outJson, error, handleHttp } from "../output.js";
|
|
4
|
+
export function registerModels(program) {
|
|
5
|
+
const cmd = program.command("models").description("Model management");
|
|
6
|
+
cmd
|
|
7
|
+
.command("ls")
|
|
8
|
+
.alias("list")
|
|
9
|
+
.description("List available models")
|
|
10
|
+
.option("--json", "Output as JSON")
|
|
11
|
+
.action(async (opts) => {
|
|
12
|
+
const token = resolveToken();
|
|
13
|
+
if (!token)
|
|
14
|
+
return error("Not authenticated", "Run 'cohub auth login <token>'");
|
|
15
|
+
const client = createClient(token);
|
|
16
|
+
try {
|
|
17
|
+
const catalog = await client.models.list();
|
|
18
|
+
if (opts.json)
|
|
19
|
+
return outJson(catalog);
|
|
20
|
+
// catalog is Record<provider, ModelCatalogEntry[]>
|
|
21
|
+
for (const [provider, entries] of Object.entries(catalog)) {
|
|
22
|
+
console.log(`\n ${provider}`);
|
|
23
|
+
console.log(" " + "─".repeat(provider.length));
|
|
24
|
+
table(entries, [
|
|
25
|
+
{ key: "id", label: "ID" },
|
|
26
|
+
{ key: "provider", label: "Provider" },
|
|
27
|
+
]);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
catch (e) {
|
|
31
|
+
handleHttp(e);
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { resolveToken } from "../auth.js";
|
|
2
|
+
import { createClient } from "../client.js";
|
|
3
|
+
import { table, json as outJson, error, handleHttp } from "../output.js";
|
|
4
|
+
export function registerPrompts(program) {
|
|
5
|
+
const cmd = program.command("prompts").description("Prompt template management");
|
|
6
|
+
cmd
|
|
7
|
+
.command("ls")
|
|
8
|
+
.alias("list")
|
|
9
|
+
.description("List prompt templates")
|
|
10
|
+
.option("--space <id>", "Filter by space")
|
|
11
|
+
.option("--json", "Output as JSON")
|
|
12
|
+
.action(async (opts) => {
|
|
13
|
+
const token = resolveToken();
|
|
14
|
+
if (!token)
|
|
15
|
+
return error("Not authenticated", "Run 'cohub auth login <token>'");
|
|
16
|
+
const client = createClient(token);
|
|
17
|
+
try {
|
|
18
|
+
const result = await client.prompts.list({ spaceId: opts.space });
|
|
19
|
+
if (opts.json)
|
|
20
|
+
return outJson(result);
|
|
21
|
+
if (result.prompts.length === 0)
|
|
22
|
+
return console.log(" (empty)");
|
|
23
|
+
table(result.prompts, [
|
|
24
|
+
{ key: "name", label: "Name" },
|
|
25
|
+
{ key: "category", label: "Category" },
|
|
26
|
+
{ key: "description", label: "Description" },
|
|
27
|
+
]);
|
|
28
|
+
}
|
|
29
|
+
catch (e) {
|
|
30
|
+
handleHttp(e);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { resolveToken } from "../auth.js";
|
|
2
|
+
import { createClient } from "../client.js";
|
|
3
|
+
import { table, json as outJson, ok, error, handleHttp } from "../output.js";
|
|
4
|
+
export function registerSessionAccess(program) {
|
|
5
|
+
const cmd = program
|
|
6
|
+
.command("session-access")
|
|
7
|
+
.description("Session-level access control");
|
|
8
|
+
cmd
|
|
9
|
+
.command("get <id>")
|
|
10
|
+
.description("Get session access policy")
|
|
11
|
+
.option("--json", "Output as JSON")
|
|
12
|
+
.action(async (id, opts) => {
|
|
13
|
+
const token = resolveToken();
|
|
14
|
+
if (!token)
|
|
15
|
+
return error("Not authenticated", "Run 'cohub auth login <token>'");
|
|
16
|
+
const client = createClient(token);
|
|
17
|
+
try {
|
|
18
|
+
const policy = await client.sessionAccess.get(id);
|
|
19
|
+
if (opts.json)
|
|
20
|
+
return outJson(policy);
|
|
21
|
+
table([policy], [
|
|
22
|
+
{ key: "signed_in_user", label: "Signed-in" },
|
|
23
|
+
{ key: "anonymous_user", label: "Anonymous" },
|
|
24
|
+
]);
|
|
25
|
+
}
|
|
26
|
+
catch (e) {
|
|
27
|
+
handleHttp(e);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
cmd
|
|
31
|
+
.command("set <id>")
|
|
32
|
+
.description("Set session anonymous access")
|
|
33
|
+
.option("--anonymous <role>", "Anonymous role (host|builder|guest|null)")
|
|
34
|
+
.option("--json", "Output as JSON")
|
|
35
|
+
.action(async (id, opts) => {
|
|
36
|
+
const token = resolveToken();
|
|
37
|
+
if (!token)
|
|
38
|
+
return error("Not authenticated");
|
|
39
|
+
const client = createClient(token);
|
|
40
|
+
try {
|
|
41
|
+
const policy = await client.sessionAccess.set(id, {
|
|
42
|
+
anonymous_user: (opts.anonymous ?? null),
|
|
43
|
+
});
|
|
44
|
+
if (opts.json)
|
|
45
|
+
return outJson(policy);
|
|
46
|
+
ok("Session access updated");
|
|
47
|
+
table([policy], [
|
|
48
|
+
{ key: "signed_in_user", label: "Signed-in" },
|
|
49
|
+
{ key: "anonymous_user", label: "Anonymous" },
|
|
50
|
+
]);
|
|
51
|
+
}
|
|
52
|
+
catch (e) {
|
|
53
|
+
handleHttp(e);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
cmd
|
|
57
|
+
.command("remove <id>")
|
|
58
|
+
.description("Remove session access override")
|
|
59
|
+
.action(async (id) => {
|
|
60
|
+
const token = resolveToken();
|
|
61
|
+
if (!token)
|
|
62
|
+
return error("Not authenticated");
|
|
63
|
+
const client = createClient(token);
|
|
64
|
+
try {
|
|
65
|
+
await client.sessionAccess.remove(id);
|
|
66
|
+
ok(`Session access override removed: ${id}`);
|
|
67
|
+
}
|
|
68
|
+
catch (e) {
|
|
69
|
+
handleHttp(e);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
}
|