Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "1.4.0"
".": "1.5.0"
}
8 changes: 4 additions & 4 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
configured_endpoints: 38
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/context-dev/context.dev-155e4761d62255841349c0f8a01b0a9c463ea1d1f2d6c4fd8d1a75c8bef6f226.yml
openapi_spec_hash: ab91f77e7c9d992400cbc7fc8a9e76c1
config_hash: bff282047fafdad771fb7ec685f56944
configured_endpoints: 40
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/context-dev/context.dev-a0dda03bbb600917cfb9add468cc4c8c84351a8dbbf61644dbc353263ca1748f.yml
openapi_spec_hash: c24264f32a46d9317aac5af9d6a396f7
config_hash: 920678668dd2da6f8966fbf1b8fde4e2
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
# Changelog

## 1.5.0 (2026-08-07)

Full Changelog: [v1.4.0...v1.5.0](https://github.com/context-dot-dev/context-dev-cli/compare/v1.4.0...v1.5.0)

### Features

* **api:** api update ([e21a8ff](https://github.com/context-dot-dev/context-dev-cli/commit/e21a8ff46d495a59b9c751965bb9d980a0765c78))
* **api:** api update ([48a68cb](https://github.com/context-dot-dev/context-dev-cli/commit/48a68cb9ad422157ee55deef66773a161e320f44))
* **api:** api update ([ad50292](https://github.com/context-dot-dev/context-dev-cli/commit/ad502925051676385440177ba5a4113631ff2dfa))
* **api:** api update ([5650e87](https://github.com/context-dot-dev/context-dev-cli/commit/5650e87248bd4d1dabd6027007f510650684d511))
* **api:** api update ([4ca42b8](https://github.com/context-dot-dev/context-dev-cli/commit/4ca42b8b8bdbe6750a50db1bc39b4ff098346f65))
* **api:** api update ([92be0b6](https://github.com/context-dot-dev/context-dev-cli/commit/92be0b69f74d40bddb2748939d27c5b9f2660f46))
* **api:** manual updates ([35e256a](https://github.com/context-dot-dev/context-dev-cli/commit/35e256a85572f24f11f89dbc452a7fa81640cef3))

## 1.4.0 (2026-08-05)

Full Changelog: [v1.3.0...v1.4.0](https://github.com/context-dot-dev/context-dev-cli/compare/v1.3.0...v1.4.0)
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ require (
github.com/charmbracelet/bubbletea v1.3.6
github.com/charmbracelet/lipgloss v1.1.0
github.com/charmbracelet/x/term v0.2.1
github.com/context-dot-dev/context-go-sdk/v2 v2.7.0
github.com/context-dot-dev/context-go-sdk/v2 v2.8.0
github.com/goccy/go-yaml v1.18.0
github.com/itchyny/json2yaml v0.1.4
github.com/muesli/reflow v0.3.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91 h1:payR
github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U=
github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
github.com/context-dot-dev/context-go-sdk/v2 v2.7.0 h1:zc4xevss1ms1jge3wTn0qgynanmORhvFJav8eLfaiIY=
github.com/context-dot-dev/context-go-sdk/v2 v2.7.0/go.mod h1:CvRANWLP0FHj5XyUwzEVX79ujdwr/2Jy375UVzKNQm8=
github.com/context-dot-dev/context-go-sdk/v2 v2.8.0 h1:K7a/NQIXa4C3VLiF+1cCDyAMGIEnsva2CdkKaYqzC5Q=
github.com/context-dot-dev/context-go-sdk/v2 v2.8.0/go.mod h1:CvRANWLP0FHj5XyUwzEVX79ujdwr/2Jy375UVzKNQm8=
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
Expand Down
93 changes: 74 additions & 19 deletions pkg/cmd/batch.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,22 @@
HideHelpCommand: true,
}

var batchDelete = cli.Command{
Name: "delete",
Usage: "Permanently delete a finished batch and its stored results. Active batches must\nsettle first.",
Suggest: true,
Flags: []cli.Flag{
&requestflag.Flag[string]{
Name: "batch-id",
Usage: "ID of the batch to retrieve or cancel.",
Required: true,
PathParam: "batch_id",
},
},
Action: handleBatchDelete,
HideHelpCommand: true,
}

var batchCancel = cli.Command{
Name: "cancel",
Usage: "Stop a batch from starting new pages. In-progress pages finish, and unused\ncredits are refunded.",
Expand Down Expand Up @@ -112,39 +128,36 @@
HideHelpCommand: true,
}

var batchSubmit = requestflag.WithInnerFlags(cli.Command{
var batchSubmit = cli.Command{
Name: "submit",
Usage: "Retrieve and normalize a person profile from identifiers.",
Usage: "Scrape 25K URLs or crawl large websites asynchronously.",
Suggest: true,
Flags: []cli.Flag{
&requestflag.Flag[map[string]any]{
Name: "identifiers",
Usage: "Known identifiers for the person. At least one identifier is required.",
Name: "input",
Usage: "Choose a URL list or a site crawl.",
Required: true,
BodyPath: "identifiers",
BodyPath: "input",
},
&requestflag.Flag[[]string]{
Name: "tag",
Usage: "Optional tags for tracking usage. Up to 20 tags, each 1 to 50 characters.",
Usage: "Tags stored on the batch. Filter the batch list by them later.",
BodyPath: "tags",
},
&requestflag.Flag[int64]{
Name: "timeout-ms",
Usage: "Optional timeout in milliseconds for the request. If the request takes longer than this value, it will be aborted with a 408 status code. Maximum allowed value is 300000ms (5 minutes).",
BodyPath: "timeoutMS",
&requestflag.Flag[string]{
Name: "webhook-url",
Usage: "URL notified when the batch finishes.",
BodyPath: "webhookUrl",
},
&requestflag.Flag[string]{
Name: "idempotency-key",
Usage: "Any string unique to this submission. Retries with the same key return the original batch.",
HeaderPath: "Idempotency-Key",
},
},
Action: handleBatchSubmit,
HideHelpCommand: true,
}, map[string][]requestflag.HasOuterFlag{
"identifiers": {
&requestflag.InnerFlag[string]{
Name: "identifiers.linkedin-url",
Usage: "LinkedIn profile URL, e.g. https://www.linkedin.com/in/yahia-bakour/.",
InnerField: "linkedinUrl",
},
},
})
}

func handleBatchRetrieve(ctx context.Context, cmd *cli.Command) error {
client := contextdev.NewClient(getDefaultRequestOptions(cmd)...)
Expand Down Expand Up @@ -229,6 +242,48 @@
})
}

func handleBatchDelete(ctx context.Context, cmd *cli.Command) error {
client := contextdev.NewClient(getDefaultRequestOptions(cmd)...)
unusedArgs := cmd.Args().Slice()
if !cmd.IsSet("batch-id") && len(unusedArgs) > 0 {
cmd.Set("batch-id", unusedArgs[0])
unusedArgs = unusedArgs[1:]
}
if len(unusedArgs) > 0 {
return fmt.Errorf("Unexpected extra arguments: %v", unusedArgs)
}

options, err := flagOptions(
cmd,
apiquery.NestedQueryFormatBrackets,
apiquery.ArrayQueryFormatComma,
EmptyBody,
false,
)
if err != nil {
return err
}

var res []byte
options = append(options, option.WithResponseBodyInto(&res))
_, err = client.Batch.Delete(ctx, cmd.Value("batch-id").(string), options...)

Check failure on line 269 in pkg/cmd/batch.go

View workflow job for this annotation

GitHub Actions / test

client.Batch.Delete undefined (type contextdev.BatchService has no field or method Delete)

Check failure on line 269 in pkg/cmd/batch.go

View workflow job for this annotation

GitHub Actions / lint

client.Batch.Delete undefined (type contextdev.BatchService has no field or method Delete)
if err != nil {
return err
}

obj := gjson.ParseBytes(res)
format := cmd.Root().String("format")
explicitFormat := cmd.Root().IsSet("format")
transform := cmd.Root().String("transform")
return ShowJSON(obj, ShowJSONOpts{
ExplicitFormat: explicitFormat,
Format: format,
RawOutput: cmd.Root().Bool("raw-output"),
Title: "batch delete",
Transform: transform,
})
}

func handleBatchCancel(ctx context.Context, cmd *cli.Command) error {
client := contextdev.NewClient(getDefaultRequestOptions(cmd)...)
unusedArgs := cmd.Args().Slice()
Expand Down
78 changes: 52 additions & 26 deletions pkg/cmd/batch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"testing"

"github.com/context-dot-dev/context-dev-cli/internal/mocktest"
"github.com/context-dot-dev/context-dev-cli/internal/requestflag"
)

func TestBatchRetrieve(t *testing.T) {
Expand Down Expand Up @@ -38,6 +37,18 @@ func TestBatchList(t *testing.T) {
})
}

func TestBatchDelete(t *testing.T) {
t.Skip("Mock server tests are disabled")
t.Run("regular flags", func(t *testing.T) {
mocktest.TestRunMockTestWithFlags(
t,
"--api-key", "string",
"batch", "delete",
"--batch-id", "batch_9f2c8a",
)
})
}

func TestBatchCancel(t *testing.T) {
t.Skip("Mock server tests are disabled")
t.Run("regular flags", func(t *testing.T) {
Expand Down Expand Up @@ -71,42 +82,57 @@ func TestBatchSubmit(t *testing.T) {
t,
"--api-key", "string",
"batch", "submit",
"--identifiers", "{linkedinUrl: https://www.linkedin.com/in/yahia-bakour/}",
"--tag", "production",
"--tag", "team-alpha",
"--timeout-ms", "1000",
)
})

t.Run("inner flags", func(t *testing.T) {
// Check that inner flags have been set up correctly
requestflag.CheckInnerFlags(batchSubmit)

// Alternative argument passing style using inner flags
mocktest.TestRunMockTestWithFlags(
t,
"--api-key", "string",
"batch", "submit",
"--identifiers.linkedin-url", "https://www.linkedin.com/in/yahia-bakour/",
"--tag", "production",
"--tag", "team-alpha",
"--timeout-ms", "1000",
"--input", "{data: {format: markdown, urls: [{url: https://example.com/products/anvil, itemId: sku-1, meta: {category: bar}}, {url: https://example.com/products/hammer, itemId: sku-2, meta: {foo: bar}}], options: {country: de, excludeSelectors: [x], includeImages: true, includeLinks: true, includeSelectors: [x], maxAgeMs: 0, pdf: {end: 1, ocr: 'true', shouldParse: 'true', start: 1}, settleAnimations: true, shortenBase64Images: true, useMainContentOnly: true, waitForMs: 0}}, mode: scrape}",
"--tag", "docs",
"--tag", "competitor",
"--webhook-url", "webhookUrl",
"--idempotency-key", "Idempotency-Key",
)
})

t.Run("piping data", func(t *testing.T) {
// Test piping YAML data over stdin
pipeData := []byte("" +
"identifiers:\n" +
" linkedinUrl: https://www.linkedin.com/in/yahia-bakour/\n" +
"input:\n" +
" data:\n" +
" format: markdown\n" +
" urls:\n" +
" - url: https://example.com/products/anvil\n" +
" itemId: sku-1\n" +
" meta:\n" +
" category: bar\n" +
" - url: https://example.com/products/hammer\n" +
" itemId: sku-2\n" +
" meta:\n" +
" foo: bar\n" +
" options:\n" +
" country: de\n" +
" excludeSelectors:\n" +
" - x\n" +
" includeImages: true\n" +
" includeLinks: true\n" +
" includeSelectors:\n" +
" - x\n" +
" maxAgeMs: 0\n" +
" pdf:\n" +
" end: 1\n" +
" ocr: 'true'\n" +
" shouldParse: 'true'\n" +
" start: 1\n" +
" settleAnimations: true\n" +
" shortenBase64Images: true\n" +
" useMainContentOnly: true\n" +
" waitForMs: 0\n" +
" mode: scrape\n" +
"tags:\n" +
" - production\n" +
" - team-alpha\n" +
"timeoutMS: 1000\n")
" - docs\n" +
" - competitor\n" +
"webhookUrl: webhookUrl\n")
mocktest.TestRunMockTestWithPipeAndFlags(
t, pipeData,
"--api-key", "string",
"batch", "submit",
"--idempotency-key", "Idempotency-Key",
)
})
}
2 changes: 1 addition & 1 deletion pkg/cmd/brand.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ var brandRetrieveSimplified = cli.Command{

var brandSearch = cli.Command{
Name: "search",
Usage: "Search brands by name or domain and get back up to 10 lightweight matches\n(domain, name, logo), most popular first: by Tranco rank, then market cap for\nbrands outside the Tranco list, with text relevance breaking ties. Matching is\nprefix-based with no typo tolerance, so it is suited to autocomplete. Only\nbrands already in the Context.dev index are returned — use /brand/retrieve to\nfetch (and index) a specific domain. Free on Pro and Scale plans; costs 1 credit\nper request on the Free and Starter plans.",
Usage: "Search brands by name or domain and get back up to 10 lightweight matches\n(domain, name, logo). Name matches rank ahead of domain matches; within each\ngroup the most popular brands come first: by Tranco rank, then market cap for\nbrands outside the Tranco list, with text relevance breaking ties. Matching is\nprefix-based with no typo tolerance, so it is suited to autocomplete. Only\nbrands already in the Context.dev index are returned — use /brand/retrieve to\nfetch (and index) a specific domain. Free on Pro and Scale plans; costs 1 credit\nper request on the Free and Starter plans.",
Suggest: true,
Flags: []cli.Flag{
&requestflag.Flag[string]{
Expand Down
9 changes: 9 additions & 0 deletions pkg/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,11 +173,20 @@ func init() {
Commands: []*cli.Command{
&batchRetrieve,
&batchList,
&batchDelete,
&batchCancel,
&batchGetResults,
&batchSubmit,
},
},
{
Name: "people",
Category: "API RESOURCE",
Suggest: true,
Commands: []*cli.Command{
&peopleEnrich,
},
},
{
Name: "@manpages",
Usage: "Generate documentation for 'man'",
Expand Down
2 changes: 1 addition & 1 deletion pkg/cmd/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ var parseHandle = requestflag.WithInnerFlags(cli.Command{
},
&requestflag.Flag[any]{
Name: "ocr",
Usage: "When true for PDF inputs, detect and OCR images embedded in the selected pages, inserting recognized text at each image's position in page reading order while preserving the PDF text layer. pdf.start/pdf.end limit the inclusive page range. When false, all OCR is disabled, including the automatic scanned-PDF fallback.",
Usage: "When true for PDF inputs, OCR the selected pages that have no usable text layer (scans), replacing each recovered page's text with the OCR result while pages with a real text layer keep it. pdf.start/pdf.end limit the inclusive page range. Billed at 1 credit per page OCR actually recovered, on top of the base request cost. When false, no OCR runs.",
Default: false,
QueryPath: "ocr",
},
Expand Down
Loading
Loading