mcpField
I
incidentio-cli

incidentio-cli

github.com/paymog云与 DevOps09.2k 次安装14 周前更新
代码仓库

关于 incidentio-cli

incidentio-cli 是 incident.io 的命令行接口,适合通过 JSON 命令管理事故、告警、排班和服务目录。它依据官方 OpenAPI 规范生成命令,同时区分公开 API 与需要浏览器会话的内部接口。

主要功能

  1. 01按官方 OpenAPI 规范生成命令
  2. 02管理事故、告警和升级流程
  3. 03查询排班、目录及配置资源
  4. 04支持 Bearer API 密钥认证
  5. 05可选浏览器会话调用内部 API

适用场景

  1. 01查询或创建事故
  2. 02处理告警并查看升级状态
  3. 03维护排班和服务目录条目
  4. 04通过内部接口查询仪表板与策略

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/paymog/incidentio-cli --skill incidentio-cli

安装后在 Claude Code 中输入/incidentio-cli确认已加载。

详细介绍

incident.io CLI

调用 incidentio 二进制文件。权威来源:paymog/incidentio-cli。

与 blacksmith 的 cookie-replay 不同,incident.io 有一个由 Bearer 令牌认证的真正的公共 API。incidentio 直接调用该 API——无需浏览器,也无需 Cookie。命令根据 incident.io 官方 OpenAPI 规范生成(每个资源标签对应一份规范),因此所有有文档记录的端点都可用。API 基础 URL 为 https://api.incident.io。

身份验证(执行任何命令前都必须完成)

需要一个 Bearer API 密钥。在 Settings → API keys (app.incident.io/settings/api-keys) 中创建;创建时可以选择其作用域(例如 incidents.create),创建后作用域集合将固定不变。

incidentio auth set <api-key>     # store it (chmod 600, ~/.config/incidentio/creds.json)
incidentio auth status            # show masked key + last-updated
incidentio auth logout            # clear stored credentials

解析顺序:--api-key <key> 标志 → $INCIDENT_API_KEY → 已存储的凭据。对于一次性使用或 CI,导出 INCIDENT_API_KEY 即可跳过 auth set。

401/403 表示密钥无效、已撤销,或缺少端点所需的作用域(例如,使用只读密钥调用 incidents create)。请在控制面板中重新检查密钥的作用域。

用法

incidentio list [filter]         # every command (optionally filtered by substring)
incidentio list incidents        # all verbs for the `incidents` resource
incidentio <resource> <verb> [flags]

命令由两个词元组成:<resource> <verb>。输出为格式化的 JSON——可以通过管道传给 jq,或传入 --raw 获取未格式化的响应。

标志
标志含义
--api-key <key>此次调用使用的 API 密钥(否则使用 $INCIDENT_API_KEY 或已存储的密钥)
--<param> <value>路径参数:--id、--user-id、--schedule-id、--alert-source-config-id
--query key=value查询参数,可重复使用(包括方括号过滤器——见下文)
--body-file <path>从文件读取 JSON 请求正文(用于 POST/PUT)
--body-json '<json>'内联 JSON 请求正文
--set a.b=value设置正文中的字段,可重复使用
--raw输出原始响应,不进行 JSON 格式化
--auth cookie|bearer(仅限 raw)强制指定身份验证模式;否则根据路径推断
方括号查询过滤器

列表端点使用方括号键(Rails 风格)。将其原样传给 --query;多值过滤器可重复传入。incident.io 的列表过滤器功能强大,但有文档记录的参数名称会显示在 incidentio list <resource> 输出中。

# incidents in the "live" status category, severity rank >= a given severity
incidentio incidents list --query 'status_category[one_of]=live' --query 'severity[gte]=<sev-id>'
# created within a date range (tilde-separated)
incidentio incidents list --query 'created_at[date_range]=2026-06-01~2026-06-30'
# any-of multiple modes
incidentio incidents list --query 'mode[one_of]=standard' --query 'mode[one_of]=retrospective'

日期使用 ISO-8601 UTC 格式(2026-06-04T00:00:00.000Z)。要获取“现在”的时间,请计算:date -u +%FT%T.000Z(macOS)或 date -u -d '30 days ago' +%FT%T.000Z(GNU)。

命令范围

