@delega-dev/cli 1.0.5 → 1.0.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/README.md +27 -4
- package/SECURITY.md +20 -0
- package/dist/api.d.ts +6 -0
- package/dist/api.js +17 -9
- package/dist/commands/agents.js +3 -3
- package/dist/commands/login.js +50 -11
- package/dist/commands/stats.js +1 -1
- package/dist/commands/tasks.js +6 -6
- package/dist/commands/whoami.js +27 -20
- package/dist/config.d.ts +1 -0
- package/dist/config.js +27 -4
- package/dist/secret-store.d.ts +3 -0
- package/dist/secret-store.js +128 -0
- package/package.json +7 -1
- package/.github/workflows/ci.yml +0 -26
- package/.github/workflows/publish.yml +0 -66
- package/src/api.ts +0 -70
- package/src/commands/agents.ts +0 -115
- package/src/commands/login.ts +0 -100
- package/src/commands/stats.ts +0 -48
- package/src/commands/tasks.ts +0 -189
- package/src/commands/whoami.ts +0 -47
- package/src/config.ts +0 -72
- package/src/index.ts +0 -41
- package/src/ui.ts +0 -92
- package/tsconfig.json +0 -14
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
name: Publish to npm
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
tags:
|
|
6
|
-
- 'v*'
|
|
7
|
-
|
|
8
|
-
permissions:
|
|
9
|
-
contents: write
|
|
10
|
-
|
|
11
|
-
jobs:
|
|
12
|
-
publish:
|
|
13
|
-
runs-on: ubuntu-latest
|
|
14
|
-
steps:
|
|
15
|
-
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
|
16
|
-
with:
|
|
17
|
-
fetch-depth: 0
|
|
18
|
-
|
|
19
|
-
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
|
20
|
-
with:
|
|
21
|
-
node-version: 22
|
|
22
|
-
cache: npm
|
|
23
|
-
registry-url: https://registry.npmjs.org
|
|
24
|
-
|
|
25
|
-
- run: npm ci
|
|
26
|
-
|
|
27
|
-
- name: Type check
|
|
28
|
-
run: npx tsc --noEmit
|
|
29
|
-
|
|
30
|
-
- name: Build
|
|
31
|
-
run: npm run build
|
|
32
|
-
|
|
33
|
-
- name: Verify package version matches tag
|
|
34
|
-
run: |
|
|
35
|
-
PKG_VERSION=$(node -p "require('./package.json').version")
|
|
36
|
-
TAG_VERSION="${GITHUB_REF_NAME#v}"
|
|
37
|
-
if [ "$PKG_VERSION" != "$TAG_VERSION" ]; then
|
|
38
|
-
echo "❌ package.json version ($PKG_VERSION) doesn't match tag ($TAG_VERSION)"
|
|
39
|
-
exit 1
|
|
40
|
-
fi
|
|
41
|
-
|
|
42
|
-
- name: Publish to npm
|
|
43
|
-
run: npm publish --access public
|
|
44
|
-
env:
|
|
45
|
-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
46
|
-
|
|
47
|
-
- name: Generate changelog
|
|
48
|
-
run: |
|
|
49
|
-
PREV_TAG=$(git tag --sort=-v:refname | sed -n '2p')
|
|
50
|
-
if [ -n "$PREV_TAG" ]; then
|
|
51
|
-
echo "## Changes since $PREV_TAG" > /tmp/changelog.md
|
|
52
|
-
echo "" >> /tmp/changelog.md
|
|
53
|
-
git log "$PREV_TAG"..HEAD --pretty=format:"- %s (%h)" --no-merges >> /tmp/changelog.md
|
|
54
|
-
else
|
|
55
|
-
echo "## Initial release" > /tmp/changelog.md
|
|
56
|
-
echo "" >> /tmp/changelog.md
|
|
57
|
-
git log --pretty=format:"- %s (%h)" --no-merges >> /tmp/changelog.md
|
|
58
|
-
fi
|
|
59
|
-
|
|
60
|
-
- name: Create GitHub Release
|
|
61
|
-
env:
|
|
62
|
-
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
63
|
-
run: |
|
|
64
|
-
gh release create "${{ github.ref_name }}" \
|
|
65
|
-
--title "${{ github.ref_name }}" \
|
|
66
|
-
--notes-file /tmp/changelog.md
|
package/src/api.ts
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import { getApiKey, getApiUrl } from "./config.js";
|
|
2
|
-
|
|
3
|
-
export interface ApiError {
|
|
4
|
-
error?: string;
|
|
5
|
-
message?: string;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export async function apiCall<T = unknown>(
|
|
9
|
-
method: string,
|
|
10
|
-
path: string,
|
|
11
|
-
body?: unknown,
|
|
12
|
-
): Promise<T> {
|
|
13
|
-
const apiKey = getApiKey();
|
|
14
|
-
if (!apiKey) {
|
|
15
|
-
console.error("Not authenticated. Run: delega login");
|
|
16
|
-
process.exit(1);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
let apiBase: string;
|
|
20
|
-
try {
|
|
21
|
-
apiBase = getApiUrl();
|
|
22
|
-
} catch (err) {
|
|
23
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
24
|
-
console.error(`Configuration error: ${msg}`);
|
|
25
|
-
process.exit(1);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const url = apiBase + path;
|
|
29
|
-
|
|
30
|
-
const headers: Record<string, string> = {
|
|
31
|
-
"X-Agent-Key": apiKey,
|
|
32
|
-
"Content-Type": "application/json",
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
const options: RequestInit = { method, headers };
|
|
36
|
-
if (body !== undefined) {
|
|
37
|
-
options.body = JSON.stringify(body);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
let res: Response;
|
|
41
|
-
try {
|
|
42
|
-
res = await fetch(url, options);
|
|
43
|
-
} catch (err) {
|
|
44
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
45
|
-
console.error(`Connection error: ${msg}`);
|
|
46
|
-
process.exit(1);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
if (res.status === 401) {
|
|
50
|
-
console.error("Authentication failed. Run: delega login");
|
|
51
|
-
process.exit(1);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
let data: unknown;
|
|
55
|
-
const text = await res.text();
|
|
56
|
-
try {
|
|
57
|
-
data = text ? JSON.parse(text) : {};
|
|
58
|
-
} catch {
|
|
59
|
-
data = { message: text };
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (!res.ok) {
|
|
63
|
-
const errData = data as ApiError;
|
|
64
|
-
const msg = errData.error || errData.message || `Request failed (${res.status})`;
|
|
65
|
-
console.error(`Error: ${msg}`);
|
|
66
|
-
process.exit(1);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
return data as T;
|
|
70
|
-
}
|
package/src/commands/agents.ts
DELETED
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
import { Command } from "commander";
|
|
2
|
-
import node_readline from "node:readline";
|
|
3
|
-
import chalk from "chalk";
|
|
4
|
-
import { apiCall } from "../api.js";
|
|
5
|
-
import { printTable, formatDate, label } from "../ui.js";
|
|
6
|
-
|
|
7
|
-
interface Agent {
|
|
8
|
-
id: string;
|
|
9
|
-
name: string;
|
|
10
|
-
display_name?: string;
|
|
11
|
-
active?: boolean;
|
|
12
|
-
created_at?: string;
|
|
13
|
-
api_key?: string;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function confirm(question: string): Promise<boolean> {
|
|
17
|
-
const rl = node_readline.createInterface({
|
|
18
|
-
input: process.stdin,
|
|
19
|
-
output: process.stdout,
|
|
20
|
-
});
|
|
21
|
-
return new Promise((resolve) => {
|
|
22
|
-
rl.question(question, (answer) => {
|
|
23
|
-
rl.close();
|
|
24
|
-
resolve(answer.trim().toLowerCase() === "y");
|
|
25
|
-
});
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const agentsList = new Command("list")
|
|
30
|
-
.description("List agents")
|
|
31
|
-
.option("--json", "Output raw JSON")
|
|
32
|
-
.action(async (opts) => {
|
|
33
|
-
const data = await apiCall<Agent[]>("GET", "/v1/agents");
|
|
34
|
-
|
|
35
|
-
if (opts.json) {
|
|
36
|
-
console.log(JSON.stringify(data, null, 2));
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const agents = Array.isArray(data) ? data : [data];
|
|
41
|
-
|
|
42
|
-
if (agents.length === 0) {
|
|
43
|
-
console.log("No agents found.");
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const headers = ["Name", "Display Name", "Active", "Created"];
|
|
48
|
-
const rows = agents.map((a) => [
|
|
49
|
-
a.name,
|
|
50
|
-
a.display_name || "—",
|
|
51
|
-
a.active !== false ? "yes" : "no",
|
|
52
|
-
formatDate(a.created_at || ""),
|
|
53
|
-
]);
|
|
54
|
-
|
|
55
|
-
printTable(headers, rows);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
const agentsCreate = new Command("create")
|
|
59
|
-
.description("Create a new agent")
|
|
60
|
-
.argument("<name>", "Agent name")
|
|
61
|
-
.option("--display-name <name>", "Friendly display name")
|
|
62
|
-
.option("--json", "Output raw JSON")
|
|
63
|
-
.action(async (name: string, opts) => {
|
|
64
|
-
const body: Record<string, unknown> = { name };
|
|
65
|
-
if (opts.displayName) body.display_name = opts.displayName;
|
|
66
|
-
|
|
67
|
-
const agent = await apiCall<Agent>("POST", "/v1/agents", body);
|
|
68
|
-
|
|
69
|
-
if (opts.json) {
|
|
70
|
-
console.log(JSON.stringify(agent, null, 2));
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
console.log();
|
|
75
|
-
label("Agent Created", agent.name);
|
|
76
|
-
if (agent.display_name) label("Display Name", agent.display_name);
|
|
77
|
-
label("ID", agent.id);
|
|
78
|
-
if (agent.api_key) {
|
|
79
|
-
console.log();
|
|
80
|
-
console.log(` API Key: ${chalk.cyan.bold(agent.api_key)}`);
|
|
81
|
-
console.log(
|
|
82
|
-
chalk.yellow(" Save this key — it will not be shown again."),
|
|
83
|
-
);
|
|
84
|
-
}
|
|
85
|
-
console.log();
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
const agentsRotate = new Command("rotate")
|
|
89
|
-
.description("Rotate an agent's API key")
|
|
90
|
-
.argument("<id>", "Agent ID")
|
|
91
|
-
.action(async (id: string) => {
|
|
92
|
-
const yes = await confirm(
|
|
93
|
-
`Rotate key for agent ${id}? Old key will stop working immediately. (y/N) `,
|
|
94
|
-
);
|
|
95
|
-
if (!yes) {
|
|
96
|
-
console.log("Cancelled.");
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const result = await apiCall<{ api_key: string }>(
|
|
101
|
-
"POST",
|
|
102
|
-
`/v1/agents/${id}/rotate-key`,
|
|
103
|
-
);
|
|
104
|
-
|
|
105
|
-
console.log();
|
|
106
|
-
console.log(` New API Key: ${chalk.cyan.bold(result.api_key)}`);
|
|
107
|
-
console.log(chalk.yellow(" Save this key — it will not be shown again."));
|
|
108
|
-
console.log();
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
export const agentsCommand = new Command("agents")
|
|
112
|
-
.description("Manage agents")
|
|
113
|
-
.addCommand(agentsList)
|
|
114
|
-
.addCommand(agentsCreate)
|
|
115
|
-
.addCommand(agentsRotate);
|
package/src/commands/login.ts
DELETED
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import { Command } from "commander";
|
|
2
|
-
import node_readline from "node:readline";
|
|
3
|
-
import { saveConfig, loadConfig, normalizeApiUrl } from "../config.js";
|
|
4
|
-
import { printBanner } from "../ui.js";
|
|
5
|
-
|
|
6
|
-
interface Agent {
|
|
7
|
-
id: string;
|
|
8
|
-
name: string;
|
|
9
|
-
display_name?: string;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
async function promptSecret(question: string): Promise<string> {
|
|
13
|
-
const mutedOutput = {
|
|
14
|
-
muted: false,
|
|
15
|
-
write(chunk: string) {
|
|
16
|
-
if (!this.muted || chunk.includes(question)) {
|
|
17
|
-
process.stdout.write(chunk);
|
|
18
|
-
}
|
|
19
|
-
},
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
const rl = node_readline.createInterface({
|
|
23
|
-
input: process.stdin,
|
|
24
|
-
output: mutedOutput as unknown as NodeJS.WritableStream,
|
|
25
|
-
terminal: true,
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
mutedOutput.muted = true;
|
|
29
|
-
|
|
30
|
-
return new Promise((resolve) => {
|
|
31
|
-
rl.question(question, (answer) => {
|
|
32
|
-
rl.close();
|
|
33
|
-
process.stdout.write("\n");
|
|
34
|
-
resolve(answer.trim());
|
|
35
|
-
});
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export const loginCommand = new Command("login")
|
|
40
|
-
.description("Authenticate with the Delega API")
|
|
41
|
-
.action(async () => {
|
|
42
|
-
printBanner();
|
|
43
|
-
|
|
44
|
-
const key = await promptSecret("Enter your API key (starts with dlg_): ");
|
|
45
|
-
|
|
46
|
-
if (!key) {
|
|
47
|
-
console.error("No key provided.");
|
|
48
|
-
process.exit(1);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
if (!key.startsWith("dlg_")) {
|
|
52
|
-
console.error("Invalid key format. Keys start with dlg_");
|
|
53
|
-
process.exit(1);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Validate by calling the API
|
|
57
|
-
const config = loadConfig();
|
|
58
|
-
let apiUrl: string;
|
|
59
|
-
try {
|
|
60
|
-
apiUrl = normalizeApiUrl(
|
|
61
|
-
config.api_url || process.env.DELEGA_API_URL || "https://api.delega.dev",
|
|
62
|
-
);
|
|
63
|
-
} catch (err) {
|
|
64
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
65
|
-
console.error(`Configuration error: ${msg}`);
|
|
66
|
-
process.exit(1);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
let res: Response;
|
|
70
|
-
try {
|
|
71
|
-
res = await fetch(`${apiUrl}/v1/agent/me`, {
|
|
72
|
-
headers: {
|
|
73
|
-
"X-Agent-Key": key,
|
|
74
|
-
"Content-Type": "application/json",
|
|
75
|
-
},
|
|
76
|
-
});
|
|
77
|
-
} catch (err) {
|
|
78
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
79
|
-
console.error(`Connection error: ${msg}`);
|
|
80
|
-
process.exit(1);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
if (!res.ok) {
|
|
84
|
-
console.error("Invalid API key. Authentication failed.");
|
|
85
|
-
process.exit(1);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
let agentName = "agent";
|
|
89
|
-
try {
|
|
90
|
-
const data = (await res.json()) as { agent?: Agent };
|
|
91
|
-
if (data.agent?.name) {
|
|
92
|
-
agentName = data.agent.display_name || data.agent.name;
|
|
93
|
-
}
|
|
94
|
-
} catch {
|
|
95
|
-
// Proceed with default name
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
saveConfig({ ...config, api_key: key });
|
|
99
|
-
console.log(`\nLogged in as ${agentName}. Key saved to ~/.delega/config.json`);
|
|
100
|
-
});
|
package/src/commands/stats.ts
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { Command } from "commander";
|
|
2
|
-
import { apiCall } from "../api.js";
|
|
3
|
-
import { label } from "../ui.js";
|
|
4
|
-
|
|
5
|
-
interface Stats {
|
|
6
|
-
total_tasks?: number;
|
|
7
|
-
completed_tasks?: number;
|
|
8
|
-
pending_tasks?: number;
|
|
9
|
-
total_agents?: number;
|
|
10
|
-
active_agents?: number;
|
|
11
|
-
[key: string]: unknown;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export const statsCommand = new Command("stats")
|
|
15
|
-
.description("Show usage statistics")
|
|
16
|
-
.option("--json", "Output raw JSON")
|
|
17
|
-
.action(async (opts) => {
|
|
18
|
-
const data = await apiCall<Stats>("GET", "/v1/stats");
|
|
19
|
-
|
|
20
|
-
if (opts.json) {
|
|
21
|
-
console.log(JSON.stringify(data, null, 2));
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
console.log();
|
|
26
|
-
if (data.total_tasks !== undefined) label("Total Tasks", String(data.total_tasks));
|
|
27
|
-
if (data.completed_tasks !== undefined) label("Completed", String(data.completed_tasks));
|
|
28
|
-
if (data.pending_tasks !== undefined) label("Pending", String(data.pending_tasks));
|
|
29
|
-
if (data.total_agents !== undefined) label("Total Agents", String(data.total_agents));
|
|
30
|
-
if (data.active_agents !== undefined) label("Active Agents", String(data.active_agents));
|
|
31
|
-
|
|
32
|
-
// Print any additional stats fields
|
|
33
|
-
const knownKeys = new Set([
|
|
34
|
-
"total_tasks",
|
|
35
|
-
"completed_tasks",
|
|
36
|
-
"pending_tasks",
|
|
37
|
-
"total_agents",
|
|
38
|
-
"active_agents",
|
|
39
|
-
]);
|
|
40
|
-
for (const [key, value] of Object.entries(data)) {
|
|
41
|
-
if (!knownKeys.has(key) && value !== undefined) {
|
|
42
|
-
const displayKey = key.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
43
|
-
const displayVal = typeof value === "object" ? JSON.stringify(value) : String(value);
|
|
44
|
-
label(displayKey, displayVal);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
console.log();
|
|
48
|
-
});
|
package/src/commands/tasks.ts
DELETED
|
@@ -1,189 +0,0 @@
|
|
|
1
|
-
import { Command } from "commander";
|
|
2
|
-
import node_readline from "node:readline";
|
|
3
|
-
import { apiCall } from "../api.js";
|
|
4
|
-
import {
|
|
5
|
-
printTable,
|
|
6
|
-
formatDate,
|
|
7
|
-
formatId,
|
|
8
|
-
priorityBadge,
|
|
9
|
-
statusBadge,
|
|
10
|
-
label,
|
|
11
|
-
} from "../ui.js";
|
|
12
|
-
|
|
13
|
-
interface Task {
|
|
14
|
-
id: string;
|
|
15
|
-
content: string;
|
|
16
|
-
status: string;
|
|
17
|
-
priority: number;
|
|
18
|
-
labels?: string[];
|
|
19
|
-
due_date?: string;
|
|
20
|
-
created_at?: string;
|
|
21
|
-
updated_at?: string;
|
|
22
|
-
completed_at?: string;
|
|
23
|
-
assigned_to_agent_id?: string;
|
|
24
|
-
comments?: Comment[];
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
interface Comment {
|
|
28
|
-
id: string;
|
|
29
|
-
content: string;
|
|
30
|
-
created_at?: string;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function confirm(question: string): Promise<boolean> {
|
|
34
|
-
const rl = node_readline.createInterface({
|
|
35
|
-
input: process.stdin,
|
|
36
|
-
output: process.stdout,
|
|
37
|
-
});
|
|
38
|
-
return new Promise((resolve) => {
|
|
39
|
-
rl.question(question, (answer) => {
|
|
40
|
-
rl.close();
|
|
41
|
-
resolve(answer.trim().toLowerCase() === "y");
|
|
42
|
-
});
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const tasksList = new Command("list")
|
|
47
|
-
.description("List tasks")
|
|
48
|
-
.option("--completed", "Include completed tasks")
|
|
49
|
-
.option("--limit <n>", "Limit results", parseInt)
|
|
50
|
-
.option("--json", "Output raw JSON")
|
|
51
|
-
.action(async (opts) => {
|
|
52
|
-
let path = "/v1/tasks";
|
|
53
|
-
const params: string[] = [];
|
|
54
|
-
if (opts.completed) params.push("completed=true");
|
|
55
|
-
if (opts.limit) params.push(`limit=${opts.limit}`);
|
|
56
|
-
if (params.length > 0) path += "?" + params.join("&");
|
|
57
|
-
|
|
58
|
-
const data = await apiCall<Task[]>("GET", path);
|
|
59
|
-
|
|
60
|
-
if (opts.json) {
|
|
61
|
-
console.log(JSON.stringify(data, null, 2));
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const tasks = Array.isArray(data) ? data : [];
|
|
66
|
-
|
|
67
|
-
if (tasks.length === 0) {
|
|
68
|
-
console.log("No tasks found.");
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const headers = ["ID", "Priority", "Status", "Content"];
|
|
73
|
-
const rows = tasks.map((t) => [
|
|
74
|
-
formatId(t.id),
|
|
75
|
-
priorityBadge(t.priority),
|
|
76
|
-
statusBadge(t.status),
|
|
77
|
-
t.content.length > 50 ? t.content.slice(0, 47) + "..." : t.content,
|
|
78
|
-
]);
|
|
79
|
-
|
|
80
|
-
printTable(headers, rows);
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
const tasksCreate = new Command("create")
|
|
84
|
-
.description("Create a new task")
|
|
85
|
-
.argument("<content>", "Task content")
|
|
86
|
-
.option("--priority <n>", "Priority 1-4 (default: 1)", (v: string) => parseInt(v, 10), 1)
|
|
87
|
-
.option("--labels <labels>", "Comma-separated labels")
|
|
88
|
-
.option("--due <date>", "Due date (YYYY-MM-DD)")
|
|
89
|
-
.option("--json", "Output raw JSON")
|
|
90
|
-
.action(async (content: string, opts) => {
|
|
91
|
-
const body: Record<string, unknown> = { content };
|
|
92
|
-
if (opts.priority) body.priority = opts.priority;
|
|
93
|
-
if (opts.labels) body.labels = opts.labels.split(",").map((l: string) => l.trim());
|
|
94
|
-
if (opts.due) body.due_date = opts.due;
|
|
95
|
-
|
|
96
|
-
const task = await apiCall<Task>("POST", "/v1/tasks", body);
|
|
97
|
-
|
|
98
|
-
if (opts.json) {
|
|
99
|
-
console.log(JSON.stringify(task, null, 2));
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
console.log(`Task created: ${task.id}`);
|
|
104
|
-
console.log();
|
|
105
|
-
label("Content", task.content);
|
|
106
|
-
label("Priority", priorityBadge(task.priority));
|
|
107
|
-
label("Status", statusBadge(task.status));
|
|
108
|
-
if (task.due_date) label("Due", formatDate(task.due_date));
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
const tasksShow = new Command("show")
|
|
112
|
-
.description("Show task details")
|
|
113
|
-
.argument("<id>", "Task ID")
|
|
114
|
-
.option("--json", "Output raw JSON")
|
|
115
|
-
.action(async (id: string, opts) => {
|
|
116
|
-
const task = await apiCall<Task>("GET", `/v1/tasks/${id}`);
|
|
117
|
-
|
|
118
|
-
if (opts.json) {
|
|
119
|
-
console.log(JSON.stringify(task, null, 2));
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
console.log();
|
|
124
|
-
label("ID", task.id);
|
|
125
|
-
label("Content", task.content);
|
|
126
|
-
label("Status", statusBadge(task.status));
|
|
127
|
-
label("Priority", priorityBadge(task.priority));
|
|
128
|
-
const labels = typeof task.labels === "string" ? JSON.parse(task.labels) : task.labels;
|
|
129
|
-
if (labels && labels.length > 0) {
|
|
130
|
-
label("Labels", labels.join(", "));
|
|
131
|
-
}
|
|
132
|
-
if (task.due_date) label("Due", formatDate(task.due_date));
|
|
133
|
-
if (task.assigned_to_agent_id) label("Assigned To", task.assigned_to_agent_id);
|
|
134
|
-
label("Created", formatDate(task.created_at || ""));
|
|
135
|
-
if (task.updated_at) label("Updated", formatDate(task.updated_at));
|
|
136
|
-
if (task.completed_at) label("Completed", formatDate(task.completed_at));
|
|
137
|
-
|
|
138
|
-
if (task.comments && task.comments.length > 0) {
|
|
139
|
-
console.log();
|
|
140
|
-
console.log("Comments:");
|
|
141
|
-
for (const c of task.comments) {
|
|
142
|
-
console.log(` [${formatDate(c.created_at || "")}] ${c.content}`);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
console.log();
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
const tasksComplete = new Command("complete")
|
|
149
|
-
.description("Mark a task as completed")
|
|
150
|
-
.argument("<id>", "Task ID")
|
|
151
|
-
.action(async (id: string) => {
|
|
152
|
-
await apiCall("POST", `/v1/tasks/${id}/complete`);
|
|
153
|
-
console.log(`Task ${id} completed.`);
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
const tasksDelete = new Command("delete")
|
|
157
|
-
.description("Delete a task")
|
|
158
|
-
.argument("<id>", "Task ID")
|
|
159
|
-
.action(async (id: string) => {
|
|
160
|
-
const yes = await confirm(`Delete task ${id}? (y/N) `);
|
|
161
|
-
if (!yes) {
|
|
162
|
-
console.log("Cancelled.");
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
165
|
-
await apiCall("DELETE", `/v1/tasks/${id}`);
|
|
166
|
-
console.log(`Task ${id} deleted.`);
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
const tasksDelegate = new Command("delegate")
|
|
170
|
-
.description("Delegate a task to another agent")
|
|
171
|
-
.argument("<task_id>", "Task ID")
|
|
172
|
-
.argument("<agent_id>", "Agent ID to delegate to")
|
|
173
|
-
.requiredOption("--content <content>", "Subtask description (required)")
|
|
174
|
-
.action(async (taskId: string, agentId: string, opts) => {
|
|
175
|
-
const body: Record<string, unknown> = { assigned_to_agent_id: agentId };
|
|
176
|
-
if (opts.content) body.content = opts.content;
|
|
177
|
-
|
|
178
|
-
await apiCall("POST", `/v1/tasks/${taskId}/delegate`, body);
|
|
179
|
-
console.log(`Task delegated to ${agentId}.`);
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
export const tasksCommand = new Command("tasks")
|
|
183
|
-
.description("Manage tasks")
|
|
184
|
-
.addCommand(tasksList)
|
|
185
|
-
.addCommand(tasksCreate)
|
|
186
|
-
.addCommand(tasksShow)
|
|
187
|
-
.addCommand(tasksComplete)
|
|
188
|
-
.addCommand(tasksDelete)
|
|
189
|
-
.addCommand(tasksDelegate);
|
package/src/commands/whoami.ts
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { Command } from "commander";
|
|
2
|
-
import { apiCall } from "../api.js";
|
|
3
|
-
import { label } from "../ui.js";
|
|
4
|
-
|
|
5
|
-
interface Agent {
|
|
6
|
-
id: string;
|
|
7
|
-
name: string;
|
|
8
|
-
display_name?: string;
|
|
9
|
-
email?: string;
|
|
10
|
-
plan?: string;
|
|
11
|
-
active?: boolean;
|
|
12
|
-
user?: {
|
|
13
|
-
email?: string;
|
|
14
|
-
plan?: string;
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export const whoamiCommand = new Command("whoami")
|
|
19
|
-
.description("Show current authenticated agent")
|
|
20
|
-
.action(async () => {
|
|
21
|
-
const data = await apiCall<Agent | Agent[]>("GET", "/v1/agents");
|
|
22
|
-
|
|
23
|
-
let agent: Agent;
|
|
24
|
-
if (Array.isArray(data)) {
|
|
25
|
-
if (data.length === 0) {
|
|
26
|
-
console.error("No agent found.");
|
|
27
|
-
process.exit(1);
|
|
28
|
-
}
|
|
29
|
-
agent = data[0];
|
|
30
|
-
} else {
|
|
31
|
-
agent = data;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
console.log();
|
|
35
|
-
label("Agent", agent.name);
|
|
36
|
-
if (agent.display_name) {
|
|
37
|
-
label("Display Name", agent.display_name);
|
|
38
|
-
}
|
|
39
|
-
if (agent.user?.email || agent.email) {
|
|
40
|
-
label("Email", agent.user?.email || agent.email || "");
|
|
41
|
-
}
|
|
42
|
-
if (agent.user?.plan || agent.plan) {
|
|
43
|
-
label("Plan", agent.user?.plan || agent.plan || "");
|
|
44
|
-
}
|
|
45
|
-
label("Active", agent.active !== false ? "yes" : "no");
|
|
46
|
-
console.log();
|
|
47
|
-
});
|