Skip to content

Commit 6fb636d

Browse files
committed
Add task list and task show commands to CLI
New commands for viewing team tasks: `codeforge task list` shows all tasks for a team, `codeforge task show` displays task detail with dependencies. Includes text and JSON formatters and test coverage. Also removes prompts/ from package files and adds CLI README.
1 parent 91d8d04 commit 6fb636d

8 files changed

Lines changed: 352 additions & 3 deletions

File tree

cli/README.md

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# CodeForge CLI
2+
3+
CLI for CodeForge development workflows. Manages sessions, plugins, configuration, codebase indexing, and devcontainers.
4+
5+
> **Experimental** — v0.1.0. Ships with CodeForge v2.1.1.
6+
7+
## Install
8+
9+
```bash
10+
npm install -g codeforge-dev-cli
11+
```
12+
13+
Requires [Bun](https://bun.sh) runtime.
14+
15+
## Usage
16+
17+
```bash
18+
codeforge <command> [options]
19+
```
20+
21+
### Global Options
22+
23+
| Flag | Description |
24+
|------|-------------|
25+
| `--local` | Run against the host filesystem (skip container proxy) |
26+
| `--container <name>` | Target a specific container by name |
27+
28+
When run outside a devcontainer, commands auto-proxy into the running CodeForge container. Use `--local` to bypass.
29+
30+
## Commands
31+
32+
### `codeforge session` — Session History
33+
34+
```bash
35+
codeforge session search "query" # Search session history
36+
codeforge session list # List recent sessions
37+
codeforge session show <id> # Show session details
38+
```
39+
40+
### `codeforge task` — Task Search
41+
42+
```bash
43+
codeforge task search "query" # Search tasks across sessions
44+
```
45+
46+
### `codeforge plan` — Plan Search
47+
48+
```bash
49+
codeforge plan search "query" # Search plans across sessions
50+
```
51+
52+
### `codeforge plugin` — Plugin Management
53+
54+
```bash
55+
codeforge plugin list # List installed plugins
56+
codeforge plugin show <name> # Show plugin details
57+
codeforge plugin enable <name> # Enable a plugin
58+
codeforge plugin disable <name> # Disable a plugin
59+
codeforge plugin hooks [name] # Show hooks (all or per-plugin)
60+
codeforge plugin agents [name] # Show agents (all or per-plugin)
61+
codeforge plugin skills [name] # Show skills (all or per-plugin)
62+
```
63+
64+
### `codeforge config` — Configuration
65+
66+
```bash
67+
codeforge config show # Show current configuration
68+
codeforge config apply # Deploy config files to ~/.claude/
69+
```
70+
71+
### `codeforge index` — Codebase Index
72+
73+
```bash
74+
codeforge index build # Build symbol index for current project
75+
codeforge index search "query" # Search the symbol index
76+
codeforge index show <symbol> # Show symbol details
77+
codeforge index stats # Index statistics
78+
codeforge index tree # Symbol tree view
79+
codeforge index clean # Remove index data
80+
```
81+
82+
### `codeforge container` — Devcontainer Management
83+
84+
These commands always run on the host (never proxied).
85+
86+
```bash
87+
codeforge container up # Start the devcontainer
88+
codeforge container down # Stop the devcontainer
89+
codeforge container rebuild # Rebuild the devcontainer
90+
codeforge container exec <cmd> # Execute a command in the container
91+
codeforge container ls # List running containers
92+
codeforge container shell # Open a shell in the container
93+
```
94+
95+
## License
96+
97+
GPL-3.0 — see [LICENSE](../LICENSE.txt).

cli/bun.lock

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cli/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@
4747
"homepage": "https://github.com/AnExiledDev/CodeForge/tree/main/cli#readme",
4848
"files": [
4949
"dist/",
50-
"prompts/",
5150
"README.md"
5251
],
5352
"bugs": {

cli/src/commands/task/list.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import chalk from "chalk";
2+
import type { Command } from "commander";
3+
import { loadTasks } from "../../loaders/task-loader.js";
4+
import { formatTaskJson, formatTaskText } from "../../output/task-text.js";
5+
6+
interface TaskListOptions {
7+
team?: string;
8+
status?: string;
9+
limit: string;
10+
format: string;
11+
color?: boolean;
12+
fullText?: boolean;
13+
}
14+
15+
export function registerTaskListCommand(parent: Command): void {
16+
parent
17+
.command("list")
18+
.description("List all tasks")
19+
.option("--team <name>", "Filter by team name")
20+
.option("--status <status>", "Filter by task status")
21+
.option("-n, --limit <count>", "Maximum number of results", "50")
22+
.option("-f, --format <format>", "Output format: text|json", "text")
23+
.option("--no-color", "Disable colored output")
24+
.option("--full-text", "Disable description truncation")
25+
.action(async (options: TaskListOptions) => {
26+
try {
27+
if (!options.color) {
28+
chalk.level = 0;
29+
}
30+
31+
let tasks = await loadTasks({
32+
team: options.team,
33+
status: options.status,
34+
});
35+
36+
// Apply limit
37+
const limit = parseInt(options.limit, 10);
38+
tasks = tasks.slice(0, limit);
39+
40+
if (options.format === "json") {
41+
console.log(formatTaskJson(tasks));
42+
} else {
43+
console.log(
44+
formatTaskText(tasks, {
45+
noColor: !options.color,
46+
fullText: options.fullText,
47+
}),
48+
);
49+
}
50+
} catch (err) {
51+
const message = err instanceof Error ? err.message : String(err);
52+
console.error(`Error: ${message}`);
53+
process.exit(1);
54+
}
55+
});
56+
}

cli/src/commands/task/show.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import chalk from "chalk";
2+
import type { Command } from "commander";
3+
import { loadTasks } from "../../loaders/task-loader.js";
4+
import {
5+
formatTaskShowJson,
6+
formatTaskShowText,
7+
} from "../../output/task-text.js";
8+
9+
interface TaskShowOptions {
10+
team?: string;
11+
format: string;
12+
color?: boolean;
13+
}
14+
15+
export function registerTaskShowCommand(parent: Command): void {
16+
parent
17+
.command("show")
18+
.description("Show a single task with full detail")
19+
.argument("<id>", "Task ID to look up")
20+
.option("--team <name>", "Filter by team name")
21+
.option("-f, --format <format>", "Output format: text|json", "text")
22+
.option("--no-color", "Disable colored output")
23+
.action(async (id: string, options: TaskShowOptions) => {
24+
try {
25+
if (!options.color) {
26+
chalk.level = 0;
27+
}
28+
29+
const tasks = await loadTasks({ team: options.team });
30+
const task = tasks.find((t) => t.id === id);
31+
32+
if (!task) {
33+
console.error(`Error: Task #${id} not found`);
34+
process.exit(1);
35+
}
36+
37+
if (options.format === "json") {
38+
console.log(formatTaskShowJson(task));
39+
} else {
40+
console.log(formatTaskShowText(task, { noColor: !options.color }));
41+
}
42+
} catch (err) {
43+
const message = err instanceof Error ? err.message : String(err);
44+
console.error(`Error: ${message}`);
45+
process.exit(1);
46+
}
47+
});
48+
}

cli/src/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ import { registerPluginSkillsCommand } from "./commands/plugin/skills.js";
2626
import { registerListCommand } from "./commands/session/list.js";
2727
import { registerSearchCommand } from "./commands/session/search.js";
2828
import { registerShowCommand } from "./commands/session/show.js";
29+
import { registerTaskListCommand } from "./commands/task/list.js";
2930
import { registerTaskSearchCommand } from "./commands/task/search.js";
31+
import { registerTaskShowCommand } from "./commands/task/show.js";
3032
import { isInsideContainer, proxyCommand } from "./utils/context.js";
3133
import { resolveContainer } from "./utils/docker.js";
3234

@@ -49,7 +51,9 @@ registerShowCommand(session);
4951

5052
const task = program.command("task").description("Search and manage tasks");
5153

54+
registerTaskListCommand(task);
5255
registerTaskSearchCommand(task);
56+
registerTaskShowCommand(task);
5357

5458
const plan = program.command("plan").description("Search and manage plans");
5559

cli/src/output/task-text.ts

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import chalk from "chalk";
22
import type { TaskWithTeam } from "../loaders/task-loader.js";
33

4-
function colorStatus(status: string): string {
4+
export function colorStatus(status: string): string {
55
switch (status) {
66
case "pending":
77
return chalk.yellow(status);
@@ -59,3 +59,58 @@ export function formatTaskJson(tasks: TaskWithTeam[]): string {
5959

6060
return JSON.stringify(output, null, 2);
6161
}
62+
63+
export function formatTaskShowText(
64+
task: TaskWithTeam,
65+
options?: { noColor?: boolean },
66+
): string {
67+
if (options?.noColor) {
68+
chalk.level = 0;
69+
}
70+
71+
const lines: string[] = [];
72+
73+
lines.push(`Team: ${chalk.magenta(task.team)}`);
74+
lines.push(`Task: #${task.id}`);
75+
lines.push(`Status: ${colorStatus(task.status)}`);
76+
lines.push(`Subject: ${task.subject}`);
77+
78+
if (task.description) {
79+
lines.push("");
80+
lines.push("Description:");
81+
for (const line of task.description.split("\n")) {
82+
lines.push(` ${line}`);
83+
}
84+
}
85+
86+
lines.push("");
87+
const blocks =
88+
task.blocks.length > 0
89+
? task.blocks.map((b) => `#${b}`).join(", ")
90+
: "\u2014";
91+
lines.push(`Blocks: ${blocks}`);
92+
93+
const blockedBy =
94+
task.blockedBy.length > 0
95+
? task.blockedBy.map((b) => `#${b}`).join(", ")
96+
: "\u2014";
97+
lines.push(`Blocked by: ${blockedBy}`);
98+
99+
return lines.join("\n");
100+
}
101+
102+
export function formatTaskShowJson(task: TaskWithTeam): string {
103+
return JSON.stringify(
104+
{
105+
id: task.id,
106+
team: task.team,
107+
status: task.status,
108+
subject: task.subject,
109+
description: task.description,
110+
blocks: task.blocks,
111+
blockedBy: task.blockedBy,
112+
},
113+
null,
114+
2,
115+
);
116+
}

0 commit comments

Comments
 (0)