运行 incidentio list 可查看权威命令列表(约 324 个命令:涵盖 53 个资源的约 179 个公共 Bearer API 命令,另有约 145 个标记为 🍪 的内部/控制面板命令,以及 raw 备用入口)。以下为分类重点命令(除非另有说明,均为 GET):

事件
incidentio incidents list [--query status[one_of]=<id>] [--query page_size=50]
incidentio incidents show --id <id>
incidentio incidents create --body-json '{"name":"...","severity_id":"...","visibility":"public"}'
incidentio incidents edit --id <id>            # edit fields/status of an incident
incidentio incidents import-postmortem-document --id <id>
操作、后续跟进、附件
incidentio actions list --query incident_id=<id>
incidentio follow-ups list --query incident_id=<id>
incidentio follow-ups create --body-json '{"incident_id":"...","content":"..."}'
incidentio follow-ups connect-external-issue --id <id> --body-json '{...}'
incidentio incident-attachments list --query incident_id=<id>
告警与告警来源
incidentio alerts list
incidentio alerts show --id <id>
incidentio alerts resolve --id <id>
incidentio alert-sources list
incidentio alert-routes list
incidentio alert-routes show --id <id>
incidentio alert-routes update --id <id> --body-json '{...}'   # public API, no version field
incidentio alert-events create-http --alert-source-config-id <id> --body-json '{...}'
incidentio heartbeat ping --alert-source-config-id <id>   # GET ping

# Alert route with incident-template custom-field binding (🍪 dashboard API)
# Rules:
#   1. version = current_version + 1 (optimistic concurrency — GET it first).
#   2. OMIT the `users` key from every escalation_config.escalation_targets entry;
#      the GET payload carries an invalid users binding that PUT rejects. API restores it.
#   3. Custom-field bindings: static option OR navigation-expression reference.
#      Static:     array_value:[{reference:"",value:"<opt-id>",label:"<label>",sort_key:0}]
#      Expression: array_value:[{reference:"expressions[\"<expr-ref>\"]"}]
#   4. Navigation expressions (derive component array from Service catalog attribute):
#      Declare in top-level `expressions` array; bind by reference in custom_fields.
# merge_strategy: "first-wins" | "last-wins" | "append"
incidentio alert-routes show-route --id <route-id>
incidentio alert-routes update-route --id <route-id> --body-json '{
  "version":4,
  "escalation_config":{"escalation_targets":[
    {"type":"schedule","id":"<sched-id>"}
  ]},
  "incident_template":{
    "custom_fields":[{
      "custom_field_id":"<field-id>",
      "merge_strategy":"first-wins",
      "binding":{"array_value":[{"reference":"","value":"<option-id>","label":"<label>","sort_key":0}]}
    }]
  }}'
# With a catalog navigation expression (auto-derive Affected Components from alert Service):
incidentio alert-routes update-route-expr --id <route-id> --body-json '{
  "version":5,
  "expressions":[{
    "id":"01EXPR001","label":"Affected Components","reference":"affected_components",
    "returns":{"type":"CatalogEntry[\"<component-type-id>\"]","array":true},
    "root_reference":"alert.attributes.<service-alert-attr-id>",
    "operations":[{"operation_type":"navigate",
      "returns":{"type":"CatalogEntry[\"<component-type-id>\"]","array":true},
      "navigate":{"reference":"catalog_attribute[\"components\"]","reference_label":"Components"}}]
  }],
  "incident_template":{
    "custom_fields":[{
      "custom_field_id":"<affected-components-field-id>",
      "merge_strategy":"first-wins",
      "binding":{"array_value":[{"reference":"expressions[\"affected_components\"]"}]}
    }]
  }}'
升级与值班安排
incidentio escalations list [--query status=active]
incidentio escalations create --body-json '{...}'
incidentio escalations cancel-escalation --id <id>
incidentio escalation-paths list
incidentio schedules list
incidentio schedules show --id <id>
incidentio schedule-entries list --schedule-id <id>
incidentio schedule-overrides list --schedule-id <id>
incidentio schedule-replicas list --schedule-id <id>
目录(以代码形式管理服务目录)
# Public API (Bearer)
incidentio catalog-types list
incidentio catalog-types show --id <type-id>            # includes .schema.attributes[].id
incidentio catalog-types create --body-json '{...}'
incidentio catalog-types update-type-schema --id <id> --body-json '{...}'
incidentio catalog-entries list --query catalog_type_id=<id>
incidentio catalog-entries create --body-json '{...}'   # simple entries
incidentio catalog-entries update --id <id> --body-json '{...}'
incidentio catalog-entries bulk-update-entries --body-json '{...}'
incidentio catalog-resources list

