1// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
2//
3// SPDX-License-Identifier: AGPL-3.0-or-later
4
5package cmd
6
7import (
8 "errors"
9 "fmt"
10 "os"
11
12 "git.secluded.site/np/internal/session"
13 "github.com/spf13/cobra"
14)
15
16var sCmd = &cobra.Command{
17 Use: "s",
18 Short: "Start session",
19 Long: `Start a new working-directory-scoped session`,
20 RunE: runStartSession,
21}
22
23func init() {
24 rootCmd.AddCommand(sCmd)
25}
26
27func runStartSession(cmd *cobra.Command, args []string) error {
28 env, err := requireEnvironment()
29 if err != nil {
30 return err
31 }
32
33 ctx := cmd.Context()
34 cwd, err := os.Getwd()
35 if err != nil {
36 return fmt.Errorf("determine working directory: %w", err)
37 }
38
39 doc, err := env.SessionStore.Start(ctx, cwd)
40 if err != nil {
41 var already session.AlreadyActiveError
42 if errors.As(err, &already) {
43 return printExistingSession(cmd, already.Session)
44 }
45 return err
46 }
47
48 printSessionStarted(cmd, doc)
49 return nil
50}
51
52func printExistingSession(cmd *cobra.Command, existing session.Document) error {
53 out := cmd.OutOrStdout()
54 fmt.Fprintf(out, "Session %s is already active for %s.\n", existing.SID, existing.DirPath)
55 fmt.Fprintln(out, "There's already an active session for this directory; ask your operator whether they want to resume or archive it.")
56 return nil
57}
58
59func printSessionStarted(cmd *cobra.Command, doc session.Document) {
60 out := cmd.OutOrStdout()
61 fmt.Fprintf(out, "Session %s is now active for %s.\n\n", doc.SID, doc.DirPath)
62
63 fmt.Fprintln(out, "Set the goal immediately with `np g s -t \"goal title\" -d \"goal description\"`.")
64 fmt.Fprintln(out, "Include ticket numbers, file paths, and any other references inside the goal description.")
65 fmt.Fprintln(out, "Once the goal is set, read the referenced files and add tasks with `np t a -t \"task\" -d \"details\"`.")
66 fmt.Fprintln(out, "Keep task statuses up to date with `np t u -i task-id -s in_progress|completed|failed|cancelled` as you work.")
67 fmt.Fprintln(out, "Use `np p` whenever you need to review the full plan.")
68}