Add context packs impact analysis and message validation
This commit is contained in:
@@ -12,6 +12,8 @@ $script:GspSubcommands = @(
|
||||
'trace',
|
||||
'flatten',
|
||||
'pack',
|
||||
'impact',
|
||||
'message',
|
||||
'graph',
|
||||
'stage-check',
|
||||
'help'
|
||||
@@ -26,7 +28,9 @@ $script:GspFlags = @{
|
||||
'index' = @('--root', '--out')
|
||||
'trace' = @('--root', '--depth', '--out')
|
||||
'flatten' = @('--root', '--depth', '--include-type', '--exclude-type', '--out')
|
||||
'pack' = @('--root', '--depth', '--budget', '--include-type', '--exclude-type', '--out')
|
||||
'pack' = @('--root', '--for', '--stage', '--depth', '--budget', '--format', '--include-type', '--exclude-type', '--out')
|
||||
'impact' = @('--root', '--depth', '--format', '--out')
|
||||
'message' = @('validate')
|
||||
'graph' = @('--root', '--depth', '--format', '--out')
|
||||
'stage-check' = @('--stage', '--root', '--out')
|
||||
}
|
||||
@@ -73,7 +77,11 @@ Register-ArgumentCompleter -Native -CommandName gsp -ScriptBlock {
|
||||
|
||||
switch ($previous) {
|
||||
'--format' {
|
||||
return @('json', 'mermaid', 'md', 'canvas') |
|
||||
$formats = @('json', 'md', 'canvas')
|
||||
if ($command -eq 'graph') {
|
||||
$formats = @('json', 'mermaid', 'md', 'canvas')
|
||||
}
|
||||
return $formats |
|
||||
Where-Object { $_ -like "$wordToComplete*" } |
|
||||
ForEach-Object { New-GspCompletion $_ }
|
||||
}
|
||||
@@ -87,6 +95,11 @@ Register-ArgumentCompleter -Native -CommandName gsp -ScriptBlock {
|
||||
Where-Object { $_ -like "$wordToComplete*" } |
|
||||
ForEach-Object { New-GspCompletion $_ }
|
||||
}
|
||||
'--for' {
|
||||
return @('design', 'implement', 'review', 'test', 'acceptance', 'handoff', 'inspect') |
|
||||
Where-Object { $_ -like "$wordToComplete*" } |
|
||||
ForEach-Object { New-GspCompletion $_ }
|
||||
}
|
||||
}
|
||||
|
||||
if ($command -eq 'completion') {
|
||||
@@ -106,7 +119,13 @@ Register-ArgumentCompleter -Native -CommandName gsp -ScriptBlock {
|
||||
ForEach-Object { New-GspCompletion $_ }
|
||||
}
|
||||
|
||||
if (@('trace', 'flatten', 'pack', 'graph') -contains $command) {
|
||||
if ($command -eq 'message') {
|
||||
return @($script:GspFlags[$command]) |
|
||||
Where-Object { $_ -like "$wordToComplete*" } |
|
||||
ForEach-Object { New-GspCompletion $_ }
|
||||
}
|
||||
|
||||
if (@('trace', 'flatten', 'pack', 'impact', 'graph') -contains $command) {
|
||||
return Get-GspIds |
|
||||
Where-Object { $_ -like "$wordToComplete*" } |
|
||||
ForEach-Object { New-GspCompletion $_ }
|
||||
@@ -125,11 +144,19 @@ _gsp_completion() {
|
||||
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
||||
cmd="${COMP_WORDS[1]}"
|
||||
local commands="init ai-init version completion validate index trace flatten pack graph stage-check help"
|
||||
local commands="init ai-init version completion validate index trace flatten pack impact message graph stage-check help"
|
||||
case "$prev" in
|
||||
--format) COMPREPLY=( $(compgen -W "json mermaid md canvas" -- "$cur") ); return ;;
|
||||
--format)
|
||||
if [[ "$cmd" == "graph" ]]; then
|
||||
COMPREPLY=( $(compgen -W "json mermaid md canvas" -- "$cur") )
|
||||
else
|
||||
COMPREPLY=( $(compgen -W "json md canvas" -- "$cur") )
|
||||
fi
|
||||
return
|
||||
;;
|
||||
--stage) COMPREPLY=( $(compgen -W "design integrate implement bind release" -- "$cur") ); return ;;
|
||||
--skill) COMPREPLY=( $(compgen -W "generic codex" -- "$cur") ); return ;;
|
||||
--for) COMPREPLY=( $(compgen -W "design implement review test acceptance handoff inspect" -- "$cur") ); return ;;
|
||||
esac
|
||||
if [[ $COMP_CWORD -eq 1 ]]; then
|
||||
COMPREPLY=( $(compgen -W "$commands" -- "$cur") )
|
||||
@@ -143,7 +170,9 @@ _gsp_completion() {
|
||||
validate|index) COMPREPLY=( $(compgen -W "--root --out" -- "$cur") ) ;;
|
||||
trace) COMPREPLY=( $(compgen -W "--root --depth --out" -- "$cur") ) ;;
|
||||
flatten) COMPREPLY=( $(compgen -W "--root --depth --include-type --exclude-type --out" -- "$cur") ) ;;
|
||||
pack) COMPREPLY=( $(compgen -W "--root --depth --budget --include-type --exclude-type --out" -- "$cur") ) ;;
|
||||
pack) COMPREPLY=( $(compgen -W "--root --for --stage --depth --budget --format --include-type --exclude-type --out" -- "$cur") ) ;;
|
||||
impact) COMPREPLY=( $(compgen -W "--root --depth --format --out" -- "$cur") ) ;;
|
||||
message) COMPREPLY=( $(compgen -W "validate" -- "$cur") ) ;;
|
||||
graph) COMPREPLY=( $(compgen -W "--root --depth --format --out" -- "$cur") ) ;;
|
||||
stage-check) COMPREPLY=( $(compgen -W "--stage --root --out" -- "$cur") ) ;;
|
||||
completion) COMPREPLY=( $(compgen -W "powershell bash zsh fish install" -- "$cur") ) ;;
|
||||
@@ -151,7 +180,7 @@ _gsp_completion() {
|
||||
return
|
||||
fi
|
||||
case "$cmd" in
|
||||
trace|flatten|pack|graph)
|
||||
trace|flatten|pack|impact|graph)
|
||||
local ids
|
||||
ids=$(gsp index --root . 2>/dev/null | sed -n 's/.*"id": "\([^"]*\)".*/\1/p')
|
||||
COMPREPLY=( $(compgen -W "$ids" -- "$cur") )
|
||||
@@ -177,6 +206,8 @@ _gsp() {
|
||||
'trace'
|
||||
'flatten'
|
||||
'pack'
|
||||
'impact'
|
||||
'message'
|
||||
'graph'
|
||||
'stage-check'
|
||||
'help'
|
||||
@@ -189,10 +220,12 @@ _gsp "$@"
|
||||
|
||||
func fishCompletionScript() string {
|
||||
return `# GSP fish completion
|
||||
complete -c gsp -f -n '__fish_use_subcommand' -a 'init ai-init version completion validate index trace flatten pack graph stage-check help'
|
||||
complete -c gsp -f -n '__fish_use_subcommand' -a 'init ai-init version completion validate index trace flatten pack impact message graph stage-check help'
|
||||
complete -c gsp -n '__fish_seen_subcommand_from graph' -l format -a 'json mermaid md canvas'
|
||||
complete -c gsp -n '__fish_seen_subcommand_from pack impact' -l format -a 'json md canvas'
|
||||
complete -c gsp -n '__fish_seen_subcommand_from stage-check' -l stage -a 'design integrate implement bind release'
|
||||
complete -c gsp -n '__fish_seen_subcommand_from ai-init' -l skill -a 'generic codex'
|
||||
complete -c gsp -n '__fish_seen_subcommand_from trace flatten pack graph' -a '(gsp index --root . 2>/dev/null | string match -r ''"id": "([^"]+)"'' | string replace -r ''.*"id": "([^"]+)".*'' ''$1'')'
|
||||
complete -c gsp -n '__fish_seen_subcommand_from pack' -l for -a 'design implement review test acceptance handoff inspect'
|
||||
complete -c gsp -n '__fish_seen_subcommand_from trace flatten pack impact graph' -a '(gsp index --root . 2>/dev/null | string match -r ''"id": "([^"]+)"'' | string replace -r ''.*"id": "([^"]+)".*'' ''$1'')'
|
||||
`
|
||||
}
|
||||
|
||||
@@ -48,6 +48,10 @@ func run(args []string) error {
|
||||
return runFlatten(args[1:])
|
||||
case "pack":
|
||||
return runPack(args[1:])
|
||||
case "impact":
|
||||
return runImpact(args[1:])
|
||||
case "message":
|
||||
return runMessage(args[1:])
|
||||
case "graph":
|
||||
return runGraph(args[1:])
|
||||
case "stage-check":
|
||||
@@ -73,7 +77,9 @@ Usage:
|
||||
gsp index [--root .] [--out index.json]
|
||||
gsp trace <id> [--root .] [--depth 3] [--out trace.json]
|
||||
gsp flatten <id> [--root .] [--depth 3] [--include-type a,b] [--exclude-type a,b] [--out flattened.json]
|
||||
gsp pack <id> [--root .] [--depth 3] [--budget 12000] [--out context-pack.json]
|
||||
gsp pack <id> [--root .] [--for implement] [--stage implement] [--depth 3] [--budget 12000] [--format json|md|canvas] [--out context-pack.json]
|
||||
gsp impact <id> [--root .] [--depth -1] [--format json|md|canvas] [--out impact.json]
|
||||
gsp message validate <file> [--root .] [--out message-report.json]
|
||||
gsp graph [id] [--root .] [--depth 3] [--format json|mermaid|md|canvas] [--out graph.json]
|
||||
gsp stage-check --stage implement [--root .] [--out stage-report.json]
|
||||
`)
|
||||
@@ -320,6 +326,9 @@ func runPack(args []string) error {
|
||||
out := commonOut(fs)
|
||||
depth := fs.Int("depth", 3, "maximum relation depth; -1 means unlimited")
|
||||
budget := fs.Int("budget", 0, "approximate JSON character budget; 0 means unlimited")
|
||||
intent := fs.String("for", "", "context purpose: design, implement, review, test, acceptance, handoff, or inspect")
|
||||
stage := fs.String("stage", "", "optional project stage")
|
||||
format := fs.String("format", "json", "json, md, or canvas")
|
||||
includeType := fs.String("include-type", "", "comma-separated type allow-list")
|
||||
excludeType := fs.String("exclude-type", "", "comma-separated type deny-list")
|
||||
if err := fs.Parse(normalizeFlagArgs(args)); err != nil {
|
||||
@@ -332,11 +341,91 @@ func runPack(args []string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
result := project.Pack(fs.Arg(0), *depth, *budget, gsp.Filter{
|
||||
result := project.PackFor(fs.Arg(0), *intent, *stage, *depth, *budget, gsp.Filter{
|
||||
IncludeTypes: splitCSV(*includeType),
|
||||
ExcludeTypes: splitCSV(*excludeType),
|
||||
})
|
||||
return writeJSON(*out, result)
|
||||
switch *format {
|
||||
case "json":
|
||||
return writeJSON(*out, result)
|
||||
case "md":
|
||||
return writeText(*out, result.Markdown())
|
||||
case "canvas":
|
||||
data, err := project.Graph(fs.Arg(0), *depth).Canvas()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return writeBytes(*out, data)
|
||||
default:
|
||||
return fmt.Errorf("unsupported pack format %q", *format)
|
||||
}
|
||||
}
|
||||
|
||||
func runImpact(args []string) error {
|
||||
fs := flag.NewFlagSet("impact", flag.ContinueOnError)
|
||||
root := commonRoot(fs)
|
||||
out := commonOut(fs)
|
||||
depth := fs.Int("depth", -1, "maximum reverse relation depth; -1 means unlimited")
|
||||
format := fs.String("format", "json", "json, md, or canvas")
|
||||
if err := fs.Parse(normalizeFlagArgs(args)); err != nil {
|
||||
return err
|
||||
}
|
||||
if fs.NArg() != 1 {
|
||||
return fmt.Errorf("impact requires one GSP id")
|
||||
}
|
||||
project, err := gsp.LoadProject(*root)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
result := project.Impact(fs.Arg(0), *depth)
|
||||
switch *format {
|
||||
case "json":
|
||||
return writeJSON(*out, result)
|
||||
case "md":
|
||||
return writeText(*out, result.Markdown())
|
||||
case "canvas":
|
||||
data, err := project.ImpactGraph(result).Canvas()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return writeBytes(*out, data)
|
||||
default:
|
||||
return fmt.Errorf("unsupported impact format %q", *format)
|
||||
}
|
||||
}
|
||||
|
||||
func runMessage(args []string) error {
|
||||
if len(args) == 0 {
|
||||
return fmt.Errorf("message requires validate")
|
||||
}
|
||||
switch args[0] {
|
||||
case "validate":
|
||||
return runMessageValidate(args[1:])
|
||||
default:
|
||||
return fmt.Errorf("unknown message command %q", args[0])
|
||||
}
|
||||
}
|
||||
|
||||
func runMessageValidate(args []string) error {
|
||||
fs := flag.NewFlagSet("message validate", flag.ContinueOnError)
|
||||
root := commonRoot(fs)
|
||||
out := commonOut(fs)
|
||||
if err := fs.Parse(normalizeFlagArgs(args)); err != nil {
|
||||
return err
|
||||
}
|
||||
if fs.NArg() != 1 {
|
||||
return fmt.Errorf("message validate requires one file")
|
||||
}
|
||||
project, err := gsp.LoadProject(*root)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
message, err := gsp.ReadMessage(project.Root, fs.Arg(0))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
report := project.ValidateMessage(message)
|
||||
return writeReport(*out, report)
|
||||
}
|
||||
|
||||
func runGraph(args []string) error {
|
||||
@@ -418,6 +507,7 @@ func normalizeFlagArgs(args []string) []string {
|
||||
"-budget": true, "--budget": true,
|
||||
"-format": true, "--format": true,
|
||||
"-stage": true, "--stage": true,
|
||||
"-for": true, "--for": true,
|
||||
"-name": true, "--name": true,
|
||||
"-entry": true, "--entry": true,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user