Skip to content

Commit 7723a37

Browse files
committed
feat: **Community support** - Contributing guidelines to help new contributors
1 parent f7e4ae8 commit 7723a37

File tree

4 files changed

+78
-59
lines changed

4 files changed

+78
-59
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
### Added
1111
- **Ideas Queue Management** - New CLI commands for managing the ideas queue
1212
- `opencoder idea <description>` command to quickly add ideas to the queue
13-
- `--ideas-list` flag to list all queued ideas without starting the loop
13+
- `opencoder idea list` command to list all queued ideas
1414
- Automatic timestamped filenames for easy organization
1515
- Pre-filled markdown templates for quick editing
1616
- **Enhanced Conventional Commits** - Expanded commit message generation

src/cli.ts

Lines changed: 68 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@ async function handleIdeaCommand(
3333
opts: Record<string, unknown>,
3434
): Promise<void> {
3535
try {
36+
// Validate description is not empty
37+
if (!description || !description.trim()) {
38+
console.error("Error: Idea description cannot be empty")
39+
process.exit(1)
40+
}
41+
3642
const projectDir = opts.project ? resolve(opts.project as string) : process.cwd()
3743
const paths = initializePaths(projectDir)
3844

@@ -70,6 +76,45 @@ async function handleIdeaCommand(
7076
}
7177
}
7278

79+
/**
80+
* Handle the 'idea list' subcommand: list all ideas in the queue
81+
*/
82+
async function handleIdeasListCommand(opts: Record<string, unknown>): Promise<void> {
83+
try {
84+
const projectDir = opts.project ? resolve(opts.project as string) : process.cwd()
85+
const paths = initializePaths(projectDir)
86+
87+
const ideas = await loadAllIdeas(paths.ideasDir)
88+
const count = await countIdeas(paths.ideasDir)
89+
90+
console.log("\nIdeas Queue")
91+
console.log("===========\n")
92+
93+
if (count === 0) {
94+
console.log("No ideas in queue.")
95+
console.log(`\nTo add ideas, run: opencoder idea "<description>"`)
96+
console.log(`Or place .md files in: ${paths.ideasDir}`)
97+
} else {
98+
console.log(`Found ${count} idea(s):\n`)
99+
for (let i = 0; i < ideas.length; i++) {
100+
const idea = ideas[i]
101+
if (!idea) continue
102+
const summary = getIdeaSummary(idea.content)
103+
console.log(` ${i + 1}. ${idea.filename}`)
104+
console.log(` ${summary}`)
105+
console.log("")
106+
}
107+
}
108+
109+
console.log("")
110+
} catch (err) {
111+
console.error(
112+
`Error: Failed to list ideas: ${err instanceof Error ? err.message : String(err)}`,
113+
)
114+
process.exit(1)
115+
}
116+
}
117+
73118
/**
74119
* Create and configure the CLI program
75120
*/
@@ -91,18 +136,27 @@ function createProgram(): Command {
91136
.option("-s, --signoff", "Add Signed-off-by line to commits")
92137
.option("--status", "Display metrics summary and exit")
93138
.option("--metrics-reset", "Reset metrics to default values (requires confirmation)")
94-
.option("--ideas-list", "List all ideas in the queue and exit")
95139

96-
// Add 'idea' subcommand
97-
const ideaCommand = program
98-
.command("idea")
99-
.description("Add a new idea to the queue")
140+
// Add 'idea' command with subcommands
141+
const ideaCommand = program.command("idea").description("Manage ideas in the queue")
142+
143+
// 'idea add' subcommand (default action)
144+
ideaCommand
100145
.argument("<description>", "Description of the idea")
101146
.option("-p, --project <dir>", "Project directory (default: current directory)")
102147
.action(async (description: string, opts: Record<string, unknown>) => {
103148
await handleIdeaCommand(description, opts)
104149
})
105150

151+
// 'idea list' subcommand
152+
ideaCommand
153+
.command("list")
154+
.description("List all ideas in the queue")
155+
.option("-p, --project <dir>", "Project directory (default: current directory)")
156+
.action(async (opts: Record<string, unknown>) => {
157+
await handleIdeasListCommand(opts)
158+
})
159+
106160
// Add help text for idea command
107161
ideaCommand.addHelpText(
108162
"after",
@@ -111,6 +165,8 @@ Examples:
111165
$ opencoder idea "Fix login bug"
112166
$ opencoder idea "Add dark mode support" -p ./myproject
113167
$ opencoder idea "Implement user authentication with JWT tokens"
168+
$ opencoder idea list
169+
$ opencoder idea list -p ./myproject
114170
`,
115171
)
116172

@@ -149,20 +205,21 @@ Examples:
149205
$ opencoder --metrics-reset
150206
Reset metrics to default values (with confirmation)
151207
152-
$ opencoder --ideas-list
153-
List all ideas in the queue without starting the loop
154-
155-
$ opencoder --ideas-list -p ./myproject
156-
List ideas for a specific project
157-
158208
$ opencoder idea "Fix login bug"
159209
Add a new idea to the queue
160210
161211
$ opencoder idea "Add dark mode support" -p ./myproject
162212
Add idea to a specific project
163213
214+
$ opencoder idea list
215+
List all ideas in the queue
216+
217+
$ opencoder idea list -p ./myproject
218+
List ideas for a specific project
219+
164220
Commands:
165221
idea <description> Add a new idea to the queue
222+
idea list List all ideas in the queue
166223
167224
Options:
168225
-p, --project <dir> Project directory (default: current directory)
@@ -176,7 +233,6 @@ Options:
176233
-s, --signoff Add Signed-off-by line to commits
177234
--status Display metrics summary and exit
178235
--metrics-reset Reset metrics to default values (requires confirmation)
179-
--ideas-list List all ideas in the queue and exit
180236
181237
Environment variables:
182238
OPENCODER_PLAN_MODEL Default plan model
@@ -299,7 +355,6 @@ export async function run(): Promise<void> {
299355
commitSignoff: opts.signoff as boolean | undefined,
300356
status: opts.status as boolean | undefined,
301357
metricsReset: opts.metricsReset as boolean | undefined,
302-
ideasList: opts.ideasList as boolean | undefined,
303358
}
304359

305360
// Handle --version flag: display version info and exit
@@ -353,36 +408,6 @@ export async function run(): Promise<void> {
353408
return
354409
}
355410

356-
// Handle --ideas-list flag: display ideas queue and exit
357-
if (cliOptions.ideasList) {
358-
const projectDir = cliOptions.project ? resolve(cliOptions.project) : process.cwd()
359-
const paths = initializePaths(projectDir)
360-
361-
const ideas = await loadAllIdeas(paths.ideasDir)
362-
const count = await countIdeas(paths.ideasDir)
363-
364-
console.log("\nIdeas Queue")
365-
console.log("===========\n")
366-
367-
if (count === 0) {
368-
console.log("No ideas in queue.")
369-
console.log(`\nTo add ideas, place .md files in: ${paths.ideasDir}`)
370-
} else {
371-
console.log(`Found ${count} idea(s):\n`)
372-
for (let i = 0; i < ideas.length; i++) {
373-
const idea = ideas[i]
374-
if (!idea) continue
375-
const summary = getIdeaSummary(idea.content)
376-
console.log(` ${i + 1}. ${idea.filename}`)
377-
console.log(` ${summary}`)
378-
console.log("")
379-
}
380-
}
381-
382-
console.log("")
383-
return
384-
}
385-
386411
const config = await loadConfig(cliOptions, hint)
387412
await runLoop(config)
388413
} catch (err) {

src/types.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,5 +204,4 @@ export interface CliOptions {
204204
commitSignoff?: boolean
205205
status?: boolean
206206
metricsReset?: boolean
207-
ideasList?: boolean
208207
}

tests/cli.test.ts

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -227,24 +227,19 @@ describe("parseCli", () => {
227227
})
228228
})
229229

230-
describe("ideas-list option", () => {
231-
test("parses --ideas-list flag", () => {
232-
const result = parseCli(argv("--ideas-list"))
230+
describe("idea subcommands", () => {
231+
test("idea command is available", () => {
232+
const result = parseCli(argv("idea", "test idea"))
233233

234-
expect(result.options.ideasList).toBe(true)
235-
})
236-
237-
test("parses --ideas-list with project option", () => {
238-
const result = parseCli(argv("--ideas-list", "-p", "./myproject"))
239-
240-
expect(result.options.ideasList).toBe(true)
241-
expect(result.options.project).toBe("./myproject")
234+
expect(result.hint).toBeUndefined()
235+
// The idea command is handled separately by the idea subcommand handler
242236
})
243237

244-
test("ideasList is undefined when not provided", () => {
245-
const result = parseCli(argv("-m", "anthropic/claude-sonnet-4"))
238+
test("idea command with project option", () => {
239+
const result = parseCli(argv("idea", "test idea", "-p", "./myproject"))
246240

247-
expect(result.options.ideasList).toBeUndefined()
241+
expect(result.hint).toBeUndefined()
242+
// The idea command is handled separately by the idea subcommand handler
248243
})
249244
})
250245

0 commit comments

Comments
 (0)