@tsuga/cli 1.5.0 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/LICENSE +21 -0
  2. package/dist/cli.js +2 -2
  3. package/package.json +3 -6
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Tsuga
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/dist/cli.js CHANGED
@@ -161,9 +161,9 @@ ${c}`:a||c}function yf(e,{maxDepth:r=1e3,numbersAsFloat:n=!1}={}){if(Rs(e)!=="ob
161
161
  `?o+`
162
162
  `:o}var v9={CLAUDE_CODE_ENABLE_TELEMETRY:"1",CLAUDE_CODE_ENHANCED_TELEMETRY_BETA:"1",OTEL_METRICS_EXPORTER:"otlp",OTEL_LOGS_EXPORTER:"otlp",OTEL_TRACES_EXPORTER:"otlp",OTEL_EXPORTER_OTLP_PROTOCOL:"http/json",OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE:"delta"};function k9(e,r,n,o){let i=(0,bi.join)(e,".claude","settings.json");B(`Claude Code \u2192 ${i}`),(0,Tf.mkdirSync)((0,bi.dirname)(i),{recursive:!0});let a=Ba(i),c;try{c=JSON.parse(a??"{}")}catch{throw new Error(`${i} is not valid JSON. Fix or remove it before re-running.`)}if(!to(c))throw new Error(`${i} must contain a JSON object at the top level.`);let m=c.env??{};if(!to(m))throw new Error(`${i} "env" must be a JSON object.`);let l=o?"1":"0";c.env={...m,...v9,OTEL_EXPORTER_OTLP_ENDPOINT:r,OTEL_LOG_USER_PROMPTS:l,OTEL_LOG_TOOL_DETAILS:l,OTEL_LOG_TOOL_CONTENT:l,OTEL_EXPORTER_OTLP_HEADERS:`Authorization=Bearer ${n}`};let f=Fa(i,a);qa(i,`${JSON.stringify(c,null,2)}
163
163
  `),B(f===void 0?" created":` patched (backup: ${f})`)}function M9(e,r,n){return{environment:"dev",log_user_prompt:n,exporter:{"otlp-http":{endpoint:`${e}/v1/logs`,protocol:"binary",headers:{Authorization:`Bearer ${r}`}}},trace_exporter:{"otlp-http":{endpoint:`${e}/v1/traces`,protocol:"binary",headers:{Authorization:`Bearer ${r}`}}}}}function D9(e,r,n,o){let i=(0,bi.join)(e,".codex"),a=(0,bi.join)(i,"config.toml");B(`Codex \u2192 ${a}`),(0,Tf.mkdirSync)(i,{recursive:!0});let c=Ba(a),m=c===void 0?{}:lf(c),l="otel"in m;delete m.otel,m.otel=M9(r,n,o);let f=Fa(a,c);qa(a,yf(m)),B(f===void 0?" created":l?` replaced existing [otel] tables (backup: ${f})`:` appended (backup: ${f})`)}function hw(){return new eu("--endpoint <url>","OTLP base URL").env("TSUGA_OTLP_ENDPOINT").makeOptionMandatory()}function Tw(){return new eu("--ingestion-api-key <key>","Tsuga ingestion API key").env("TSUGA_INGESTION_API_KEY").makeOptionMandatory()}var Ew="Restart your claude / codex session to load the new config.";function _w(e){let r=e.command("setup").description("Configure local LLM CLIs to ship OTEL telemetry to Tsuga");r.command("claude-code").description("Patch ~/.claude/settings.json with Tsuga OTEL env").addOption(hw()).addOption(Tw()).option("--no-include-prompts","Strip user prompts + tool content from telemetry (default: include)").action(n=>{k9((0,hf.homedir)(),n.endpoint.replace(/\/+$/,""),n.ingestionApiKey,n.includePrompts),B(Ew)}),r.command("codex").description("Patch ~/.codex/config.toml with Tsuga OTEL settings").addOption(hw()).addOption(Tw()).option("--no-include-prompts","Strip user prompts + tool content from telemetry (default: include)").action(n=>{D9((0,hf.homedir)(),n.endpoint.replace(/\/+$/,""),n.ingestionApiKey,n.includePrompts),B(Ew)})}var wp="/v0/logs";var Ef=["CRITICAL","ERROR","WARN","NOTICE","INFO","DEBUG","TRACE"];var Cs=0,_f=t.Object({__tsuga_metadata__:t.Object({id:t.String(),source:t.Optional(t.String())},{additionalProperties:!0}),context:t.Optional(t.Object({team:t.Optional(t.String({description:"Team name associated with this log."})),tag_policy_warnings:t.Optional(t.Record(t.String(),t.String()))},{additionalProperties:!0,description:"Context attributes attached to the log after ingestion and route processing. `team` comes from telemetry or route-enriched context when present."})),message:t.Optional(t.Unknown({description:"Log message after ingestion and route processing. It can be any JSON value because processors may map arbitrary data into `message`."})),timestamp:t.Number({description:"Log timestamp as a Unix timestamp in milliseconds."}),level:t.Enum(Ef,{description:"Log severity, normalized from the source severity into one of the fixed Tsuga levels (ordered `CRITICAL` to `TRACE`)."}),[dS]:t.Optional(t.String({description:"ID of the cluster this log was read from. Only set when the request spanned several clusters."}))},{additionalProperties:!0}),Iw=100,G9="timestamp",$9=t.Union([t.Literal(G9)]),io=t.Partial(t.Object({...He.properties,query:p({type:"tsuga-query",description:"Tsuga query used to filter logs in the selected time range."}),maxResults:t.Integer({minimum:1,maximum:1e3,description:"Maximum number of logs to return. Valid values are 1 through 1000."}),shouldRecommendAttributes:t.Boolean({description:"Whether Tsuga should return suggested attributes to highlight in results."}),triggeredBy:t.Literal("refresh",{description:"Indicates the query was triggered by a refresh action."}),startOffset:t.Number({minimum:Cs,description:"Result offset used when fetching additional log rows."}),startOffsets:t.Array(t.Number({minimum:Cs}),{description:`Result offsets used when fetching additional log rows, one per entry of \`clusterIds\` and in the same order. Echo back each cluster's \`nextStartOffset\` from the previous response. Must have the same length as \`clusterIds\`. Defaults to ${Cs} for every cluster.`}),clusterId:p({allowEmpty:!1,description:"ID of the cluster to target. Omit to use the default cluster."}),clusterIds:Ea,sortBy:$9,sortDirection:t.Union([t.Literal("asc"),t.Literal("desc")],{description:"Timestamp sort direction for log results."})})),YQe=d({tags:["logs"],url:`${wp}/count`,method:"GET",query:t.Pick(io,["from","to","query","clusterId","clusterIds"]),response:t.Object({count:t.Number(),clusterResponses:t.Optional($o())})}),Ps=t.Object({value:t.String(),priority:t.Number()}),VQe=d({tags:["logs"],url:`${wp}/search`,method:"GET",query:io,response:t.Object({logs:t.Optional(t.Array(_f)),attributesToHighlight:t.Optional(t.Array(Ps)),clusterResponses:t.Optional($o(t.Object({nextStartOffset:t.Number({description:"Number of logs consumed on this cluster so far. Echo it back at this cluster's position in `startOffsets` to fetch the next page."})})))},{additionalProperties:!0})}),j9=t.Cyclic({TokenOutput:t.Union([t.Object({type:t.Literal("top"),values:t.Array(t.String())}),t.Object({type:t.Literal("ip"),value:t.String()}),t.Object({type:t.Literal("range"),min:t.Number(),max:t.Number()}),t.Object({type:t.Literal("variable"),value:t.String()}),t.Object({type:t.Literal("text"),value:t.String()}),t.Object({type:t.Literal("date"),value:t.String()}),t.Object({type:t.Literal("url"),value:t.String()}),t.Object({type:t.Literal("structure"),key:t.Array(t.String()),value:t.Array(t.Ref("TokenOutput"))})])},"TokenOutput",{description:"A token identified as part of the pattern"}),q9=t.Object({id:t.String(),pattern:t.Array(j9),size:t.Integer({description:"Number of logs that matched the pattern"}),examples:t.Array(t.Object({id:t.String(),timestampUnix:t.Number()})),timeDistribution:t.Array(t.Number()),staticFeatures:t.Array(t.Object({key:t.String(),value:t.String()},{description:"Fixed groups present in all logs matching the pattern"}))}),QQe=d({tags:["logs"],url:`${wp}/patterns`,method:"GET",query:t.Object({...He.properties,query:p({type:"tsuga-query"}),clusteringThreshold:t.Optional(t.Number()),clusterId:t.Optional(p({allowEmpty:!1}))}),response:t.Object({patterns:t.Array(q9),sampleSize:t.Number()})}),WQe=d({tags:["logs"],url:`${wp}/attributes`,method:"GET",query:t.Object({...He.properties,clusterId:t.Optional(p({allowEmpty:!1,description:"Cluster ID"})),clusterIds:t.Optional(Ea)}),response:t.Object({attributes:t.Array(t.String()),clusterResponses:t.Optional($o())})});var Us=`/${"v1"}/logs`,If=t.Object({context:t.Optional(t.Object({team:t.Optional(t.String({description:"Team name associated with this log."}))},{additionalProperties:!0,$id:"LogContext",description:"Context attributes attached to the log after ingestion and route processing. `team` comes from telemetry or route-enriched context when present."})),...t.Pick(_f,["message","timestamp","level"]).properties},{additionalProperties:!0,$id:"LogEvent",description:"Log event including message, timestamp, severity level, and optional enriched context attributes."}),B9={context:{team:"platform"},message:"Request completed successfully",timestamp:17040672e5,level:"INFO"};Object.assign(If,{examples:[B9]});var bw=t.Object({query:t.Optional(p({type:"tsuga-query",default:"*",description:"Tsuga query selecting logs to return. Omit to search all logs with `*`."})),maxResults:t.Optional(t.Integer({minimum:1,maximum:1e3,default:Iw,description:"Maximum number of logs to return. Defaults to 100. Valid values are 1 through 1000."})),clusterId:t.Optional(p({allowEmpty:!1,description:"Telemetry cluster to target. Required when the organization has multiple clusters; omit only for single-cluster organizations."})),...ut.properties},{description:"Log search query. Provide a time range, optional Tsuga query, and optional limit."}),F9={query:"level:ERROR",maxResults:100,from:1704067200,to:1704070800};Object.assign(bw,{examples:[F9]});var Sw=d({description:"Searches logs in a required time range using Tsuga query syntax. Use this endpoint to retrieve raw log events for investigations or automation. See [Logs](/documentation/explore/logs) and [Query syntax](/documentation/explore/query-syntax).",operationId:"searchLogs",tags:["public","logs"],url:`${Us}/search`,method:"GET",query:bw,response:t.Object({logs:t.Array(If,{description:"Log events matching the query and time range."})})}),H9=t.Object({pattern:t.String({description:"Clustered log pattern formatted as a readable string."}),size:t.Integer({description:"Number of logs that matched the pattern"}),groups:t.Array(t.Object({key:t.String({description:"Attribute dot-path shared by all logs in the pattern."}),value:t.String({description:"Value of the attribute identified by `key`, common to all logs in the pattern."})},{description:"Attribute key-value pair that is constant across every log matching this pattern, e.g. a shared `level` or `context.team`."}))}),Ow=t.Object({patterns:t.Array(H9,{description:"Log patterns clustered from logs matching the query."}),sampleSize:t.Number({description:"Number of logs sampled while computing patterns."})},{}),K9={patterns:[{pattern:"Resolved segment SegmentId([0:1]) from cache",size:37004,groups:[{key:"level",value:"DEBUG"},{key:"context.team",value:"infra"}]}],sampleSize:100};Object.assign(Ow,{examples:[K9]});var Aw=d({description:"Clusters matching logs into readable patterns for the requested time range. Use this to summarize common log shapes before drilling into raw events. See [Logs](/documentation/explore/logs).",operationId:"getLogPatterns",tags:["public","logs"],url:`${Us}/patterns`,method:"GET",query:t.Object({...ut.properties,query:p({type:"tsuga-query",description:"Tsuga query selecting logs to cluster into patterns."}),clusterId:t.Optional(p({allowEmpty:!1,description:"Telemetry cluster to target. Required when the organization has multiple clusters; omit only for single-cluster organizations."}))}),response:Ow}),z9=t.Object({exampleLog:t.Optional(If),team:t.String({description:"Team associated with the new error pattern."}),env:t.String({description:"Environment associated with the new error pattern."}),service:t.String({description:"Service associated with the new error pattern."}),firstSeen:t.Number({description:"Unix timestamp in seconds when this pattern was first seen."}),lastSeen:t.Number({description:"Unix timestamp in seconds when this pattern was last seen."})}),xw=t.Object({newErrorPatterns:t.Array(z9,{description:"Error patterns first seen in the requested time range."})},{}),Y9={newErrorPatterns:[{team:"platform",env:"production",service:"api-gateway",firstSeen:1704067200,lastSeen:1704153600,exampleLog:{message:"ConnectionError: Failed to connect to database",timestamp:17041536e5,level:"ERROR"}}]};Object.assign(xw,{examples:[Y9]});var Rw=d({description:"Finds error patterns first seen in the requested time range, optionally filtered by team, environment, or service. Use this to detect newly appearing failures. See [Logs](/documentation/explore/logs).",operationId:"getNewErrorPatterns",tags:["public","logs"],url:`${Us}/patterns/new`,method:"GET",query:t.Object({...ut.properties,team:t.Optional(p({description:"Team name to restrict pattern detection to."})),env:t.Optional(p({description:"Environment to restrict pattern detection to."})),service:t.Optional(p({description:"Service name to restrict pattern detection to."})),clusterId:t.Optional(p({allowEmpty:!1,description:"Telemetry cluster to target. Required when the organization has multiple clusters; omit only for single-cluster organizations."}))}),response:xw}),V9=t.Object({team:t.String({description:"Team associated with the error pattern."}),env:t.String({description:"Environment associated with the error pattern."}),pattern:t.String({description:"Error pattern formatted as a readable string."}),increaseTimestamps:t.Array(t.Number({description:"Unix timestamp in milliseconds of a detected spike in occurrence of this pattern. One entry per spike detected in the requested time range."}))}),Cw=t.Object({errorPatternIncreases:t.Array(V9,{description:"Error patterns with increased occurrence in the requested time range."})},{}),Q9={errorPatternIncreases:[{team:"platform",env:"production",pattern:"Non-resolved segment SegmentId(*) from cache",increaseTimestamps:[17041536e5,17042392e5]}]};Object.assign(Cw,{examples:[Q9]});var Pw=d({description:"Finds error patterns whose occurrence increased for a team in the requested time range. Use this to identify growing failure modes. See [Logs](/documentation/explore/logs).",operationId:"getErrorPatternIncrease",tags:["public","logs"],url:`${Us}/patterns/increase`,method:"GET",query:t.Object({...ut.properties,team:p({description:"Team name to analyze for pattern increases."}),env:t.Optional(p({description:"Environment to restrict the analysis to."})),clusterId:t.Optional(p({allowEmpty:!1,description:"Telemetry cluster to target. Required when the organization has multiple clusters; omit only for single-cluster organizations."}))}),response:Cw}),Uw=t.Object({attributes:t.Array(t.String(),{description:"Log attribute dot-paths observed in the time range"})},{}),W9={attributes:["context.env","context.k8s.pod.name","context.service.name","context.team","level","message","timestamp"]};Object.assign(Uw,{examples:[W9]});var Z9=t.Object({...ut.properties,clusterId:t.Optional(p({allowEmpty:!1,description:"Telemetry cluster to target. Required when the organization has multiple clusters; omit only for single-cluster organizations."}))},{description:"Log attribute discovery query. Provide a time range and optional cluster ID."}),ww=d({description:"Lists log attribute dot-paths observed in the requested time range. This endpoint requires a public API credential that can read all relevant teams because attribute discovery is not team-filtered. Use this to discover fields for Tsuga queries, filters, and grouping. See [Logs](/documentation/explore/logs).",operationId:"getLogAttributes",tags:["public","logs"],url:`${Us}/attributes`,method:"GET",query:Z9,response:Uw});var vr="/v0/metrics",X9=t.Object({__tsuga_metadata__:t.Object({},{additionalProperties:!0}),context:t.Optional(t.Object({},{additionalProperties:!0})),message:t.Optional(t.String()),timestamp:t.Number(),level:t.Enum(Ef)},{additionalProperties:!0}),u8e=d({tags:["metrics"],url:`${vr}/count`,method:"GET",query:t.Pick(io,["from","to","query","clusterId"]),response:t.Object({count:t.Number()})}),m8e=d({tags:["metrics"],url:`${vr}/search`,method:"GET",query:io,response:t.Object({logs:t.Optional(t.Array(X9)),totalHits:t.Optional(t.Number()),attributesToHighlight:t.Optional(t.Array(Ps))},{additionalProperties:!0})}),Np=t.Enum(["counter","gauge","histogram","summary","composite_histogram"],{description:"Metric instrument type, set by the reporting instrumentation. `counter` accumulates a monotonically increasing total (aggregate with `sum` or `increase`); `gauge` reports a point-in-time value that can go up or down (aggregate with `average`, `max`, `min`, or `last`); `histogram`, `composite_histogram`, and `summary` report a distribution of values, from which percentiles can be computed. Tsuga displays `composite_histogram` metrics as Histogram in the app."}),bf=t.Enum(["delta","cumulative","none"],{description:"Metric temporality. `delta` reports changes per collection interval, `cumulative` reports running totals, and `none` means temporality is not applicable or unknown."}),J9=t.Object({capabilities:t.Optional(t.Array(t.String(),{description:"Aggregate function types (such as `max`, `min`, `sum`) supported when querying or graphing this metric. If this field is omitted or empty, all aggregate types are supported."})),description:t.Optional(t.String({description:"Human-readable description of the metric"})),tags:t.Optional(t.Array(t.String(),{description:"Attribute names available as dimensions for filtering or grouping this metric. Exposed publicly as `attributes`."})),temporality:t.Optional(bf),type:t.Optional(Np),unit:t.Optional(t.String({description:"Metric unit reported by instrumentation or inferred metadata."}))}),l8e=d({url:`${vr}/metadata`,method:"GET",query:t.Object({...He.properties,metricName:p({allowEmpty:!1}),clusterId:t.Optional(p({allowEmpty:!1,description:"Cluster ID"}))}),response:J9}),d8e=d({tags:["metrics"],url:vr,method:"GET",query:t.Object({...He.properties,clusterId:t.Optional(p({allowEmpty:!1,description:"Cluster ID"}))}),response:t.Array(t.String())}),Lp=t.Array(t.Object({name:t.String({description:"Metric name observed by Tsuga."}),type:Np}),{description:"Metrics observed in the requested time range, with the instrument type each was reported as."}),e3=[{name:"http.server.request.duration",type:"histogram"},{name:"http.server.active_requests",type:"gauge"},{name:"http.server.request.count",type:"counter"}];Object.assign(Lp,{examples:[e3]});var f8e=d({tags:["metrics"],url:`${vr}/names-and-types`,method:"GET",query:t.Object({...He.properties,clusterId:t.Optional(p({allowEmpty:!1,description:"Cluster ID"}))}),response:Lp}),ws=t.Array(t.String(),{description:"Attribute names available as dimensions for filtering or grouping the requested metric(s)."}),t3=["service","env","host","method","status_code"];Object.assign(ws,{examples:[t3]});var g8e=d({tags:["metrics"],url:`${vr}/attributes`,method:"GET",query:t.Object({...He.properties,metricName:p({allowEmpty:!1}),clusterId:t.Optional(p({allowEmpty:!1,description:"Cluster ID"}))}),response:ws}),y8e=d({tags:["metrics"],url:`${vr}/attributes/batch`,method:"GET",query:t.Object({...He.properties,metricNames:t.Array(p({allowEmpty:!1}),{minItems:1,description:"Metric names to fetch attributes for"}),clusterId:t.Optional(p({allowEmpty:!1,description:"Cluster ID"}))}),response:ws}),Sf=t.Object({assets:t.Array(t.Object({type:t.Enum(["dashboard","monitor"],{description:"Kind of asset referencing the metric."}),id:t.String({description:"Dashboard or monitor ID for the asset that queries this metric."}),name:t.String({description:"Display name of the referencing dashboard or monitor."}),owner:t.String({description:"Team ID that owns the referencing dashboard or monitor."})},{description:"A dashboard or monitor that queries this metric."}),{description:"Dashboards and monitors that currently query this metric."})}),h8e=d({tags:["metrics"],url:`${vr}/assets-usage`,method:"GET",query:t.Object({metricName:p({allowEmpty:!1})}),response:Sf}),T8e=d({url:`${vr}/per-attribute`,method:"GET",query:t.Object({from:t.Optional(t.Number()),to:t.Optional(t.Number()),attribute:p(),clusterId:t.Optional(p({allowEmpty:!1}))}),response:t.Array(t.String())});var Of=`/${"v1"}/metrics`,r3=[{name:"http.server.request.duration",type:"histogram"},{name:"http.server.active_requests",type:"gauge"},{name:"http.server.request.count",type:"counter"}];Object.assign(Lp,{examples:[r3]});var Af=t.Object({name:t.String({description:"Metric name observed by Tsuga. Use this value in metric queries and aggregations."}),type:Np,description:t.Optional(t.String({description:"Human-readable description of what the metric measures, set by the reporting instrumentation. Omitted when the instrumentation did not provide one."})),unit:t.Optional(t.String({description:"Metric unit reported by instrumentation or inferred metadata."})),temporality:t.Optional(bf),capabilities:t.Optional(t.Array(t.String(),{description:"Aggregate function types (such as `max`, `min`, `sum`) supported when querying or graphing this metric. An empty or omitted array means all aggregate types are supported."})),attributes:t.Optional(t.Array(t.String(),{description:"Metric attribute names available as dimensions for filtering or grouping."}))}),n3={name:"http.server.request.duration",type:"histogram",description:"Duration of HTTP server requests",unit:"ms",temporality:"delta",capabilities:["max","min","sum"],attributes:["context.team","context.environment","context.region"]};Object.assign(Af,{examples:[n3]});var Nw=t.Object({...ut.properties,clusterId:t.Optional(p({allowEmpty:!1,description:"Telemetry cluster to target. Required when the organization has multiple clusters; omit only for single-cluster organizations."}))},{description:"Metric metadata query. Provide the time range to inspect and optionally a cluster ID."}),Lw=d({description:"Lists metrics observed in the requested time range with metadata such as type, unit, temporality, capabilities, and attributes. Use this to discover metric names before querying or graphing them. See [Metrics](/documentation/explore/metrics/index).",operationId:"listMetrics",tags:["public","metrics"],url:Of,method:"GET",query:Nw,response:t.Array(Af)}),vw=d({description:"Retrieves metadata for one metric name in the requested time range. Use this to inspect available dimensions and supported query behavior for a metric. See [Metric details](/documentation/explore/metrics/metric-details).",operationId:"getMetric",tags:["public","metrics"],url:`${Of}/:name`,method:"GET",params:t.Object({name:p({allowEmpty:!1,description:"Metric name to retrieve, for example `http.server.request.duration`."})}),query:Nw,response:Af}),o3=["service","env","host","method","status_code"];Object.assign(ws,{examples:[o3]});var kw=t.Pick(Sf,["assets"]),i3={assets:[{type:"dashboard",id:"dash-123-abc",name:"API Performance Overview",owner:"team-123-abc"},{type:"monitor",id:"mon-789-ghi",name:"High Latency Alert",owner:"team-123-abc"}]};Object.assign(kw,{examples:[i3]});var Mw=d({description:"Retrieve dashboards and monitors that use a specific metric",operationId:"getMetricAssetsUsage",tags:["private"],url:`${Of}/assets-usage`,method:"GET",query:t.Object({metricName:p({allowEmpty:!1,description:"The name of the metric to find usage for"})}),response:kw});var Si="/v0/traces",N8e=d({tags:["traces"],url:`${Si}/count`,method:"GET",query:t.Pick(io,["from","to","query","clusterId"]),response:t.Object({count:t.Number()})}),a3=["unset","ok","error"],s3=t.Enum(a3),c3=["unspecified","internal","server","client","producer","consumer"],p3=t.Enum(c3),Gw=t.Object({__tsuga_metadata__:t.Optional(t.Object({},{additionalProperties:!0})),context:t.Optional(t.Object({telemetry:t.Optional(t.Object({sdk:t.Optional(t.Object({language:t.Optional(t.String())},{additionalProperties:!0}))},{additionalProperties:!0})),tag_policy_warnings:t.Optional(t.Record(t.String(),t.String())),service:t.Optional(t.Object({name:t.Optional(t.String()),version:t.Optional(t.String())},{additionalProperties:!0})),env:t.Optional(t.String())},{additionalProperties:!0})),parent_span_id:t.Optional(t.String()),resource_attributes:t.Object({},{additionalProperties:!0}),span_attributes:t.Object({},{additionalProperties:!0}),duration:t.Number({description:"In milliseconds."}),duration_ns:t.String({description:"In nanoseconds. Transmitted as a string to avoid losing precision, as BigInt is not JSON-compatible."}),start_time:t.String({description:"In nanoseconds. Transmitted as a string to avoid losing precision, as BigInt is not JSON-compatible."}),end_time:t.String({description:"In nanoseconds. Transmitted as a string to avoid losing precision, as BigInt is not JSON-compatible."}),error:t.Optional(t.Object({message:t.String()})),events:t.Optional(t.Array(t.Object({event_attributes:t.Object({},{additionalProperties:!0}),event_name:t.String(),event_timestamp_nanos:t.String({description:"In nanoseconds. Transmitted as a string to avoid losing precision, as BigInt is not JSON-compatible."})}))),links:t.Optional(t.Array(t.Object({},{additionalProperties:!0}))),span_id:t.String(),span:t.Object({kind:p3,name:t.String()}),status_code:t.Optional(s3),trace_id:t.String()}),$w=100,u3="start_time",m3="duration_ns",l3=t.Union([t.Literal(u3),t.Literal(m3)]),d3={...He.properties,query:t.Optional(p({type:"tsuga-query"})),maxResults:t.Optional(t.Integer({minimum:1,maximum:1e4})),shouldRecommendAttributes:t.Optional(t.Boolean()),startOffset:t.Optional(t.Number({minimum:Cs})),clusterId:t.Optional(p({allowEmpty:!1,description:"Cluster ID"})),sortBy:t.Optional(l3),sortDirection:t.Optional(t.Union([t.Literal("asc"),t.Literal("desc")]))},L8e=d({tags:["traces"],url:`${Si}/search`,method:"GET",query:t.Object(d3),response:t.Object({spans:t.Optional(t.Array(Gw)),attributesToHighlight:t.Optional(t.Array(Ps))})});var f3=t.Object({groupByAttributes:t.Array(p({allowEmpty:!1}),{description:'Glob patterns of span_attributes keys to use as additional grouping dimensions (e.g. "db.*"). Matches against flattened dotted keys of span_attributes only.'}),minLeafSpansToAggregate:t.Integer({minimum:2,description:"Minimum leaf-group size before aggregation occurs. Default 5."}),maxParentDepth:t.Integer({minimum:-1,description:"Max depth of recursive parent aggregation. 0 = leaves only, -1 = unlimited (default)."}),aggregationHistogramBucketsSeconds:t.Array(t.Number({minimum:0}),{description:"Upper bounds for the latency histogram in seconds. Empty array disables the histogram attributes."}),sortSpans:t.Boolean({description:"Whether to sort the returned spans by start_time (span_id tie-breaker). Set false when the caller reconstructs the trace tree and does not need ordering. Default true."})}),g3=t.Object({...He.properties,traceId:p({allowEmpty:!1,description:"Trace ID to summarize"}),clusterId:t.Optional(p({allowEmpty:!1,description:"Cluster ID"})),...t.Partial(f3).properties}),v8e=d({tags:["traces"],url:`${Si}/summarize`,method:"GET",query:g3,response:t.Object({spans:t.Array(Gw)})}),k8e=d({tags:["traces"],url:`${Si}/attributes`,method:"GET",query:t.Object({...He.properties,clusterId:t.Optional(p({allowEmpty:!1,description:"Cluster ID"}))}),response:t.Object({attributes:t.Array(t.String())})}),y3=t.Object({key:t.String({description:"Opaque stable key identifying this contributing service within the response. Tsuga assigns it while building the summary; `ranges[].contributions[].serviceKey` and `serviceTotals[].serviceKey` reference this value."}),name:t.String({description:"Observed service name that contributed leaf-span time to the trace. Comes from trace service context and is returned for every contributing service."}),env:t.Optional(t.String({description:"Observed service environment for this contributing service. Comes from trace service context and is absent when the spans do not carry an environment."})),id:t.Optional(t.String({description:"Service catalog ID for this contributing service. Tsuga sets it when exactly one catalog entry matches the observed service and environment; absent when the service is not cataloged or matches ambiguously."})),namespace:t.Optional(t.String({description:"Service namespace from the matched service catalog entry. Returned only when Tsuga can resolve the contributing service to one catalog entry with a namespace."}))}),h3=t.Object({fromNs:t.String({description:"Range start time in nanoseconds since Unix epoch. Tsuga sets it from the trace timeline split where active leaf spans change. Transmitted as a string to avoid losing precision."}),toNs:t.String({description:"Range end time in nanoseconds since Unix epoch. Tsuga sets it from the trace timeline split where active leaf spans change. Transmitted as a string to avoid losing precision."}),durationNs:t.String({description:"Range duration in nanoseconds, computed as `toNs - fromNs`. Transmitted as a string to avoid losing precision."}),contributions:t.Array(t.Object({serviceKey:t.String({description:"Contributing service key for this range. References `services[].key` in the same response."}),weight:t.Number({description:"Share of this range attributed to the service, from `0` through `1`. Tsuga computes the weight from active leaf spans in the range; weights inside one range sum to `1`."}),durationNs:t.String({description:"Estimated duration attributed to this service in the range, computed as `weight` times the range's own `durationNs` and rounded to whole nanoseconds. Use `serviceTotals` as authoritative when rounded range values do not add up exactly."})}),{description:"Services contributing active leaf-span time to this range, with weighted shares for the range duration."}),spanIds:t.Array(t.String(),{description:"Leaf span IDs that produced this range. Tsuga returns IDs from the leaf-only attribution set, including merged sub-ranges after short-range collapsing."})}),T3=t.Object({serviceKey:t.String({description:"Contributing service key for this aggregate total. References `services[].key` in the same response."}),durationNs:t.String({description:"Total wall-clock contribution of this service across the trace, in nanoseconds. Sum of `weight * durationNs` over every range the service contributes to; authoritative when it disagrees with rounded per-range values. Transmitted as a string to avoid losing precision."}),share:t.Number({description:"Share of total trace duration attributed to this service, from `0` through `1`. Computed as `durationNs / totalDurationNs`; multiply by 100 for a percentage."})}),xf=t.Optional(t.Number({minimum:0,description:"Minimum range duration in milliseconds. Shorter ranges are collapsed (absorbed into a neighbor or blended with adjacent shorts) to keep the timeline readable. When omitted, the default depends on the trace: max(1ms, 1% of the total trace duration), so e.g. a 10s trace collapses ranges shorter than 100ms. Pass 0 to disable collapsing."})),Rf=t.Optional(t.Boolean({default:!0,description:"When false, omits the per-range timeline (returns `ranges: []`) and returns only `services` and `serviceTotals`. Cuts payload size for callers that only need the headline. Defaults to true."})),vp=t.Object({traceId:t.String({description:"Trace ID summarized by the response. Echoes the required `traceId` query parameter."}),startTimeNs:t.String({description:"Earliest `start_time` across fetched spans, in nanoseconds since Unix epoch. If the request window does not cover the full trace, this reflects the fetched subset, not necessarily the trace's true start. Transmitted as a string to avoid losing precision."}),endTimeNs:t.String({description:"Latest `end_time` across fetched spans, in nanoseconds since Unix epoch. If the request window does not cover the full trace, this reflects the fetched subset, not necessarily the trace's true end. Transmitted as a string to avoid losing precision."}),totalDurationNs:t.String({description:"Total fetched trace duration in nanoseconds, computed as `endTimeNs - startTimeNs`. Transmitted as a string to avoid losing precision."}),truncated:t.Boolean({description:"Whether the underlying span fetch hit its result cap. When true, the latency summary may be incomplete because not every span in the trace was available."}),services:t.Array(y3,{description:"Unique services that contributed leaf-span time to the trace, enriched with catalog IDs when Tsuga can resolve them. Referenced by `serviceKey` from `ranges` and `serviceTotals`."}),ranges:t.Array(h3,{description:"Sequential trace timeline split into ranges wherever the active leaf-span set changes. Empty when the request sets `includeRanges` to false."}),serviceTotals:t.Array(T3,{description:"Aggregated wall-clock contribution per service across the fetched trace. Use this for service-level latency ownership without processing the per-range timeline."})}),E3={traceId:"78c99c5bb1e4a30297fa134b9dbec64f",startTimeNs:"1704067200000000000",endTimeNs:"1704067202400000000",totalDurationNs:"2400000000",truncated:!1,services:[{key:"checkout|prod",name:"checkout",env:"prod",id:"123-456-abc",namespace:"default"},{key:"payments|prod",name:"payments",env:"prod",id:"456-789-def",namespace:"default"}],ranges:[{fromNs:"1704067200000000000",toNs:"1704067201200000000",durationNs:"1200000000",contributions:[{serviceKey:"checkout|prod",weight:1,durationNs:"1200000000"}],spanIds:["3df8cc3449378f66"]},{fromNs:"1704067201200000000",toNs:"1704067202400000000",durationNs:"1200000000",contributions:[{serviceKey:"checkout|prod",weight:.5,durationNs:"600000000"},{serviceKey:"payments|prod",weight:.5,durationNs:"600000000"}],spanIds:["187a47da1b2560f8","3df8cc3449378f66"]}],serviceTotals:[{serviceKey:"checkout|prod",durationNs:"1800000000",share:.75},{serviceKey:"payments|prod",durationNs:"600000000",share:.25}]};Object.assign(vp,{examples:[E3]});var M8e=d({tags:["traces"],url:`${Si}/latency-summary`,method:"GET",query:t.Object({...He.properties,traceId:p({allowEmpty:!1,description:"Trace ID to summarize"}),clusterId:t.Optional(p({allowEmpty:!1,description:"Cluster ID"})),minRangeDurationMs:xf,includeRanges:Rf}),response:vp}),Dw=t.Object({filter:p({type:"tsuga-query",description:"TQL filter defining the group"}),timeRange:jo}),_3=t.Object({attr:t.String(),value:t.String()}),I3=t.Object({value:t.String(),supportA:t.Number(),supportB:t.Number()}),b3=t.Object({predicate:_3,supportA:t.Number(),supportB:t.Number(),lift:t.Number(),pValue:t.Number(),attrValues:t.Array(I3)}),D8e=d({tags:["traces"],url:`${Si}/contrast-sets`,method:"POST",body:t.Object({groupA:Dw,groupB:Dw,candidateAttrs:t.Optional(t.Array(p({allowEmpty:!1}))),topK:t.Optional(t.Integer({minimum:1,maximum:100})),minLift:t.Optional(t.Number({minimum:1})),minSupport:t.Optional(t.Number({minimum:0,maximum:100})),clusterId:t.Optional(p({allowEmpty:!1,description:"Cluster ID"}))}),response:t.Object({contrastSets:t.Array(b3),groupACount:t.Number(),groupBCount:t.Number()})});var Cf=`/${"v1"}/traces`,Pf=t.Object({context:t.Optional(t.Object({service:t.Optional(t.Object({name:t.Optional(t.String({description:"Service name associated with the span."})),version:t.Optional(t.String({description:"Service version associated with the span."}))},{additionalProperties:!0,description:"Service identity associated with the span, from OpenTelemetry service resource attributes."}))},{additionalProperties:!0,description:"OpenTelemetry resource context resolved for the span, holding the identity of the emitting service."})),parentSpanId:t.Optional(t.String({description:"`spanId` of this span's parent within the same trace. Absent for the root span."})),resourceAttributes:t.Object({},{additionalProperties:!0,description:"OpenTelemetry resource attributes describing the process/host that emitted the span (e.g. `host.name`, `k8s.pod.name`), as a flat key-value map set by the instrumented service or its SDK."}),spanAttributes:t.Object({},{additionalProperties:!0,description:"OpenTelemetry span attributes describing this operation (e.g. HTTP method, DB statement), as a flat key-value map set by the instrumented code or auto-instrumentation."}),duration:t.Number({description:"Span duration in milliseconds, derived from the nanosecond `startTime` and `endTime` values."}),startTime:t.String({description:"Span start time as a Unix epoch timestamp in nanoseconds, encoded as a string to preserve precision."}),endTime:t.String({description:"Span end time as a Unix epoch timestamp in nanoseconds, encoded as a string to preserve precision."}),error:t.Optional(t.Object({message:t.String({description:"Error message associated with the span."})},{description:"Error details associated with the span, separate from the OpenTelemetry `statusCode` field."})),events:t.Optional(t.Array(t.Object({event_attributes:t.Object({},{additionalProperties:!0,description:"Key-value attributes recorded with this event, set by the instrumented code when the event was added to the span (e.g. exception details)."}),event_name:t.String({description:"Name of the span event."}),event_timestamp_nanos:t.String({description:"Event timestamp in nanoseconds, transmitted as a string for precision."})},{description:"A single timestamped event recorded on the span, with its name and attributes."}),{description:"Events recorded on the span."})),spanId:t.String({description:"Unique span ID within the trace."}),span:t.Object({kind:t.String({description:"OpenTelemetry span kind describing the relationship to remote calls: `unspecified`, `internal`, `server`, `client`, `producer`, or `consumer`."}),name:t.String({description:"Operation name recorded on the span."})},{description:"Operation identity for the span, combining the recorded operation name and the OpenTelemetry span kind."}),statusCode:t.Optional(t.String({description:"OpenTelemetry span status set by the instrumented code: `unset` (default, no explicit status), `ok`, or `error`. Absent if the source span never set a status."})),traceId:t.String({description:"Trace ID shared by all spans in the trace."})},{additionalProperties:!0,$id:"SpanEvent",description:"Distributed tracing span including timing, identifiers, OpenTelemetry attributes, events, and status metadata."}),S3={context:{service:{name:"my-service",version:"1.0.0"}},parentSpanId:"187a47da1b2560f8",resourceAttributes:{},spanAttributes:{busyNs:374640,code:{file:{path:"src/queue/sqs.rs"},line:{number:162},module:{name:"queue::sqs"}},idleNs:23621445,maxMessages:"1",target:"queue::sqs",thread:{id:2,name:"tokio-runtime-worker"}},duration:23,startTime:"1770923469995353600",endTime:"1770923470019349500",spanId:"3df8cc3449378f66",span:{kind:"internal",name:"receive_messages"},statusCode:"ok",traceId:"78c99c5bb1e4a30297fa134b9dbec64f"};Object.assign(Pf,{examples:[S3]});var O3={from:1704067200,to:1704070800,query:"context.service.name:my-service",maxResults:100},jw=t.Object({...ut.properties,query:t.Optional(p({type:"tsuga-query",default:"*",description:"Tsuga query selecting spans to return. Omit to search all spans in the range with `*`."})),maxResults:t.Optional(t.Integer({minimum:1,maximum:1e4,default:$w,description:"Maximum number of spans to return. Defaults to 100. Valid values are 1 through 10000."})),clusterId:t.Optional(p({allowEmpty:!1,description:"Telemetry cluster to target. Required when the organization has multiple clusters; omit only for single-cluster organizations."}))},{description:"Span search query. Provide a time range, optional Tsuga query, and optional limit."});Object.assign(jw,{examples:[O3]});var qw=d({description:"Searches spans in a required time range using Tsuga query syntax. Use this endpoint to retrieve trace spans for investigations or automation. See [Traces](/documentation/explore/traces) and [Query syntax](/documentation/explore/query-syntax).",operationId:"searchSpans",tags:["public","traces"],url:`${Cf}/search`,method:"GET",query:jw,response:t.Object({spans:t.Array(Pf,{description:"Spans matching the query and time range."})})}),A3={from:1704067200,to:1704070800,traceId:"78c99c5bb1e4a30297fa134b9dbec64f"},Bw=t.Object({...ut.properties,traceId:p({allowEmpty:!1,description:"Trace ID to summarize. Use the `traceId` returned by span search, the trace details page, or your tracing instrumentation. Required; the requested time range must include the trace."}),clusterId:t.Optional(p({allowEmpty:!1,description:"Telemetry cluster to target. Required when the organization has multiple clusters; omit only for single-cluster organizations."})),groupByAttributes:t.Optional(t.Array(p({allowEmpty:!1}),{description:"Glob patterns of span attribute keys to use as additional grouping dimensions. Use this when spans should be summarized separately for matching attributes, such as `db.*`. Matches flattened dotted span attribute keys; omitted by default."})),minLeafSpansToAggregate:t.Optional(t.Integer({minimum:2,default:5,description:"Minimum number of similar leaf spans in a group before Tsuga replaces them with one synthetic summary span. Use higher values for less aggressive summarization. Optional; defaults to 5 and must be at least 2."})),maxParentDepth:t.Optional(t.Integer({minimum:-1,default:-1,description:"Maximum depth of recursive parent aggregation after leaf spans are summarized. Use this to limit parent-level aggregation. Use `0` to aggregate leaf spans only or `-1` for unlimited depth; defaults to `-1`."})),aggregationHistogramBucketsSeconds:t.Optional(t.Array(t.Number({minimum:0}),{description:"Upper-bound bucket values, in seconds, for the latency histogram recorded on synthetic summary spans. Provide custom buckets when the default latency buckets are not suitable. Pass an empty array to omit histogram attributes; omitted values use Tsuga defaults from 5 ms through 10 s."})),sortSpans:t.Optional(t.Boolean({default:!0,description:"Whether Tsuga sorts returned spans by start time, using span ID as the tie-breaker for identical start times. Defaults to `true`; set to `false` only when reconstructing the trace tree yourself, in which case summary spans are appended after surviving spans."}))},{description:"Trace summarization query. Provide a trace ID, a time range covering the trace, and optional aggregation tuning."});Object.assign(Bw,{examples:[A3]});var Fw=d({description:"Summarizes a trace by aggregating groups of similar spans into synthetic summary spans, producing a compact view of large traces. Summary spans are marked with `spanAttributes.aggregation.is_summary` and carry span counts, duration statistics, and an optional latency histogram. See [Traces](/documentation/explore/traces).",operationId:"summarizeTrace",tags:["public","traces"],url:`${Cf}/summarize`,method:"GET",query:Bw,response:t.Object({spans:t.Array(Pf,{description:"Summarized trace spans, sorted by start time unless `sortSpans` is false. Aggregated groups are replaced by synthetic summary spans marked with `spanAttributes.aggregation.is_summary`."})})}),x3={from:1704067200,to:1704070800,traceId:"78c99c5bb1e4a30297fa134b9dbec64f"},Hw=t.Object({...ut.properties,traceId:p({allowEmpty:!1,description:"Trace ID to summarize. Use the `traceId` returned by span search, the trace details page, or your tracing instrumentation. Required; the requested time range must include the trace."}),clusterId:t.Optional(p({allowEmpty:!1,description:"Telemetry cluster to target. Required when the organization has multiple clusters; omit only for single-cluster organizations."})),minRangeDurationMs:xf,includeRanges:Rf},{description:"Trace latency summary query. Provide a trace ID, a time range covering the trace, and optional timeline tuning."});Object.assign(Hw,{examples:[x3]});var Kw=d({description:"Summarizes where wall-clock time is spent in a trace, attributing each slice of the trace timeline to the services with active leaf spans. Returns per-service totals and an optional sequential range timeline. See [Traces](/documentation/explore/traces).",operationId:"getTraceLatencySummary",tags:["public","traces"],url:`${Cf}/latency-summary`,method:"GET",query:Hw,response:vp});var Vw=["timestamp","level","message"],Qw=["count","ratio","team","level","pattern"];function nt(e,r){let n=r??hr(e);if(!n)throw new Error(`--${e} is required`);return $s(n)}function zw(e){let r={from:nt("from",e.from),to:nt("to",e.to)},n=e.query??hr("query");n!==void 0&&(r.query=n);let o=e.maxResults??hr("max-results");if(o!==void 0){let i=Number(o);if(Number.isNaN(i))throw new Error(`--max-results must be a number (got: ${o})`);r.maxResults=i}return r}function Ee(e){let r=hr(e);return r===void 0?"":` (default: ${r})`}function R3(e){let r=iu(e.output),n=e.fields===void 0?void 0:au(e.fields);return r==="json"?{format:r,fields:n}:{format:r,fields:n??Vw}}function C3(e){let r=iu(e.output),n=e.fields===void 0?void 0:au(e.fields);return r==="json"?{format:r,fields:n}:{format:r,fields:n??Qw}}function Yw(e,r){let n={count:e.size,ratio:r>0?e.size/r:0,pattern:e.pattern};for(let{key:o,value:i}of e.groups)o==="context.team"?n.team=i:n[o]=i;return n}function P3(e,r){if(r.format==="json"){if(r.fields===void 0){W(e);return}let{fields:i}=r;W({patterns:e.patterns.map(a=>Yw(a,e.sampleSize)).map(a=>su(a,i)),sampleSize:e.sampleSize});return}let n=e.patterns.map(i=>Yw(i,e.sampleSize)),o=cu(r.format,n,r.fields);o.length>0&&B(o)}function U3(e,r){if(r.format==="json"){if(r.fields===void 0){W(e);return}let{fields:o}=r;W({logs:e.logs.map(i=>su(i,o))});return}let n=cu(r.format,e.logs,r.fields);n.length>0&&B(n)}function Ww(e,r){let n=e.command("logs").description("Search and analyze logs");n.command("search").description("Search logs").option("--from <timestamp>",`Start of time range${Ee("from")}`).option("--to <timestamp>",`End of time range${Ee("to")}`).option("--query <query>",`Search query${Ee("query")}`).option("--max-results <n>",`Maximum number of results${Ee("max-results")}`).option("--fields <fields>",`Comma-separated dot-paths to project from each log (default for --output=tsv|csv: ${Vw.join(",")})`).option("-o, --output <format>","Output format: json | tsv | csv","json").action(async c=>{let m=R3(c),l=await r()(Sw,{query:zw(c)});U3(l,m)}),n.command("attributes").description("List log attribute dot-paths observed in the time range").option("--from <timestamp>",`Start of time range${Ee("from")}`).option("--to <timestamp>",`End of time range${Ee("to")}`).action(async c=>{let m=await r()(ww,{query:{from:nt("from",c.from),to:nt("to",c.to)}});W(m)}),n.command("patterns").description("List log patterns").option("--from <timestamp>",`Start of time range${Ee("from")}`).option("--to <timestamp>",`End of time range${Ee("to")}`).option("--query <query>",`Search query${Ee("query")}`).option("--fields <fields>",`Comma-separated dot-paths to project from each pattern (default for --output=tsv|csv: ${Qw.join(",")})`).option("-o, --output <format>","Output format: json | tsv | csv","json").action(async c=>{let m=C3(c),l={from:nt("from",c.from),to:nt("to",c.to)},f=c.query??hr("query");f!==void 0&&(l.query=f);let y=await r()(Aw,{query:l});P3(y,m)}),n.command("new-error-patterns").description("List new error patterns").option("--from <timestamp>",`Start of time range${Ee("from")}`).option("--to <timestamp>",`End of time range${Ee("to")}`).option("--team <team>","Filter by team").option("--env <env>","Filter by environment").option("--service <service>","Filter by service").action(async c=>{let m={from:nt("from",c.from),to:nt("to",c.to)};c.team!==void 0&&(m.team=c.team),c.env!==void 0&&(m.env=c.env),c.service!==void 0&&(m.service=c.service);let l=await r()(Rw,{query:m});W(l)}),n.command("error-pattern-increases").description("List error pattern increases for a given team").option("--from <timestamp>",`Start of time range${Ee("from")}`).option("--to <timestamp>",`End of time range${Ee("to")}`).requiredOption("--team <team>","Team to query").option("--env <env>","Filter by environment").action(async c=>{let m={from:nt("from",c.from),to:nt("to",c.to),team:c.team};c.env!==void 0&&(m.env=c.env);let l=await r()(Pw,{query:m});W(l)});let o=e.command("metrics").description("List and inspect metrics");o.command("list").description("List all metrics with their metadata").option("--from <timestamp>",`Start of time range${Ee("from")}`).option("--to <timestamp>",`End of time range${Ee("to")}`).action(async c=>{let m=await r()(Lw,{query:{from:nt("from",c.from),to:nt("to",c.to)}});W(m)}),o.command("get <name>").description("Retrieve a metric by name with its metadata").option("--from <timestamp>",`Start of time range${Ee("from")}`).option("--to <timestamp>",`End of time range${Ee("to")}`).action(async(c,m)=>{let l=await r()(vw,{params:{name:c},query:{from:nt("from",m.from),to:nt("to",m.to)}});W(l)}),o.command("assets-usage <name>").description("List dashboards and monitors that use a specific metric").action(async c=>{let m=await r()(Mw,{query:{metricName:c}});W(m)});let i=e.command("traces").description("Search traces");i.command("search").description("Search spans").option("--from <timestamp>",`Start of time range${Ee("from")}`).option("--to <timestamp>",`End of time range${Ee("to")}`).option("--query <query>",`Search query${Ee("query")}`).option("--max-results <n>",`Maximum number of results${Ee("max-results")}`).action(async c=>{let m=await r()(qw,{query:zw(c)});W(m)}),i.command("summarize").description("Summarize a trace by aggregating groups of similar spans into summary spans").requiredOption("--trace-id <id>","Trace ID to summarize").option("--from <timestamp>",`Start of time range${Ee("from")}`).option("--to <timestamp>",`End of time range${Ee("to")}`).action(async c=>{let m=await r()(Fw,{query:{traceId:c.traceId,from:nt("from",c.from),to:nt("to",c.to)}});W(m)}),i.command("latency-summary").description("Summarize where wall-clock time is spent in a trace, attributed per service").requiredOption("--trace-id <id>","Trace ID to summarize").option("--from <timestamp>",`Start of time range${Ee("from")}`).option("--to <timestamp>",`End of time range${Ee("to")}`).option("--min-range-duration-ms <n>","Collapse timeline ranges shorter than this (default: max(1ms, 1% of trace duration); 0 disables collapsing)").option("--no-ranges","Omit the per-range timeline; return only services and serviceTotals").action(async c=>{let m={traceId:c.traceId,from:nt("from",c.from),to:nt("to",c.to)};if(c.minRangeDurationMs!==void 0){let f=Number(c.minRangeDurationMs);if(Number.isNaN(f))throw new Error(`--min-range-duration-ms must be a number (got: ${c.minRangeDurationMs})`);m.minRangeDurationMs=f}c.ranges||(m.includeRanges=!1);let l=await r()(Kw,{query:m});W(l)});let a=e.command("aggregation").description("Run aggregation queries");Wn(a,"scalar","Run aggregation queries and return scalar results",HS,r),Wn(a,"timeseries","Run aggregation queries and return timeseries results",zS,r)}var w3="x-tsuga-session-id",Uf="x-tsuga-source",wf="x-tsuga-source-version",Nf="x-tsuga-source-commit",Lf="x-tsuga-source-date",vf="x-tsuga-rationale",N3="x-tsuga-dashboard-id",L3="x-tsuga-widget-id",v3="x-request-id",tWe={[w3]:"Session identifier for request correlation",[Uf]:"SDK or client source identifier (e.g., web-frontend, terraform-provider)",[wf]:"SDK version",[Nf]:"SDK commit hash",[Lf]:"SDK commit date",[vf]:"Optional caller-supplied rationale for this request, recorded for telemetry",[N3]:"ID of the dashboard a query is issued from, when the request originates from a dashboard widget",[L3]:"ID of the dashboard widget (graph) a query is issued from, when the request originates from a dashboard widget",[v3]:"Unique identifier for this API request, useful for debugging and support"};var yn=class e extends Error{constructor(n,o,i,a,c){super(n);this.statusCode=o;this.code=i;this.requestId=a;this.details=c;this.name="CliError"}static fromErrorResponse(n,o){return new e(n.message,n.statusCode,n.code,o,n.details)}};function Zw(e){if(e instanceof yn){let r=[`Error: ${e.message}`];return e.code&&r.push(`Code: ${e.code}`),e.statusCode&&r.push(`Status: ${e.statusCode}`),e.requestId&&r.push(`Request ID: ${e.requestId}`),e.details&&r.push(`Details: ${JSON.stringify(e.details,null,2)}`),r.join(`
164
- `)}return e instanceof Error?`Error: ${e.message}`:String(e)}function k3(e){return e.replace(/\s+/g," ").replace(/[^\x20-\x7e\x80-\xff]/g,"").trim()}function Xw(e,r,n,o){return async function(a,c={}){let{body:m,params:l,query:f}=c,y;if(a.url!==void 0)y=a.url;else if(a.buildUrl){if(!l)throw new yn("Internal error: params required for this endpoint");y=a.buildUrl(l)}else throw new yn("Internal error: endpoint has neither url nor buildUrl");let E=n===void 0?f:{clusterId:n,...f},A=Sb(`${e}${y}`,E),ye={Accept:"application/json",Authorization:`Bearer ${r}`,[Uf]:"cli",[wf]:"1.5.0",[Nf]:"7de0834bcb",[Lf]:"2026-08-03T10:56:51.838Z"};m&&(ye["Content-Type"]="application/json");let Ue=o?.(),Mr=Ue?k3(Ue):"";Mr&&(ye[vf]=Mr);let ao=await fetch(A,{method:a.method,headers:ye,body:m?JSON.stringify(m):null}),hn;try{hn=await ao.json()}catch{throw new yn(ao.status===504?"The server timed out (504). Try a smaller time range.":`Server returned a non-JSON response (HTTP ${ao.status}).`,ao.status)}if(hn.error)throw yn.fromErrorResponse(hn.error,hn.requestId);return hn.data}}var M3=3e3,D3="https://registry.npmjs.org/@tsuga/cli/latest";function G3(e,r){let n=e.split(".").map(Number),o=r.split(".").map(Number);for(let i=0;i<Math.max(n.length,o.length);i++){let a=n[i]??0,c=o[i]??0;if(a>c)return!0;if(a<c)return!1}return!1}async function Jw(e){try{let r=Bb();if(r&&Date.now()-new Date(r).getTime()<Gs)return;let n=await fetch(D3,{signal:AbortSignal.timeout(M3)});if(!n.ok)return;let i=(await n.json()).version;G3(i,e)&&(process.stderr.write(`
164
+ `)}return e instanceof Error?`Error: ${e.message}`:String(e)}function k3(e){return e.replace(/\s+/g," ").replace(/[^\x20-\x7e\x80-\xff]/g,"").trim()}function Xw(e,r,n,o){return async function(a,c={}){let{body:m,params:l,query:f}=c,y;if(a.url!==void 0)y=a.url;else if(a.buildUrl){if(!l)throw new yn("Internal error: params required for this endpoint");y=a.buildUrl(l)}else throw new yn("Internal error: endpoint has neither url nor buildUrl");let E=n===void 0?f:{clusterId:n,...f},A=Sb(`${e}${y}`,E),ye={Accept:"application/json",Authorization:`Bearer ${r}`,[Uf]:"cli",[wf]:"1.5.1",[Nf]:"3e1fa91409",[Lf]:"2026-08-03T11:18:29.300Z"};m&&(ye["Content-Type"]="application/json");let Ue=o?.(),Mr=Ue?k3(Ue):"";Mr&&(ye[vf]=Mr);let ao=await fetch(A,{method:a.method,headers:ye,body:m?JSON.stringify(m):null}),hn;try{hn=await ao.json()}catch{throw new yn(ao.status===504?"The server timed out (504). Try a smaller time range.":`Server returned a non-JSON response (HTTP ${ao.status}).`,ao.status)}if(hn.error)throw yn.fromErrorResponse(hn.error,hn.requestId);return hn.data}}var M3=3e3,D3="https://registry.npmjs.org/@tsuga/cli/latest";function G3(e,r){let n=e.split(".").map(Number),o=r.split(".").map(Number);for(let i=0;i<Math.max(n.length,o.length);i++){let a=n[i]??0,c=o[i]??0;if(a>c)return!0;if(a<c)return!1}return!1}async function Jw(e){try{let r=Bb();if(r&&Date.now()-new Date(r).getTime()<Gs)return;let n=await fetch(D3,{signal:AbortSignal.timeout(M3)});if(!n.ok)return;let i=(await n.json()).version;G3(i,e)&&(process.stderr.write(`
165
165
  Update available: ${e} \u2192 ${i}
166
- `),process.stderr.write("Run `tsuga self-update` to update\n")),Fb(new Date().toISOString())}catch{}}var Qe=new Vf().name("tsuga").description("Tsuga CLI - manage resources from the command line").version("1.5.0").option("--operation-api-key <operation-api-key>","Operation API key").option("--cluster <cluster-id>","Target cluster (overrides config and TSUGA_CLUSTER_ID)"),kp,eN;function kr(){if(kp)return kp;let e=Qe.opts(),r=Do({operationApiKey:e.operationApiKey,clusterId:e.cluster});Ms(r.credential,new Date)&&(console.error("Your session expired. Run `tsuga auth login` to sign in again."),process.exit(1));let n=Lb(r);return n||(console.error("Error: no credentials. Authenticate with one of:"),console.error(" tsuga auth login # log in as a user (OAuth)"),console.error(" tsuga auth operation-key <operation-api-key> # save an operation API key"),console.error(" export TSUGA_OPERATION_API_KEY=<operation-api-key>"),console.error(" tsuga --operation-api-key <operation-api-key> <command>"),process.exit(1)),kp=Xw(r.apiUrl,n,r.clusterId,()=>eN),kp}Kb(Qe);aS(Qe);var $3=new Set(Qe.commands);sw(Qe,kr);Ww(Qe,kr);KR(Qe,kr);QR(Qe,kr);wC(Qe,kr);lS(Qe,kr);Yx(Qe,kr);rS(Qe,kr);Fx(Qe,kr);_w(Qe);JR(Qe);pw(Qe);iS(Qe);function tN(e){for(let r of e.commands)r.commands.length===0&&r.option("--rationale <text>",'Why you are making this call, e.g. "confirming the deploy caused the error spike". Recorded to explain intent; does not affect the result.'),tN(r)}for(let e of Qe.commands)$3.has(e)||tN(e);Qe.hook("preAction",(e,r)=>{let{rationale:n}=r.opts();eN=n});Qe.parseAsync().then(()=>Jw("1.5.0")).catch(e=>{console.error(Zw(e)),process.exitCode=1});
166
+ `),process.stderr.write("Run `tsuga self-update` to update\n")),Fb(new Date().toISOString())}catch{}}var Qe=new Vf().name("tsuga").description("Tsuga CLI - manage resources from the command line").version("1.5.1").option("--operation-api-key <operation-api-key>","Operation API key").option("--cluster <cluster-id>","Target cluster (overrides config and TSUGA_CLUSTER_ID)"),kp,eN;function kr(){if(kp)return kp;let e=Qe.opts(),r=Do({operationApiKey:e.operationApiKey,clusterId:e.cluster});Ms(r.credential,new Date)&&(console.error("Your session expired. Run `tsuga auth login` to sign in again."),process.exit(1));let n=Lb(r);return n||(console.error("Error: no credentials. Authenticate with one of:"),console.error(" tsuga auth login # log in as a user (OAuth)"),console.error(" tsuga auth operation-key <operation-api-key> # save an operation API key"),console.error(" export TSUGA_OPERATION_API_KEY=<operation-api-key>"),console.error(" tsuga --operation-api-key <operation-api-key> <command>"),process.exit(1)),kp=Xw(r.apiUrl,n,r.clusterId,()=>eN),kp}Kb(Qe);aS(Qe);var $3=new Set(Qe.commands);sw(Qe,kr);Ww(Qe,kr);KR(Qe,kr);QR(Qe,kr);wC(Qe,kr);lS(Qe,kr);Yx(Qe,kr);rS(Qe,kr);Fx(Qe,kr);_w(Qe);JR(Qe);pw(Qe);iS(Qe);function tN(e){for(let r of e.commands)r.commands.length===0&&r.option("--rationale <text>",'Why you are making this call, e.g. "confirming the deploy caused the error spike". Recorded to explain intent; does not affect the result.'),tN(r)}for(let e of Qe.commands)$3.has(e)||tN(e);Qe.hook("preAction",(e,r)=>{let{rationale:n}=r.opts();eN=n});Qe.parseAsync().then(()=>Jw("1.5.1")).catch(e=>{console.error(Zw(e)),process.exitCode=1});
167
167
  /**
168
168
  * The following is a list of HTTP status codes and their meanings.
169
169
  *
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tsuga/cli",
3
3
  "description": "Tsuga CLI - manage resources from the command line",
4
- "version": "1.5.0",
4
+ "version": "1.5.1",
5
5
  "bin": {
6
6
  "tsuga": "dist/cli.js"
7
7
  },
@@ -23,6 +23,7 @@
23
23
  "files": [
24
24
  "dist"
25
25
  ],
26
+ "homepage": "https://tsuga.com",
26
27
  "keywords": [
27
28
  "cli",
28
29
  "dashboards",
@@ -33,14 +34,10 @@
33
34
  "traces",
34
35
  "tsuga"
35
36
  ],
37
+ "license": "MIT",
36
38
  "publishConfig": {
37
39
  "access": "public"
38
40
  },
39
- "repository": {
40
- "type": "git",
41
- "url": "git+https://github.com/tsuga-dev/typescript.git",
42
- "directory": "packages/cli"
43
- },
44
41
  "scripts": {
45
42
  "build": "yarn clean && node esbuild.js",
46
43
  "clean": "rm -rf dist",