# Catalog entries with attribute_values (🍪 dashboard API — verified contract)
# Required body: catalog_type_id, name, external_id, attribute_values (pass {} when none)
# Attribute shapes:
#   plain text:       {"<attr-id>":{"value":"some text"}}
#   catalog-relation: {"<attr-id>":{"array_value":["<entry-id>",...]}}
#   intentional clear (create only): {"<attr-id>":{"value":null}}
# Get attribute IDs: incidentio catalog-types show --id <type-id> | jq '.catalog_type.schema.attributes[].id'
incidentio catalog-entries create-entry --body-json '{
  "catalog_type_id":"<type-id>",
  "name":"My Service",
  "external_id":"my-service",
  "attribute_values":{
    "<attr-id>":{"value":"production"},
    "<rel-attr-id>":{"array_value":["<related-entry-id>"]}
  }}'
incidentio catalog-entries update-entry --id <entry-id> --body-json '{
  "name":"My Service",
  "attribute_values":{"<attr-id>":{"value":"staging"}}}'
配置(自定义字段、严重级别、类型、角色、状态、时间戳)
# Public API (Bearer)
incidentio custom-fields list
incidentio custom-fields create --body-json '{...}'      # basic fields
incidentio custom-field-options list --query custom_field_id=<id>
incidentio severities list
incidentio incident-types list
incidentio incident-roles list
incidentio incident-statuses list
incidentio incident-timestamps list

# Catalog-backed multi-select custom field (🍪 dashboard API — supports catalog_type_id,
# field_mode, condition_groups not available in the public API)
# Required body: name, description, field_type:"multi_select", catalog_type_id, field_mode,
#   dynamic_options, cannot_be_unset, options, condition_groups
incidentio custom-fields create-catalog-backed --body-json '{
  "name":"Affected Services",
  "description":"Which services are affected by this incident",
  "field_type":"multi_select",
  "catalog_type_id":"<catalog-type-id>",
  "field_mode":"dashboard",
  "dynamic_options":true,
  "cannot_be_unset":false,
  "options":[],
  "condition_groups":[]}'
状态页面
# Read (Bearer public API)
incidentio status-pages list
incidentio status-pages show --status-page-id <id>          # includes current_structure
incidentio status-page-incidents list --query status_page_id=<id>
incidentio status-page-maintenances list --query status_page_id=<id>

# Manage the page itself (🍪 internal — the public API cannot create pages/components)
# Simple page:
incidentio status-pages create --body-json '{"name":"Acme","subpath":"acme","theme":"light"}'
# Catalog-backed parent page with auto-generated sub-pages per catalog entry:
incidentio status-pages create --body-json '{
  "name":"Acme","subpath":"acme","theme":"light",
  "parent_page_options":{
    "page_type":"parent",
    "split_by_catalog_type_id":"<catalog-type-id>",
    "split_by_component_attribute_id":"<component-attr-id>",
    "sub_pages":[
      {"defined_by_catalog_entry_id":"<entry-id>","name":"Team A","subpath":"team-a"}
    ]
  }}'
# Update — name, subpath, support_label are ALL required even for a single-field change:
incidentio status-pages update --status-page-id <id> --body-json '{"name":"Acme","subpath":"acme","support_label":"Report a problem","allow_search_engine_indexing":false}'
incidentio status-page-components create --body-json '{"name":"API","status_page_id":"<id>"}'
incidentio status-page-components delete --id <component-id>
incidentio status-page-structures create --body-json '{"status_page_id":"<id>","items":[
  {"group":{"name":"Core","display_aggregated_uptime":true,"hidden":false,"components":[
    {"component_id":"<id>","display_uptime":true,"hidden":false}]}},
  {"component":{"component_id":"<id>","display_uptime":true,"hidden":false}}]}'

# Audit subscribers / templates (🍪)
incidentio status-page-subscriptions --query status_page_id=<id>
incidentio status-page-templates --query status_page_id=<id>

