feat(cmd/s): implement session start

Amolith and Crush created

Start command is the entry point for creating directory-scoped sessions.

- Replace stub with full implementation
- Handle AlreadyActiveError with helpful message
- Print next steps after session creation

Co-authored-by: Crush <crush@charm.land>

Change summary

cmd/s.go | 54 ++++++++++++++++++++++++++++++++++++++++++++----------
1 file changed, 44 insertions(+), 10 deletions(-)

Detailed changes

cmd/s.go 🔗

@@ -5,8 +5,11 @@
 package cmd
 
 import (
+	"errors"
 	"fmt"
+	"os"
 
+	"git.secluded.site/np/internal/session"
 	"github.com/spf13/cobra"
 )
 
@@ -14,21 +17,52 @@ var sCmd = &cobra.Command{
 	Use:   "s",
 	Short: "Start session",
 	Long:  `Start a new working-directory-scoped session`,
-	Run: func(cmd *cobra.Command, args []string) {
-		fmt.Println("[STUB] Start new working-directory-scoped session")
-	},
+	RunE:  runStartSession,
 }
 
 func init() {
 	rootCmd.AddCommand(sCmd)
+}
+
+func runStartSession(cmd *cobra.Command, args []string) error {
+	env, err := requireEnvironment()
+	if err != nil {
+		return err
+	}
+
+	ctx := cmd.Context()
+	cwd, err := os.Getwd()
+	if err != nil {
+		return fmt.Errorf("determine working directory: %w", err)
+	}
+
+	doc, err := env.SessionStore.Start(ctx, cwd)
+	if err != nil {
+		var already session.AlreadyActiveError
+		if errors.As(err, &already) {
+			return printExistingSession(cmd, already.Session)
+		}
+		return err
+	}
 
-	// Here you will define your flags and configuration settings.
+	printSessionStarted(cmd, doc)
+	return nil
+}
+
+func printExistingSession(cmd *cobra.Command, existing session.Document) error {
+	out := cmd.OutOrStdout()
+	fmt.Fprintf(out, "Session %s is already active for %s.\n", existing.SID, existing.DirPath)
+	fmt.Fprintln(out, "There's already an active session for this directory; ask your operator whether they want to resume or archive it.")
+	return nil
+}
 
-	// Cobra supports Persistent Flags which will work for this command
-	// and all subcommands, e.g.:
-	// sCmd.PersistentFlags().String("foo", "", "A help for foo")
+func printSessionStarted(cmd *cobra.Command, doc session.Document) {
+	out := cmd.OutOrStdout()
+	fmt.Fprintf(out, "Session %s is now active for %s.\n\n", doc.SID, doc.DirPath)
 
-	// Cobra supports local flags which will only run when this command
-	// is called directly, e.g.:
-	// sCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
+	fmt.Fprintln(out, "Set the goal immediately with `np g s -t \"goal title\" -d \"goal description\"`.")
+	fmt.Fprintln(out, "Include ticket numbers, file paths, and any other references inside the goal description.")
+	fmt.Fprintln(out, "Once the goal is set, read the referenced files and add tasks with `np t a -t \"task\" -d \"details\"`.")
+	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.")
+	fmt.Fprintln(out, "Use `np p` whenever you need to review the full plan.")
 }