@@ -2,6 +2,19 @@ import type { LocalCommandResult } from '../../commands.js'
22import type { ToolUseContext } from '../../Tool.js'
33import type { PopOptions } from '../../services/pushStack/state.js'
44
5+ /**
6+ * Parses a marker argument (`#N` or `N`) into a positive ordinal. Rejects any
7+ * input that is not a pure integer — `Number.parseInt` would otherwise silently
8+ * accept `2junk` (→2) or `1.5` (→1) and pop the wrong branch. Returns null on
9+ * any malformed value.
10+ */
11+ function parseMarkerOrdinal ( raw : string ) : number | null {
12+ const digits = raw . replace ( / ^ # / , '' )
13+ if ( ! / ^ \d + $ / . test ( digits ) ) return null
14+ const n = Number . parseInt ( digits , 10 )
15+ return Number . isInteger ( n ) && n >= 1 ? n : null
16+ }
17+
518/**
619 * Parses `/pop` flags into PopOptions. Recognized:
720 * --to #N | --to N cross-layer pop back to marker ordinal N (§4.7)
@@ -22,12 +35,12 @@ export function parsePopArgs(args: string): PopOptions | string {
2235 const next = tokens [ ++ i ]
2336 if ( next === undefined )
2437 return 'Missing marker number after --to (e.g. /pop --to #1).'
25- const n = Number . parseInt ( next . replace ( / ^ # / , '' ) , 10 )
26- if ( ! Number . isInteger ( n ) || n < 1 ) return `Invalid marker number: ${ next } `
38+ const n = parseMarkerOrdinal ( next )
39+ if ( n === null ) return `Invalid marker number: ${ next } `
2740 opts . to = n
2841 } else if ( tok . startsWith ( '--to=' ) ) {
29- const n = Number . parseInt ( tok . slice ( '--to=' . length ) . replace ( / ^ # / , '' ) , 10 )
30- if ( ! Number . isInteger ( n ) || n < 1 ) return `Invalid marker number: ${ tok } `
42+ const n = parseMarkerOrdinal ( tok . slice ( '--to=' . length ) )
43+ if ( n === null ) return `Invalid marker number: ${ tok } `
3144 opts . to = n
3245 } else {
3346 return `Unknown option: ${ tok } `
0 commit comments