# Retrospective status-page incident (Bearer) — bulk-import historical incidents
incidentio status-page-incidents create-status-page-retrospective-incident --body-json '{
  "status_page_id":"<id>",
  "name":"Elevated API latency",
  "idempotency_key":"historical-2021-08-17",
  "updates":[
    {"incident_status":"investigating","message":"Looking into it.","published_at":"2021-08-17T13:28:57Z"},
    {"incident_status":"resolved","message":"Fixed.","published_at":"2021-08-17T14:00:00Z",
     "component_statuses":[{"component_id":"<id>","component_status":"operational"}]}
  ]}'

说明:创建页面、设置品牌样式以及定义页面组件/布局仅限内部使用(需要 Cookie 会话);公共 Bearer API 仅支持列出/显示页面,以及发布事件/维护信息。公共页面的组件是页面原生对象(先创建组件,再使用 status-page-structures 放置),并非自定义字段(该模型用于内部页面)。theme 的值为 light|dark。Team 套餐仅允许创建一个公共页面(第二次调用 create 会返回 422 exceeded your allowance)。Logo、favicon 和品牌颜色需在控制面板中上传。

对于基于目录的父页面:split_by_catalog_type_id 和 split_by_component_attribute_id 用于标识子页面所基于的目录类型,以及该类型中指向组件的属性;每个 sub_pages 条目都将一个目录条目映射到一个子页面 slug。

用户、团队、API 密钥、工作流、密钥
incidentio users list --query email=<email>
incidentio users show --id <id>
incidentio teams list
incidentio api-keys list
incidentio api-keys rotate --id <id>
# api-keys create/update accept optional `comments` string

# Workflows (public Bearer CRUD)
incidentio workflows list
incidentio workflows show --id <id>
incidentio workflows create --body-json '{...}'   # public shape — see OpenAPI
incidentio workflows update --id <id> --body-json '{...}'

# Secrets store (public Bearer — prefer this for scripting)
# Create: {name, value, description?, owning_team_ids?}
# Rotate: {value} — bumps version; value never returned (only last_four_chars)
incidentio secrets list [--query team_ids=<id>]
incidentio secrets show --id <id>                 # includes versions[] history
incidentio secrets create --body-json '{"name":"pagerduty_token","value":"..."}'
incidentio secrets rotate --id <id> --body-json '{"value":"new-secret"}'
incidentio secrets update --id <id> --body-json '{"name":"pagerduty_token"}'
incidentio secrets delete --id <id>
日常维护
incidentio utilities identity              # validate the key + show the identity
incidentio maintenancewindows list
incidentio ipallowlists show
incidentio telemetry update --id <id> --body-json '{...}'

Dashboard / 内部 API(🍪 — 需要浏览器会话)

