CLI-PR-001/002/003/004: Rename propose->proposal, add essential commands, improve accept, restrict story

- Rename 'propose' group to 'proposal' in surface, leaf help, and routing
- Keep 'hf propose' as backward-compatible alias via groupAliases
- Add essential subcommand group: list, create, update, delete
- Accept command now shows generated story tasks in output
- Accept command supports --json output
- Task create blocks story/* types with helpful error message
- All help text updated to use 'proposal' terminology
This commit is contained in:
zhi
2026-04-01 06:56:10 +00:00
parent fbfa866c9d
commit 97af3d3177
6 changed files with 404 additions and 21 deletions

View File

@@ -261,7 +261,22 @@ func RunProposeUpdate(proposeCode string, args []string, tokenFlag string) {
fmt.Printf("proposal updated: %s\n", proposeCode)
}
// RunProposeAccept implements `hf propose accept <propose-code> --milestone <milestone-code>`.
// acceptResponse holds the accept result including generated tasks.
type acceptResponse struct {
ProposalCode string `json:"proposal_code"`
Status string `json:"status"`
GeneratedTasks []generatedTask `json:"generated_tasks"`
}
type generatedTask struct {
TaskID int `json:"task_id"`
TaskCode *string `json:"task_code"`
Title string `json:"title"`
TaskType string `json:"task_type"`
TaskSubtype *string `json:"task_subtype"`
}
// RunProposeAccept implements `hf proposal accept <proposal-code> --milestone <milestone-code>`.
func RunProposeAccept(proposeCode string, args []string, tokenFlag string) {
token := ResolveToken(tokenFlag)
@@ -280,7 +295,7 @@ func RunProposeAccept(proposeCode string, args []string, tokenFlag string) {
}
if milestone == "" {
output.Error("usage: hf propose accept <propose-code> --milestone <milestone-code>")
output.Error("usage: hf proposal accept <proposal-code> --milestone <milestone-code>")
}
payload := map[string]interface{}{
@@ -296,12 +311,38 @@ func RunProposeAccept(proposeCode string, args []string, tokenFlag string) {
output.Errorf("config error: %v", err)
}
c := client.New(cfg.BaseURL, token)
_, err = c.Post("/proposes/"+proposeCode+"/accept", bytes.NewReader(body))
data, err := c.Post("/proposes/"+proposeCode+"/accept", bytes.NewReader(body))
if err != nil {
output.Errorf("failed to accept proposal: %v", err)
}
if output.JSONMode {
var raw json.RawMessage
if err := json.Unmarshal(data, &raw); err != nil {
output.Errorf("invalid JSON response: %v", err)
}
output.PrintJSON(raw)
return
}
fmt.Printf("proposal accepted: %s\n", proposeCode)
// Try to parse and display generated tasks
var resp acceptResponse
if err := json.Unmarshal(data, &resp); err == nil && len(resp.GeneratedTasks) > 0 {
fmt.Printf("\nGenerated %d story task(s):\n", len(resp.GeneratedTasks))
for _, gt := range resp.GeneratedTasks {
code := ""
if gt.TaskCode != nil {
code = *gt.TaskCode
}
subtype := ""
if gt.TaskSubtype != nil {
subtype = "/" + *gt.TaskSubtype
}
fmt.Printf(" %s %s%s %s\n", code, gt.TaskType, subtype, gt.Title)
}
}
}
// RunProposeReject implements `hf propose reject <propose-code>`.