← back to Cli Printing Press
feat(cli): flag empty defaultSyncResources at dogfood time (#1633)
042a78d494058fb5d80000bba1b1cfc379e1d2b2 · 2026-05-18 12:24:41 -0700 · Trevin Chow
* feat(cli): flag empty defaultSyncResources at dogfood time
When a spec exposes no bulk-list endpoint (only parameterized detail pages and
required-query searches, e.g. Allrecipes), the profiler correctly produces an
empty SyncableResources slice, but the generator still emits `sync` as a
runtime no-op alongside store-dependent novel commands (cookbook, pantry,
top-rated, ...). The CLI ships with no advertised path to populate the store.
Add a dogfood pipeline_check signal that detects the empty-list emission of
defaultSyncResources() in the generated sync.go and surfaces it as WARN so the
gap is visible at shipcheck time. Also emit a one-line runtime hint (stderr
in human mode, sync_warning JSON event in agent mode) when the structural
precondition holds, so callers see "no bulk-list endpoints in spec; populate
the store via single-fetch commands" instead of a silent total_records:0.
Closes #1156
* fix(cli): always emit sync_file_emitted in pipeline_check JSON
Greptile flagged a JSON-tag asymmetry on PipelineResult: SyncFileEmitted
carried `omitempty` but SyncResourcesPresent did not, so when sync.go is
absent a downstream consumer sees `sync_resources_present: false` with no
sync_file_emitted signal, which incorrectly reads as "should have resources
but does not." Drop the `omitempty` so both fields always appear together
and consumers can disambiguate the three real states:
sync_file_emitted=false, sync_resources_present=false no sync surface
sync_file_emitted=true, sync_resources_present=true healthy
sync_file_emitted=true, sync_resources_present=false empty (issue #1156)
Files touched
M internal/generator/sync_param_passthrough_test.goM internal/generator/templates/sync.go.tmplM internal/pipeline/dogfood.goM internal/pipeline/dogfood_test.goM testdata/golden/expected/dogfood-verdict-matrix/fail-path-auth-dead.jsonM testdata/golden/expected/dogfood-verdict-matrix/pass.jsonM testdata/golden/expected/dogfood-verdict-matrix/warn-priority.jsonM testdata/golden/expected/generate-golden-api/dogfood.json
Diff
commit 042a78d494058fb5d80000bba1b1cfc379e1d2b2
Author: Trevin Chow <trevin@trevinchow.com>
Date: Mon May 18 12:24:41 2026 -0700
feat(cli): flag empty defaultSyncResources at dogfood time (#1633)
* feat(cli): flag empty defaultSyncResources at dogfood time
When a spec exposes no bulk-list endpoint (only parameterized detail pages and
required-query searches, e.g. Allrecipes), the profiler correctly produces an
empty SyncableResources slice, but the generator still emits `sync` as a
runtime no-op alongside store-dependent novel commands (cookbook, pantry,
top-rated, ...). The CLI ships with no advertised path to populate the store.
Add a dogfood pipeline_check signal that detects the empty-list emission of
defaultSyncResources() in the generated sync.go and surfaces it as WARN so the
gap is visible at shipcheck time. Also emit a one-line runtime hint (stderr
in human mode, sync_warning JSON event in agent mode) when the structural
precondition holds, so callers see "no bulk-list endpoints in spec; populate
the store via single-fetch commands" instead of a silent total_records:0.
Closes #1156
* fix(cli): always emit sync_file_emitted in pipeline_check JSON
Greptile flagged a JSON-tag asymmetry on PipelineResult: SyncFileEmitted
carried `omitempty` but SyncResourcesPresent did not, so when sync.go is
absent a downstream consumer sees `sync_resources_present: false` with no
sync_file_emitted signal, which incorrectly reads as "should have resources
but does not." Drop the `omitempty` so both fields always appear together
and consumers can disambiguate the three real states:
sync_file_emitted=false, sync_resources_present=false no sync surface
sync_file_emitted=true, sync_resources_present=true healthy
sync_file_emitted=true, sync_resources_present=false empty (issue #1156)
---
internal/generator/sync_param_passthrough_test.go | 88 +++++++++++++++
internal/generator/templates/sync.go.tmpl | 16 +++
internal/pipeline/dogfood.go | 60 +++++++++-
internal/pipeline/dogfood_test.go | 124 ++++++++++++++++++++-
.../fail-path-auth-dead.json | 4 +-
.../expected/dogfood-verdict-matrix/pass.json | 4 +-
.../dogfood-verdict-matrix/warn-priority.json | 4 +-
.../expected/generate-golden-api/dogfood.json | 4 +-
8 files changed, 295 insertions(+), 9 deletions(-)
diff --git a/internal/generator/sync_param_passthrough_test.go b/internal/generator/sync_param_passthrough_test.go
index 44433b25..48e2283b 100644
--- a/internal/generator/sync_param_passthrough_test.go
+++ b/internal/generator/sync_param_passthrough_test.go
@@ -233,3 +233,91 @@ func TestGenerateSyncDependentErrorNotSilent(t *testing.T) {
assert.Contains(t, syncSrc, "syncErrorJSON(dep.Name, parentID, err)",
"dependent-resource non-warning error must emit a sync_error JSON event with the parent ID")
}
+
+// noBulkListSpec mirrors the Allrecipes shape (issue #1156): a resource whose
+// only GET endpoints are a parameterized detail page and a search with a
+// required query param. Neither qualifies as a syncable list endpoint, so
+// the generator's profile lands SyncableResources empty.
+func noBulkListSpec(name string) *spec.APISpec {
+ apiSpec := minimalSpec(name)
+ apiSpec.Resources = map[string]spec.Resource{
+ "recipes": {
+ Description: "Recipes",
+ Endpoints: map[string]spec.Endpoint{
+ "get": {
+ Method: "GET",
+ Path: "/recipe/{recipe_id}/{slug}",
+ Params: []spec.Param{
+ {Name: "recipe_id", PathParam: true, Required: true, Type: "string"},
+ {Name: "slug", PathParam: true, Required: true, Type: "string"},
+ },
+ Response: spec.ResponseDef{Type: "object", Item: "Recipe"},
+ },
+ "search": {
+ Method: "GET",
+ Path: "/search",
+ Params: []spec.Param{
+ {Name: "q", Required: true, Type: "string"},
+ },
+ Response: spec.ResponseDef{Type: "array"},
+ },
+ },
+ },
+ }
+ return apiSpec
+}
+
+// TestGenerateSyncEmitsEmptyHintWhenNoBulkList covers issue #1156. When a spec
+// has no bulk-list endpoint (only parameterized detail pages and required-
+// query searches), defaultSyncResources renders empty and the runtime sync
+// command is a no-op. The template must emit a clear hint so users and agents
+// understand the silence and can find the population path (single-fetch
+// commands writing to the store).
+func TestGenerateSyncEmitsEmptyHintWhenNoBulkList(t *testing.T) {
+ t.Parallel()
+
+ apiSpec := noBulkListSpec("nobulk")
+ outputDir := filepath.Join(t.TempDir(), naming.CLI(apiSpec.Name))
+ require.NoError(t, New(apiSpec, outputDir).Generate())
+
+ syncGo, err := os.ReadFile(filepath.Join(outputDir, "internal", "cli", "sync.go"))
+ require.NoError(t, err)
+ syncSrc := string(syncGo)
+
+ // Sanity: the structural precondition matches Allrecipes shape with both
+ // syncable and dependent slices empty, so defaultSyncResources renders
+ // with an empty body.
+ assert.Regexp(t,
+ `func defaultSyncResources\(\) \[\]string \{\s*return \[\]string\{\}\s*\}`,
+ syncSrc,
+ "defaultSyncResources should be empty for a spec with no bulk-list endpoints",
+ )
+
+ // The runtime hint surfaces in both modes so JSON-driven agents and human
+ // callers both see the explanation instead of a silent total_records:0.
+ assert.Contains(t, syncSrc, "no bulk-list endpoints",
+ "sync should print a stderr hint when defaultSyncResources is empty")
+ assert.Contains(t, syncSrc, `"reason":"no_bulk_list_endpoints"`,
+ "sync should emit a sync_warning JSON event when defaultSyncResources is empty")
+}
+
+// TestGenerateSyncSkipsEmptyHintWhenBulkListExists ensures the template hint
+// is template-time conditional and does not appear when the spec exposes at
+// least one syncable resource. Without this guard, every CLI would carry the
+// dead branch.
+func TestGenerateSyncSkipsEmptyHintWhenBulkListExists(t *testing.T) {
+ t.Parallel()
+
+ apiSpec := minimalSpec("withbulk")
+ outputDir := filepath.Join(t.TempDir(), naming.CLI(apiSpec.Name))
+ require.NoError(t, New(apiSpec, outputDir).Generate())
+
+ syncGo, err := os.ReadFile(filepath.Join(outputDir, "internal", "cli", "sync.go"))
+ require.NoError(t, err)
+ syncSrc := string(syncGo)
+
+ assert.NotContains(t, syncSrc, "no bulk-list endpoints",
+ "sync should not carry the empty-list hint when a syncable resource exists")
+ assert.NotContains(t, syncSrc, `"reason":"no_bulk_list_endpoints"`,
+ "sync should not emit the no_bulk_list_endpoints event when a syncable resource exists")
+}
diff --git a/internal/generator/templates/sync.go.tmpl b/internal/generator/templates/sync.go.tmpl
index b55d02cb..312a10fa 100644
--- a/internal/generator/templates/sync.go.tmpl
+++ b/internal/generator/templates/sync.go.tmpl
@@ -156,6 +156,22 @@ Resource scoping:
if len(resources) == 0 {
resources = defaultSyncResources()
}
+{{- if and (not .SyncableResources) (not .DependentSyncResources)}}
+
+ // Empty-sync hint: this spec exposed no bulk-list endpoint and no
+ // dependent resources, so `sync` cannot populate the store on its
+ // own. Emit a one-line note so users and agents understand the
+ // runtime no-op instead of seeing only `total_records: 0`. The
+ // store is still populated by single-fetch commands (recipe, get,
+ // fetch, …) that the spec's other resources define.
+ if len(resources) == 0 {
+ if humanFriendly {
+ fmt.Fprintln(os.Stderr, "{{.Name}}-pp-cli sync: no bulk-list endpoints in spec; populate the store via single-fetch commands instead.")
+ } else {
+ fmt.Fprintln(os.Stdout, `{"event":"sync_warning","reason":"no_bulk_list_endpoints","detail":"no bulk-list endpoints in spec; populate the store via single-fetch commands"}`)
+ }
+ }
+{{- end}}
// Reject --resource-param keys that don't match a known resource.
// Validates against the full top-level + dependent set, not the
diff --git a/internal/pipeline/dogfood.go b/internal/pipeline/dogfood.go
index 763dd05c..b063f8db 100644
--- a/internal/pipeline/dogfood.go
+++ b/internal/pipeline/dogfood.go
@@ -123,10 +123,12 @@ type DeadCodeResult struct {
}
type PipelineResult struct {
- SyncCallsDomain bool `json:"sync_calls_domain"`
- SearchCallsDomain bool `json:"search_calls_domain"`
- DomainTables int `json:"domain_tables"`
- Detail string `json:"detail"`
+ SyncCallsDomain bool `json:"sync_calls_domain"`
+ SearchCallsDomain bool `json:"search_calls_domain"`
+ DomainTables int `json:"domain_tables"`
+ SyncFileEmitted bool `json:"sync_file_emitted"`
+ SyncResourcesPresent bool `json:"sync_resources_present"`
+ Detail string `json:"detail"`
}
type ExampleCheckResult struct {
@@ -1460,6 +1462,8 @@ func checkPipelineIntegrity(dir string) PipelineResult {
result.SyncCallsDomain = domainUpsertRe.MatchString(syncSource)
result.SearchCallsDomain = domainSearchRe.MatchString(searchSource)
result.DomainTables = countDomainTables(storeSource)
+ result.SyncFileEmitted = syncSource != ""
+ result.SyncResourcesPresent = hasPopulatedSyncResources(syncSource)
var parts []string
switch {
@@ -1484,10 +1488,48 @@ func checkPipelineIntegrity(dir string) PipelineResult {
parts = append(parts, fmt.Sprintf("%d domain tables found", result.DomainTables))
}
+ // When sync.go is emitted but defaultSyncResources() returns an empty list,
+ // the sync command is a no-op at runtime. Store-dependent novel commands
+ // (cookbook, pantry, top-rated, …) then ship with no advertised path to
+ // populate the store. Flag so the absence surfaces at shipcheck time.
+ if syncSource != "" && !result.SyncResourcesPresent {
+ parts = append(parts, "defaultSyncResources empty (sync command is a no-op)")
+ }
+
result.Detail = strings.Join(parts, "; ")
return result
}
+// defaultSyncResourcesEmptyRe matches the generator's empty-list emission for
+// defaultSyncResources, after gofmt collapses `return []string{\n}` to a single
+// line. Matching the open-brace through the literal "}" keeps the check robust
+// against trailing whitespace and the gofmt-aware "\n\t}" form some emitters
+// produce when the template body has a leading newline.
+var defaultSyncResourcesEmptyRe = regexp.MustCompile(
+ `(?s)func\s+defaultSyncResources\s*\(\s*\)\s*\[\]string\s*\{\s*return\s+\[\]string\{\s*\}\s*\}`,
+)
+
+// hasPopulatedSyncResources reports whether the emitted sync.go declares at
+// least one syncable resource via the defaultSyncResources() helper. Returns
+// true when defaultSyncResources is either absent (hand-rolled or test
+// fixture sync surfaces are not the failure mode this check targets) or
+// present with at least one entry. Returns false only when the helper is
+// emitted with an explicit empty-list body `return []string{}`. Used by
+// dogfood's pipeline check to surface CLIs that emit a sync command with
+// nothing to sync: the failure mode where store-dependent novel commands
+// have no advertised population path.
+func hasPopulatedSyncResources(syncSource string) bool {
+ if syncSource == "" {
+ return false
+ }
+ if !strings.Contains(syncSource, "func defaultSyncResources") {
+ // No generator-emitted helper to inspect. Treat as "not the failure
+ // mode" rather than risking false positives on hand-rolled sync.
+ return true
+ }
+ return !defaultSyncResourcesEmptyRe.MatchString(syncSource)
+}
+
type dogfoodVerdictRule struct {
verdict string
match func(*DogfoodReport, bool) bool
@@ -1508,6 +1550,13 @@ var dogfoodVerdictRules = []dogfoodVerdictRule{
{"WARN", func(r *DogfoodReport, _ bool) bool { return r.DeadFlags.Dead >= 1 && r.DeadFlags.Dead <= 2 }},
{"WARN", func(r *DogfoodReport, _ bool) bool { return r.DeadFuncs.Dead >= 1 }},
{"WARN", func(r *DogfoodReport, _ bool) bool { return !r.PipelineCheck.SyncCallsDomain }},
+ {"WARN", func(r *DogfoodReport, _ bool) bool {
+ // Issue #1156: when defaultSyncResources is emitted empty, the sync
+ // command is a runtime no-op and store-dependent novel commands have
+ // no advertised path to populate the store. Promote to WARN so the
+ // gap surfaces at shipcheck time rather than after publish.
+ return r.PipelineCheck.SyncFileEmitted && !r.PipelineCheck.SyncResourcesPresent
+ }},
{"WARN", func(r *DogfoodReport, _ bool) bool { return len(r.ExampleCheck.InvalidFlags) > 0 }},
{"WARN", func(r *DogfoodReport, _ bool) bool { return r.ExampleCheck.Skipped }},
{"FAIL", func(r *DogfoodReport, _ bool) bool { return len(r.WiringCheck.CommandTree.Unregistered) > 0 }},
@@ -1562,6 +1611,9 @@ func collectDogfoodIssues(report *DogfoodReport, hasSpec bool) []string {
if !report.PipelineCheck.SyncCallsDomain {
issues = append(issues, "sync uses generic Upsert only")
}
+ if report.PipelineCheck.SyncFileEmitted && !report.PipelineCheck.SyncResourcesPresent {
+ issues = append(issues, "defaultSyncResources empty: sync command is a runtime no-op; store-dependent novel commands have no advertised population path")
+ }
if report.ExampleCheck.Tested > 0 && (report.ExampleCheck.WithExamples*100/report.ExampleCheck.Tested) < 50 {
issues = append(issues, fmt.Sprintf("%d%% example coverage", report.ExampleCheck.WithExamples*100/report.ExampleCheck.Tested))
}
diff --git a/internal/pipeline/dogfood_test.go b/internal/pipeline/dogfood_test.go
index 2ccebbfe..306c163f 100644
--- a/internal/pipeline/dogfood_test.go
+++ b/internal/pipeline/dogfood_test.go
@@ -215,13 +215,126 @@ CREATE TABLE IF NOT EXISTS sync_state (
assert.Equal(t, 1, countDomainTables(storeSource))
}
+// TestCheckPipelineIntegritySyncResourcesEmpty asserts that when the generator
+// emits sync.go with an empty defaultSyncResources() body (the structural
+// signature of an API with no bulk-list endpoint, e.g., Allrecipes), dogfood's
+// pipeline check records SyncFileEmitted=true and SyncResourcesPresent=false
+// and surfaces the detail string. Issue #1156.
+func TestCheckPipelineIntegritySyncResourcesEmpty(t *testing.T) {
+ dir := t.TempDir()
+ require.NoError(t, os.MkdirAll(filepath.Join(dir, "internal", "cli"), 0o755))
+ require.NoError(t, os.MkdirAll(filepath.Join(dir, "internal", "store"), 0o755))
+
+ writeTestFile(t, filepath.Join(dir, "internal", "cli", "sync.go"), `package cli
+
+func runSync(s interface{ UpsertItems() error }) error {
+ return s.UpsertItems()
+}
+
+func defaultSyncResources() []string {
+ return []string{}
+}
+`)
+ writeTestFile(t, filepath.Join(dir, "internal", "store", "store.go"), "package store\n")
+
+ result := checkPipelineIntegrity(dir)
+ assert.True(t, result.SyncFileEmitted, "sync.go was written")
+ assert.False(t, result.SyncResourcesPresent, "defaultSyncResources is empty")
+ assert.Contains(t, result.Detail, "defaultSyncResources empty")
+}
+
+// TestCheckPipelineIntegritySyncResourcesPopulated covers the normal case where
+// the generator emits sync.go with one or more resources. Both new fields
+// should be set; the empty-list detail string should not appear.
+func TestCheckPipelineIntegritySyncResourcesPopulated(t *testing.T) {
+ dir := t.TempDir()
+ require.NoError(t, os.MkdirAll(filepath.Join(dir, "internal", "cli"), 0o755))
+ require.NoError(t, os.MkdirAll(filepath.Join(dir, "internal", "store"), 0o755))
+
+ writeTestFile(t, filepath.Join(dir, "internal", "cli", "sync.go"), `package cli
+
+func runSync(s interface{ UpsertUsers() error }) error {
+ return s.UpsertUsers()
+}
+
+func defaultSyncResources() []string {
+ return []string{
+ "users",
+ }
+}
+`)
+ writeTestFile(t, filepath.Join(dir, "internal", "store", "store.go"), "package store\n")
+
+ result := checkPipelineIntegrity(dir)
+ assert.True(t, result.SyncFileEmitted)
+ assert.True(t, result.SyncResourcesPresent)
+ assert.NotContains(t, result.Detail, "defaultSyncResources empty")
+}
+
+func TestHasPopulatedSyncResources(t *testing.T) {
+ tests := []struct {
+ name string
+ src string
+ want bool
+ }{
+ {
+ name: "empty source",
+ src: "",
+ want: false,
+ },
+ {
+ name: "helper absent (hand-rolled or fixture)",
+ src: "package cli\nfunc runSync() {}\n",
+ want: true,
+ },
+ {
+ name: "helper present with empty list",
+ src: `package cli
+func defaultSyncResources() []string {
+ return []string{}
+}
+`,
+ want: false,
+ },
+ {
+ name: "helper present with one entry",
+ src: `package cli
+func defaultSyncResources() []string {
+ return []string{
+ "users",
+ }
+}
+`,
+ want: true,
+ },
+ {
+ name: "helper present with several entries",
+ src: `package cli
+func defaultSyncResources() []string {
+ return []string{
+ "commissions",
+ "customers",
+ "domains",
+ }
+}
+`,
+ want: true,
+ },
+ }
+ for _, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ assert.Equal(t, tc.want, hasPopulatedSyncResources(tc.src))
+ })
+ }
+}
+
func TestDeriveDogfoodVerdict(t *testing.T) {
report := &DogfoodReport{
PathCheck: PathCheckResult{Tested: 10, Valid: 10, Pct: 100},
AuthCheck: AuthCheckResult{Match: true},
DeadFlags: DeadCodeResult{Dead: 1},
DeadFuncs: DeadCodeResult{Dead: 0},
- PipelineCheck: PipelineResult{SyncCallsDomain: true},
+ PipelineCheck: PipelineResult{SyncCallsDomain: true, SyncResourcesPresent: true},
}
assert.Equal(t, "WARN", deriveDogfoodVerdict(report, true))
@@ -236,6 +349,15 @@ func TestDeriveDogfoodVerdict(t *testing.T) {
report.PipelineCheck.SyncCallsDomain = true
assert.Equal(t, "PASS", deriveDogfoodVerdict(report, true))
+ // Issue #1156: when sync.go is emitted but defaultSyncResources is empty,
+ // the sync command is a runtime no-op. Dogfood must flag this as WARN so
+ // the gap surfaces at shipcheck time.
+ report.PipelineCheck.SyncFileEmitted = true
+ report.PipelineCheck.SyncResourcesPresent = false
+ assert.Equal(t, "WARN", deriveDogfoodVerdict(report, true))
+ report.PipelineCheck.SyncResourcesPresent = true
+ assert.Equal(t, "PASS", deriveDogfoodVerdict(report, true))
+
report.ExampleCheck = ExampleCheckResult{Tested: 10, WithExamples: 4}
assert.Equal(t, "FAIL", deriveDogfoodVerdict(report, true))
diff --git a/testdata/golden/expected/dogfood-verdict-matrix/fail-path-auth-dead.json b/testdata/golden/expected/dogfood-verdict-matrix/fail-path-auth-dead.json
index cb4f2924..803652fb 100644
--- a/testdata/golden/expected/dogfood-verdict-matrix/fail-path-auth-dead.json
+++ b/testdata/golden/expected/dogfood-verdict-matrix/fail-path-auth-dead.json
@@ -61,7 +61,9 @@
"detail": "sync uses domain-specific Upsert methods; search methods not found",
"domain_tables": 0,
"search_calls_domain": false,
- "sync_calls_domain": true
+ "sync_calls_domain": true,
+ "sync_file_emitted": true,
+ "sync_resources_present": true
},
"print_json_filtered_check": {
"checked": 3
diff --git a/testdata/golden/expected/dogfood-verdict-matrix/pass.json b/testdata/golden/expected/dogfood-verdict-matrix/pass.json
index 15d537d0..75f68366 100644
--- a/testdata/golden/expected/dogfood-verdict-matrix/pass.json
+++ b/testdata/golden/expected/dogfood-verdict-matrix/pass.json
@@ -48,7 +48,9 @@
"detail": "sync uses domain-specific Upsert methods; search methods not found",
"domain_tables": 0,
"search_calls_domain": false,
- "sync_calls_domain": true
+ "sync_calls_domain": true,
+ "sync_file_emitted": true,
+ "sync_resources_present": true
},
"print_json_filtered_check": {
"checked": 2
diff --git a/testdata/golden/expected/dogfood-verdict-matrix/warn-priority.json b/testdata/golden/expected/dogfood-verdict-matrix/warn-priority.json
index d796a421..cdadc080 100644
--- a/testdata/golden/expected/dogfood-verdict-matrix/warn-priority.json
+++ b/testdata/golden/expected/dogfood-verdict-matrix/warn-priority.json
@@ -55,7 +55,9 @@
"detail": "sync uses domain-specific Upsert methods; search methods not found",
"domain_tables": 0,
"search_calls_domain": false,
- "sync_calls_domain": true
+ "sync_calls_domain": true,
+ "sync_file_emitted": true,
+ "sync_resources_present": true
},
"print_json_filtered_check": {
"checked": 3
diff --git a/testdata/golden/expected/generate-golden-api/dogfood.json b/testdata/golden/expected/generate-golden-api/dogfood.json
index f0770511..15ac1ee3 100644
--- a/testdata/golden/expected/generate-golden-api/dogfood.json
+++ b/testdata/golden/expected/generate-golden-api/dogfood.json
@@ -51,7 +51,9 @@
"detail": "sync uses domain-specific Upsert methods; search uses generic Search only; 1 domain tables found",
"domain_tables": 1,
"search_calls_domain": false,
- "sync_calls_domain": true
+ "sync_calls_domain": true,
+ "sync_file_emitted": true,
+ "sync_resources_present": true
},
"print_json_filtered_check": {
"checked": 34
← 14bc18a4 feat(cli): default mcp.transport=[stdio, http] for small API
·
back to Cli Printing Press
·
fix(cli): route Swagger 2.0 specs through openapi2conv to av e798f671 →