Add context packs impact analysis and message validation

This commit is contained in:
2026-05-07 10:17:24 +08:00
parent f2d0a83705
commit 0c5254eb1b
18 changed files with 780 additions and 13 deletions

View File

@@ -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,
}