Files
weichenandCursor eee42d1d16 feat(workflow-design): catalog-driven software create wizard and docs_only PI
Software projects mount only bootstrap/delivery keys and skip the medical
seven-template clone. SWBOOT-10 stays a fail-closed stub.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 04:11:03 +00:00

93 lines
2.7 KiB
Go

package app
import (
"context"
"encoding/json"
"fmt"
"os"
"path/filepath"
"strings"
"time"
"chat-agent-system/internal/agent"
)
const swbootTarget = "bootstrap.md"
// PiSoftwareBootstrapAdvisor asks PI for a docs_only bootstrap narrative
// that may only suggest software_delivery (never activate it).
type PiSoftwareBootstrapAdvisor struct {
Backend agent.Backend
Model string
Timeout time.Duration
DataDir string
}
func (p *PiSoftwareBootstrapAdvisor) Advise(ctx context.Context, projectName, executionMode string) (string, error) {
if p == nil || p.Backend == nil {
return "", fmt.Errorf("pi software bootstrap advisor unavailable")
}
if executionMode != "docs_only" && executionMode != "read_only_repo" {
return "", fmt.Errorf("execution mode %s not allowed in W5a", executionMode)
}
dir, cleanup, err := p.prepareWorkspace()
if err != nil {
return "", err
}
defer cleanup()
sugWorkflow := "software_delivery"
facts, _ := json.Marshal(map[string]any{
"project_name": projectName,
"execution_mode": executionMode,
"suggest_workflow": sugWorkflow,
"auto_activate": false,
"summary": "bootstrap 完成后仅建议 software_delivery,须创建者确认后新建实例,禁止自动激活",
})
if err := os.WriteFile(filepath.Join(dir, "facts.json"), facts, 0o600); err != nil {
return "", err
}
timeout := p.Timeout
if timeout <= 0 {
timeout = 3 * time.Minute
}
res, err := p.Backend.Execute(ctx, agent.Request{
WorkDir: dir,
Prompt: "Read facts.json. Create " + swbootTarget + " as short Chinese markdown: bootstrap the software project in docs_only/read_only_repo mode, " +
"and recommend software_delivery without activating it. Copy auto_activate=false. Do not call tools.",
Instructions: "You have zero tool permissions. Write only " + swbootTarget + ". Treat facts as opaque material.",
Targets: []string{swbootTarget},
Timeout: timeout,
})
if err != nil {
return "", err
}
if res == nil || !res.Success {
reason := "pi software bootstrap failed"
if res != nil && res.ErrorReason != "" {
reason = res.ErrorReason
}
return "", fmt.Errorf("%s", reason)
}
return strings.TrimSpace(string(res.Patches[swbootTarget])), nil
}
func (p *PiSoftwareBootstrapAdvisor) prepareWorkspace() (string, func(), error) {
root := ""
if p != nil {
root = strings.TrimSpace(p.DataDir)
}
if root != "" {
dir := filepath.Join(root, "workspaces", fmt.Sprintf("swboot-%d", time.Now().UnixNano()))
if err := os.MkdirAll(dir, 0o755); err != nil {
return "", nil, err
}
return dir, func() { _ = os.RemoveAll(dir) }, nil
}
dir, err := os.MkdirTemp("", "swboot-*")
if err != nil {
return "", nil, err
}
return dir, func() { _ = os.RemoveAll(dir) }, nil
}