这些命令会访问 app.incident.io/api/*,该接口拒绝 API 密钥(“Cannot use API keys to authenticate to internal APIs”)。它们会重放已登录的浏览器会话。请先导入一个会话:

# devtools → Network → right-click any /api/ request → Copy as cURL
incidentio auth import '<paste curl>'        # or: pbpaste | incidentio auth import
incidentio auth set-org 01G9XY4BZ7YGBPJ3K50NB30YXS   # x-incident-organisation-id (auto-captured from the curl if present)

然后,list 中标记为 🍪 的命令即可使用。以下是一些亮点——公共 API 无法实现的功能:

incidentio saved-views --query context=incidents     # saved filter views
incidentio insights trends --query start_date=2026-06-01 --query end_date=2026-06-30
incidentio insights custom-dashboards
incidentio policies                                 # policy list
incidentio policies update --id <id> --body-json '{...}'  # flip run_on_private_incidents etc.
incidentio secrets list-internal                  # cookie twin of public secrets.*
incidentio workflows triggers                     # alert.updated|attached, scheduled, ...
incidentio workflows show-internal --id <id>      # expands webhook.send signing params
incidentio workflows create-internal --body-json '{
  "trigger":"alert.updated",
  "workflow":{"name":"...","once_for":["alert"],"condition_groups":[],"steps":[],"expressions":[],
    "runs_on_incident_modes":["standard"],"continue_on_step_error":false,
    "runs_on_incidents":"newly_created","state":"draft","private_incident_scope":"none"}}'
incidentio policy-violations
incidentio incident-timelines timeline --incident-timeline <id>            # full timeline
incidentio incident-timelines activity-log --incident-timeline <id>        # activity log
incidentio debriefs incident-debriefs --query incident_id=<id>
incidentio incident-suggestions for-incident --query incident_id=<id>      # AI suggestions
incidentio postmortems templates --query incident_id=<id>
incidentio schedule-reports
incidentio user-preferences
incidentio identity self                  # who am I + scopes (dashboard identity)

🍪 命令返回 401 "No authorization material",表示会话 Cookie 未被识别(错误或已过期)——请重新导入一份最新的 Copy-as-CURL。组织 ID 的解析顺序为 --org → $INCIDENT_ORG_ID → 已存储的值。

原始请求和新端点的逆向工程

并非每个端点都已编入代码。incidentio raw <METHOD> </path> 使用已存储的凭据访问任意端点,是探测和逆向工程内部路由的快捷方式:

incidentio raw GET  /api/status_pages                    # cookie inferred (/api/*)
incidentio raw GET  /v2/incidents --query page_size=1    # bearer inferred (else)
incidentio raw POST /api/status_pages --body-json '{}'   # probe: 422 names required fields
incidentio raw PUT  /api/settings/self --body-json '{...}'   # tune a setting
incidentio raw DELETE /api/status_pages/<id> --auth cookie

身份验证方式会自动推断(/api/* → Cookie,否则使用 bearer);可通过 --auth cookie|bearer 覆盖。可直接在路径中内联任意 ID(raw 不会替换 :param)。

将新端点编入代码(步骤):

  1. 使用空请求体或部分请求体进行探测:incidentio raw POST /api/<thing> --body-json '{}'。
  2. 阅读 422 validation_error——source.field / 消息会指出必填字段;使用故意无效的枚举值重试,以了解允许的值。
  3. 在 src/commands/manual-internal.ts 中添加一个 Command(加载时会合并该文件中的命令,且 HAR 重新生成后仍会保留),然后运行 bun run build。

操作指南

验证 API 密钥
incidentio utilities identity | jq '.identity'
按最新顺序列出未关闭的事件
incidentio incidents list --query 'status_category[one_of]=live' \
  | jq '.incidents[] | {id, name, severity: .severity.name, status: .incident_status.name}'
分页浏览列表(游标分页)

list 响应包含 pagination_meta.after 游标;将其作为 --query after=<cursor> 传回:

incidentio incidents list --query page_size=250 > first.json
AFTER=$(jq -r '.pagination_meta.after // empty' first.json)
[ -n "$AFTER" ] && incidentio incidents list --query page_size=250 --query "after=$AFTER" > second.json
声明事件
incidentio incidents create --body-json '{
  "name": "API 5xx spike",
  "severity_id": "<sev-id>",
  "summary": "Elevated 5xx from the edge.",
  "visibility": "public"
}' | jq '.incident.id'

需要先获取严重性 / 状态 ID?请运行 incidentio severities list / incidentio incident-statuses list。

资源支持哪些动词?
incidentio list schedules      # shows list/create/show/update/delete + nested schedule-entries/overrides/replicas
incidentio list catalog-entries   # shows create/create-entry (🍪)/update/update-entry (🍪)/...
创建带有组件关系的目录条目(🍪)
# 1. Get the catalog type's attribute IDs
incidentio catalog-types show --id <type-id> | jq '.catalog_type.schema.attributes[] | {id, name}'

# 2. Create an entry with attribute values
incidentio catalog-entries create-entry --body-json '{
  "catalog_type_id":"<type-id>",
  "name":"payments-service",
  "external_id":"payments-service",
  "attribute_values":{
    "<team-attr-id>":{"array_value":["<team-catalog-entry-id>"]},
    "<tier-attr-id>":{"value":"tier-1"}
  }}'
更新告警路由以绑定自定义字段(🍪)
# 1. GET current route — capture version and escalation_targets (you'll need to strip `users`)
VERSION=$(incidentio alert-routes show-route --id <route-id> | jq '.version')

# 2. PUT with version+1. Two critical rules:
#    a) version = $VERSION + 1 (optimistic concurrency)
#    b) omit `users` from every escalation_config.escalation_targets entry
#       (the GET payload has an invalid users binding the PUT rejects; API restores it after PUT)
incidentio alert-routes update-route --id <route-id> --body-json '{
  "version":'$((VERSION+1))',
  "name":"My Route",
  "escalation_config":{"escalation_targets":[
    {"type":"schedule","id":"<sched-id>"}
  ]},
  "incident_template":{
    "custom_fields":[{
      "custom_field_id":"<field-id>",
      "merge_strategy":"first-wins",
      "binding":{"array_value":[{"reference":"","value":"<option-id>","label":"P1 - Critical","sort_key":0}]}
    }]
  }}'
通过目录导航表达式,从告警 Service 派生受影响的组件(🍪)

导航表达式可让告警路由通过目录关系(例如 Components),从告警属性(例如 Service)导航,从而自动填充目录关联的自定义字段。

# 1. Find the IDs you need:
#    - service-alert-attr-id: the alert source attribute ID for the Service field
#    - component-type-id: catalog type ID for Components (incidentio catalog-types list)
#    - affected-components-field-id: the incident custom field ID (incidentio custom-fields list)
VERSION=$(incidentio alert-routes show-route --id <route-id> | jq '.version')

# 2. PUT the route with an expression + expression-reference binding.
#    Same rules: version+1, omit users from escalation_targets.
incidentio alert-routes update-route-expr --id <route-id> --body-json '{
  "version":'$((VERSION+1))',
  "escalation_config":{"escalation_targets":[{"type":"schedule","id":"<sched-id>"}]},
  "expressions":[{
    "id":"<expr-id>",
    "label":"Affected Components",
    "reference":"affected_components",
    "returns":{"type":"CatalogEntry[\"<component-type-id>\"]","array":true},
    "root_reference":"alert.attributes.<service-alert-attr-id>",
    "operations":[{
      "operation_type":"navigate",
      "returns":{"type":"CatalogEntry[\"<component-type-id>\"]","array":true},
      "navigate":{"reference":"catalog_attribute[\"components\"]","reference_label":"Components"}
    }]
  }],
  "incident_template":{
    "custom_fields":[{
      "custom_field_id":"<affected-components-field-id>",
      "merge_strategy":"first-wins",
      "binding":{"array_value":[{"reference":"expressions[\"affected_components\"]"}]}
    }]
  }}'
# After a successful PUT the API echoes the expressions array back intact.

注意:

  • root_reference 指向存有 Service 目录条目的告警来源属性。
  • operations[0].navigate.reference 是 Service 类型上存有其组件条目的目录属性名称(可通过 incidentio catalog-types show --id <service-type-id> 验证)。
  • 表达式的 reference 值会成为 expressions["<reference>"] 绑定中的键。
  • Affected Components 自定义字段必须是通过 custom-fields create-catalog-backed(Dashboard 内部 API)创建的目录关联 multi_select,并以 Component 目录类型为目标。
密钥、签名 Webhook、由告警触发的工作流
# List triggers (🍪) — includes alert.updated, alert.attached, scheduled
incidentio workflows triggers | jq '.triggers[] | select(.name|test("alert|scheduled"))'

# Create an alert-triggered workflow (🍪). NOTE the split body: top-level `trigger`
# string + nested `workflow` object. Public `workflows create` uses a flatter shape.
incidentio workflows create-internal --body-json '{
  "trigger":"alert.updated",
  "workflow":{
    "name":"Alert resolved webhook",
    "once_for":["alert"],
    "condition_groups":[],
    "steps":[{
      "id":"step1",
      "name":"webhook.send",
      "param_bindings":[
        {"value":{"literal":"https://example.com/hook"}},
        {"value":{"literal":"POST"}},
        {"array_value":[{"literal":"Authorization: Bearer {{secrets.my_token}}"}]},
        {"value":{"literal":"{\"ok\":true}"}},
        {"value":{"literal":"<secret-id>"}},
        {"value":{"literal":""}},
        {"value":{"literal":"X-Signature"}}
      ]
    }],
    "expressions":[],
    "runs_on_incident_modes":["standard"],
    "continue_on_step_error":false,
    "runs_on_incidents":"newly_created",
    "state":"draft",
    "private_incident_scope":"none"
  }}'

# webhook.send param order (from show-internal): endpoint, method, headers
# (TemplatedText plain_single_line_with_secrets), body, signing_secret (type Secret),
# generated_signing_secret, signature_header_name (HMAC-SHA256).
# Prefer public `secrets create` for the signing secret when you have a Bearer key.
将策略设为允许私人事件(🍪)
# GET first — subjects/operations come back as expanded objects
incidentio policies | jq '.policies[] | {id,name,run_on_private_incidents}'

# PUT write shape differs: subject/operation are bare strings; follow_up needs due_date_config
incidentio policies update --id <id> --body-json '{
  "enabled":true,
  "name":"...",
  "description":"...",
  "policy_type":"follow_up",
  "conditions":[{"conditions":[{"subject":"incident.severity","operation":"gte",
    "param_bindings":[{"value":{"literal":"<sev-id>"}}]}]}],
  "requirements":{"conditions":[{"conditions":[{"subject":"follow_up.status","operation":"not_one_of",
    "param_bindings":[{"array_value":[{"literal":"outstanding"}]}]}]}]},
  "run_on_private_incidents":true,
  "due_date_config":{"incident_timestamp_id":"<ts-id>","days":{"value":{"literal":"30"}},
    "calculation_type":"seven_days"}
}'

重新生成命令目录

命令位于 src/commands/generated.ts,由 incident.io 按标签划分的 OpenAPI 规范生成(实时从 docs.incident.io 获取):

bun run codegen

生成器会从 docs.incident.io/llms.txt 中发现 REST 标签集,获取每个 /openapi/tags/<tag>.json,为每个操作生成 <resource> <verb> 名称,并解决名称冲突(例如 catalog-types update-type 与 update-type-schema;heartbeat ping 与 ping-post)。重新生成后,运行构建(bun run build)。

通过 bun run codegen:har <a.har> [b.har ...],从捕获的浏览器 HAR 文件生成仪表板/内部命令。它会收集 GET 和写入端点(POST→create、PUT/PATCH→update、DELETE→delete),将 ULID/Slack ID 替换为 :param,剔除公共 Bearer API 已涵盖的端点,并覆盖 generated-internal.ts——因此,请在一次调用中传入所有想要纳入的 HAR 文件(例如 app.incident.io.har app.incident.io2.har app.incident.io3.har)。未出现在任何 HAR 中、经人工核验的内部端点(例如状态页的 create/update/components/structures)位于 src/commands/manual-internal.ts,并在加载时合并,因此重新生成不会影响它们。

常见问题

not authenticated

未通过标志、环境变量或存储找到密钥。运行 incidentio auth set <key> 或 export INCIDENT_API_KEY=<key>。

HTTP 401 / HTTP 403(公共/Bearer 命令)

密钥无效/已过期,或缺少端点所需的权限范围(例如,只读密钥调用写入动词)。在 Settings → API keys 中检查密钥的权限范围;权限范围在创建时固定——如需更多权限,请轮换密钥或创建新密钥。

needs a browser session / 401 "No authorization material"(🍪 仪表板命令)

仪表板命令(app.incident.io/api/*)不接受 API 密钥。它们需要已登录的浏览器会话:通过 incidentio auth import <curl> 重新导入(在 app.incident.io 中使用 Copy-as-cURL),并确保已设置组织 ID(使用 auth set-org 或 --org)。Chrome/Brave 导出的 HAR 通常会去掉 Cookie——请使用 Copy-as-cURL。

HTTP 422,并显示验证消息

请求体/查询参数格式错误(缺少必填字段、枚举值无效或类型错误)。错误正文会指出有问题的 source.field——请修正 --body-json/--query/--set 的值。

HTTP 429

触发速率限制(默认每个密钥每分钟 1200 个请求)。错误正文包含 rate_limit.retry_after。请稍后重试,不要持续发送请求。

unknown command

命令格式为 <resource> <verb>。运行 incidentio list <resource> 查看确切的动词。如果只输入资源,CLI 会提示其动词。CRUD 动词会合并显示(incidents list/create/show/update/delete);非 CRUD 操作保留其名称(incidents edit、escalations cancel-escalation、catalog-entries bulk-update-entries)。

缺少端点

该端点不在生成的目录中。重新运行 bun run codegen 以纳入新发布的 incident.io 端点,然后重新构建。

评论

支持 Markdown