(args []string)
| 29 | } |
| 30 | |
| 31 | func cmdRunPlaybook(args []string) int { |
| 32 | if len(args) == 0 { |
| 33 | fmt.Fprintln(os.Stderr, "error: run playbook requires a slug") |
| 34 | return 2 |
| 35 | } |
| 36 | slug := args[0] |
| 37 | fs := flagSet("run playbook") |
| 38 | dangerSkip := fs.Bool("dangerously-skip-permissions", false, "skip per-tool approval prompts in the spawned harness (ignored when --here is set)") |
| 39 | here := fs.Bool("here", false, "bind THIS Claude session to the new playbook run (no new tab); requires running inside a Claude Code session") |
| 40 | auto := fs.Bool("auto", false, "run the playbook headlessly in the background (no tab, no human); the run self-completes via `flow done`") |
| 41 | withInstr := fs.String("with", "", "inject `<instruction>` as the run session's first user message (forwarded to flow do)") |
| 42 | withFile := fs.String("with-file", "", "inject 'read instructions at <path>' (forwarded to flow do)") |
| 43 | if err := fs.Parse(args[1:]); err != nil { |
| 44 | return 2 |
| 45 | } |
| 46 | |
| 47 | // Reject misuse before we materialize the run-task row. |
| 48 | if _, rc := loadInjectionText(fs, *withInstr, *withFile); rc != 0 { |
| 49 | return rc |
| 50 | } |
| 51 | if (*withInstr != "" || *withFile != "") && *here { |
| 52 | fmt.Fprintln(os.Stderr, "error: --with/--with-file cannot be used with --here (no session is spawned to inject into)") |
| 53 | return 2 |
| 54 | } |
| 55 | if *auto && *here { |
| 56 | fmt.Fprintln(os.Stderr, "error: --auto cannot be used with --here (--auto launches its own detached session)") |
| 57 | return 2 |
| 58 | } |
| 59 | // --auto + --with/--with-file IS allowed: the instruction rides along to |
| 60 | // the detached run (e.g. a scheduled playbook that today should also |
| 61 | // double-check something). The delegation below forwards both flags. |
| 62 | |
| 63 | dbPath, err := flowDBPath() |
| 64 | if err != nil { |
| 65 | fmt.Fprintf(os.Stderr, "error: %v\n", err) |
| 66 | return 1 |
| 67 | } |
| 68 | db, err := openConcurrentDB(dbPath) |
| 69 | if err != nil { |
| 70 | fmt.Fprintf(os.Stderr, "error: %v\n", err) |
| 71 | return 1 |
| 72 | } |
| 73 | defer db.Close() |
| 74 | |
| 75 | pb, err := ResolvePlaybook(db, slug, false) |
| 76 | if err != nil { |
| 77 | fmt.Fprintf(os.Stderr, "error: %v\n", err) |
| 78 | return 1 |
| 79 | } |
| 80 | |
| 81 | // --here validation BEFORE the run-task row insert. Mirrors the |
| 82 | // pre-write checks in cmdDoHere — failing fast prevents a dangling |
| 83 | // backlog playbook_run task when env is wrong or this session is |
| 84 | // already owned by another task. |
| 85 | if *here { |
| 86 | h := defaultHarness() |
| 87 | sid := currentSessionID() |
| 88 | if sid == "" { |
no test coverage detected