@vess-id/ai-identity 0.17.0 → 0.18.0

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.
package/dist/index.js CHANGED
@@ -4184,7 +4184,7 @@ function validateRegistryObject(registry) {
4184
4184
  for (const a of typed.actions) {
4185
4185
  if (a.input_schema) {
4186
4186
  try {
4187
- const local = new import_ajv.default({ strict: true, allErrors: true });
4187
+ const local = new import_ajv.default({ strict: true, allErrors: true, allowUnionTypes: true });
4188
4188
  (0, import_ajv_formats.default)(local);
4189
4189
  const compiled = local.compile(a.input_schema);
4190
4190
  if (compiled.errors?.length) {
@@ -7750,471 +7750,1464 @@ var ACTION_REGISTRY = {
7750
7750
  target_bindings: { resource_id: { source: "param", param: "portalId" } },
7751
7751
  version: "1.0.0"
7752
7752
  },
7753
- // ─── Agent Inbox Actions (internal) ───
7754
- // Inbox actions back the Agent Inbox MCP tools (task delegation between
7755
- // agents/people). They are internal (no external OAuth provider), so they
7756
- // carry a single nominal base scope `inbox` to satisfy the registry
7757
- // meta-schema's `minItems: 1` (same pattern as hubspot.account.link.get).
7753
+ // ─── Linear Actions ───
7758
7754
  {
7759
- action: "inbox.send",
7760
- resource_type: "inbox:item",
7761
- required_relations: ["editor", "act_as"],
7762
- required_scopes: ["inbox"],
7763
- capability: "inbox.write",
7755
+ action: "linear.issue.list",
7756
+ resource_type: "linear:issue",
7757
+ required_relations: ["viewer", "editor", "admin", "owner"],
7758
+ required_scopes: ["read"],
7759
+ capability: "linear.read.basic",
7764
7760
  input_schema: {
7765
7761
  type: "object",
7766
7762
  properties: {
7767
- to: { type: "string", minLength: 1, description: "Recipient (user id / handle) the task request is sent to" },
7768
- taskType: { type: "string", minLength: 1, description: "Type of task being requested" },
7769
- payload: { type: "object", description: "Task-specific payload data" },
7770
- message: { type: "string", description: "Optional human-readable message" }
7763
+ teamId: { type: "string", description: "Filter by team ID" },
7764
+ assigneeId: { type: "string", description: "Filter by assignee user ID" },
7765
+ assigneeMe: { type: "boolean", description: "If true, filter issues assigned to the authenticated user" },
7766
+ stateId: { type: "string", description: "Filter by workflow state ID" },
7767
+ priority: { type: "number", minimum: 0, maximum: 4, description: "0=No priority, 1=Urgent, 2=High, 3=Medium, 4=Low" },
7768
+ limit: { type: "number", minimum: 1, maximum: 250, description: "Max number of issues to return (default 50)" }
7771
7769
  },
7772
- required: ["to", "taskType", "payload"],
7773
7770
  additionalProperties: false
7774
7771
  },
7775
- constraints: { rate_bucket: "inbox.write" },
7776
- effects: ["Create:InboxItem"],
7777
- risk: "high",
7772
+ constraints: { rate_bucket: "linear.read" },
7773
+ effects: ["Read:IssueList"],
7774
+ risk: "low",
7778
7775
  target_bindings: {
7779
- resource_id: { source: "param", param: "to" }
7776
+ resource_id: { source: "param", param: "teamId", required: false }
7780
7777
  },
7781
7778
  version: "1.0.0"
7782
7779
  },
7783
7780
  {
7784
- action: "inbox.respond",
7785
- resource_type: "inbox:item",
7786
- required_relations: ["editor", "act_as"],
7787
- required_scopes: ["inbox"],
7788
- capability: "inbox.write",
7781
+ action: "linear.issue.read",
7782
+ resource_type: "linear:issue",
7783
+ required_relations: ["viewer", "editor", "admin", "owner"],
7784
+ required_scopes: ["read"],
7785
+ capability: "linear.read.basic",
7789
7786
  input_schema: {
7790
7787
  type: "object",
7791
7788
  properties: {
7792
- id: { type: "string", minLength: 1, description: "Inbox item id being responded to" },
7793
- action: { type: "string", enum: ["accept", "decline", "counter"], description: "Response action" },
7794
- data: { type: "object", description: "Optional response data (e.g. counter-proposal)" }
7789
+ issueId: { type: "string", minLength: 1, description: "Issue ID or identifier (e.g. ENG-123)" }
7795
7790
  },
7796
- required: ["id", "action"],
7791
+ required: ["issueId"],
7797
7792
  additionalProperties: false
7798
7793
  },
7799
- constraints: { rate_bucket: "inbox.write" },
7800
- effects: ["Update:InboxItem"],
7801
- // high (not medium): an agent-mediated response (MCP invoke) must always
7802
- // go through human approval — the Phase 1 "always confirm" guarantee made
7803
- // enforceable. target_bindings below binds the concrete inbox item id so
7804
- // the high-risk approval has a specific resource constraint (the public
7805
- // /scheduling/:token link flow does NOT go through this gate — it calls
7806
- // InboxService.respond directly, system-key-signed).
7807
- risk: "high",
7794
+ constraints: { rate_bucket: "linear.read" },
7795
+ effects: ["Read:Issue"],
7796
+ risk: "low",
7808
7797
  target_bindings: {
7809
- resource_id: { source: "param", param: "id" }
7798
+ resource_id: { source: "param", param: "issueId" }
7810
7799
  },
7811
7800
  version: "1.0.0"
7812
7801
  },
7813
7802
  {
7814
- action: "inbox.check",
7815
- resource_type: "inbox:item",
7803
+ action: "linear.issue.search",
7804
+ resource_type: "linear:issue",
7816
7805
  required_relations: ["viewer", "editor", "admin", "owner"],
7817
- required_scopes: ["inbox"],
7818
- capability: "inbox.read",
7806
+ required_scopes: ["read"],
7807
+ capability: "linear.read.basic",
7819
7808
  input_schema: {
7820
7809
  type: "object",
7821
7810
  properties: {
7822
- types: { type: "array", items: { type: "string" }, description: "Filter by task types" },
7823
- status: { type: "string", description: "Filter by item status" }
7811
+ query: { type: "string", minLength: 1, description: "Full-text search query" },
7812
+ teamId: { type: "string", description: "Restrict search to a specific team" },
7813
+ limit: { type: "number", minimum: 1, maximum: 250, description: "Max number of results (default 50)" }
7824
7814
  },
7815
+ required: ["query"],
7825
7816
  additionalProperties: false
7826
7817
  },
7827
- constraints: { rate_bucket: "inbox.read" },
7828
- effects: ["Read:InboxItem"],
7818
+ constraints: { rate_bucket: "linear.read" },
7819
+ effects: ["Read:IssueList"],
7829
7820
  risk: "low",
7830
7821
  target_bindings: {
7831
- resource_id: { source: "param", param: "id", required: false }
7822
+ resource_id: { source: "param", param: "teamId", required: false }
7832
7823
  },
7833
7824
  version: "1.0.0"
7834
7825
  },
7835
7826
  {
7836
- action: "inbox.checkByToken",
7837
- resource_type: "inbox:item",
7838
- required_relations: ["viewer", "editor", "admin", "owner"],
7839
- required_scopes: ["inbox"],
7840
- capability: "inbox.read",
7827
+ action: "linear.issue.create",
7828
+ resource_type: "linear:issue",
7829
+ required_relations: ["editor", "act_as"],
7830
+ required_scopes: ["issues:create"],
7831
+ capability: "linear.write.basic",
7841
7832
  input_schema: {
7842
7833
  type: "object",
7843
7834
  properties: {
7844
- token: { type: "string", minLength: 1, description: "Opaque access token for a single inbox item" }
7835
+ teamId: { type: "string", minLength: 1, description: "Team ID to create the issue in" },
7836
+ title: { type: "string", minLength: 1, description: "Issue title" },
7837
+ description: { type: "string", description: "Issue description (Markdown)" },
7838
+ assigneeId: { type: "string", description: "Assignee user ID" },
7839
+ stateId: { type: "string", description: "Workflow state ID" },
7840
+ priority: { type: "number", minimum: 0, maximum: 4, description: "0=No priority, 1=Urgent, 2=High, 3=Medium, 4=Low" },
7841
+ labelIds: { type: "array", items: { type: "string" }, description: "Label IDs to attach" }
7845
7842
  },
7846
- required: ["token"],
7843
+ required: ["teamId", "title"],
7847
7844
  additionalProperties: false
7848
7845
  },
7849
- constraints: { rate_bucket: "inbox.read" },
7850
- effects: ["Read:InboxItem"],
7851
- risk: "low",
7846
+ constraints: { rate_bucket: "linear.write" },
7847
+ effects: ["Create:Issue"],
7848
+ risk: "high",
7852
7849
  target_bindings: {
7853
- resource_id: { source: "param", param: "token" }
7850
+ resource_id: { source: "param", param: "teamId" }
7854
7851
  },
7855
7852
  version: "1.0.0"
7856
7853
  },
7857
7854
  {
7858
- action: "inbox.complete",
7859
- resource_type: "inbox:item",
7855
+ action: "linear.issue.update",
7856
+ resource_type: "linear:issue",
7860
7857
  required_relations: ["editor", "act_as"],
7861
- required_scopes: ["inbox"],
7862
- capability: "inbox.write",
7858
+ required_scopes: ["write"],
7859
+ capability: "linear.write.basic",
7863
7860
  input_schema: {
7864
7861
  type: "object",
7865
7862
  properties: {
7866
- id: { type: "string", minLength: 1, description: "Inbox item id being completed" },
7867
- result: { type: "object", description: "Result payload for the completed task" }
7863
+ issueId: { type: "string", minLength: 1, description: "Issue ID or identifier (e.g. ENG-123)" },
7864
+ title: { type: "string", description: "New title" },
7865
+ description: { type: "string", description: "New description (Markdown)" },
7866
+ assigneeId: { type: "string", description: "Assignee user ID (null to unassign)" },
7867
+ stateId: { type: "string", description: "Workflow state ID" },
7868
+ priority: { type: "number", minimum: 0, maximum: 4, description: "0=No priority, 1=Urgent, 2=High, 3=Medium, 4=Low" },
7869
+ labelIds: { type: "array", items: { type: "string" }, description: "New set of label IDs" }
7868
7870
  },
7869
- required: ["id", "result"],
7871
+ required: ["issueId"],
7870
7872
  additionalProperties: false
7871
7873
  },
7872
- constraints: { rate_bucket: "inbox.write" },
7873
- effects: ["Update:InboxItem"],
7874
- risk: "low",
7874
+ constraints: { rate_bucket: "linear.write" },
7875
+ effects: ["Update:Issue"],
7876
+ risk: "high",
7875
7877
  target_bindings: {
7876
- resource_id: { source: "param", param: "id" }
7878
+ resource_id: { source: "param", param: "issueId" }
7877
7879
  },
7878
7880
  version: "1.0.0"
7879
7881
  },
7880
- // ─── Scheduling Actions (internal) ───
7881
- // scheduling.request is a meeting-time negotiation façade over inbox.send.
7882
- // Candidate slots may be supplied two ways (server-side EXCLUSIVE — exactly
7883
- // one): (a) `candidates` — the agent computes them LLM-side from the user
7884
- // calendar and the server validates + freebusy-filters them, or (b)
7885
- // `candidateWindow` — the agent hands the server a { start, end } window and
7886
- // the server generates busy-free candidates from the sender's Google
7887
- // Calendar. Like the inbox actions it is internal (no external OAuth
7888
- // provider), so it carries the single nominal base scope `inbox`.
7889
- //
7890
- // NOTE: the candidates/candidateWindow exclusivity is expressed here as
7891
- // `oneOf` for documentation + the deep JSON-Schema authorities, but the SDK's
7892
- // hand-written `validateActionInput` is a SHALLOW shape gate that does NOT
7893
- // interpret `oneOf` (neither key is in top-level `required`). The exclusivity
7894
- // (exactly one of candidates/candidateWindow) is ENFORCED server-side in
7895
- // SchedulingRequestService — see that service for the 400s on both-given /
7896
- // both-missing.
7897
- // Spec: docs/specs/2026-06-10-inbox-intent-routing-design.md §2.1
7898
7882
  {
7899
- action: "scheduling.request",
7900
- resource_type: "inbox:item",
7883
+ action: "linear.comment.create",
7884
+ resource_type: "linear:comment",
7901
7885
  required_relations: ["editor", "act_as"],
7902
- required_scopes: ["inbox"],
7903
- capability: "inbox.write",
7886
+ required_scopes: ["comments:create"],
7887
+ capability: "linear.write.basic",
7904
7888
  input_schema: {
7905
7889
  type: "object",
7906
7890
  properties: {
7907
- to: { type: "string", minLength: 1, description: "Counterpart (user id / email) to negotiate a meeting time with" },
7908
- topic: { type: "string", minLength: 1, description: "Meeting topic shown to the counterpart" },
7909
- durationMinutes: { type: "integer", minimum: 5, maximum: 480, description: "Meeting length in minutes" },
7910
- candidates: {
7911
- type: "array",
7912
- minItems: 1,
7913
- maxItems: 10,
7914
- description: "Explicit candidate slots computed by the agent from the user calendar. The server validates them AND (when Google Calendar is connected) filters out any that conflict with the sender's calendar. Mutually exclusive with candidateWindow \u2014 supply exactly one.",
7915
- items: {
7916
- type: "object",
7917
- properties: {
7918
- start: { type: "string", description: "ISO 8601 start" },
7919
- end: { type: "string", description: "ISO 8601 end" }
7920
- },
7921
- required: ["start", "end"],
7922
- additionalProperties: false
7923
- }
7924
- },
7925
- candidateWindow: {
7926
- type: "object",
7927
- description: "A { start, end } search window (ISO 8601, span \u2264 62 days). The server generates busy-free candidate slots from the sender's Google Calendar within it. Mutually exclusive with candidates \u2014 supply exactly one. Requires a connected Google Calendar.",
7928
- properties: {
7929
- start: { type: "string", description: "ISO 8601 window start" },
7930
- end: { type: "string", description: "ISO 8601 window end" }
7931
- },
7932
- required: ["start", "end"],
7933
- additionalProperties: false
7934
- },
7935
- hold: {
7936
- type: "boolean",
7937
- description: "When true (or omitted, when the sender's delegation policy has holds enabled), tentatively hold the offered slots on the sender's calendar as [\u4EEE] events until the counterpart responds or the request expires. Pass false to skip holds for this request. Only takes effect when the sender has an enabled scheduling delegation policy."
7938
- },
7939
- message: { type: "string", description: "Optional human-readable message" }
7891
+ issueId: { type: "string", minLength: 1, description: "Issue ID to comment on" },
7892
+ body: { type: "string", minLength: 1, description: "Comment body (Markdown)" }
7940
7893
  },
7941
- // candidates / candidateWindow are intentionally NOT in `required`: the
7942
- // exclusive-choice is documented via `oneOf` and enforced server-side.
7943
- // Each oneOf branch re-declares its property locally (empty `properties`
7944
- // entry) so AJV strict mode (`strictRequired`) sees the required key as
7945
- // defined within the branch scope — the value shape itself is validated
7946
- // by the top-level `properties` above.
7947
- required: ["to", "topic", "durationMinutes"],
7948
- oneOf: [
7949
- { required: ["candidates"], properties: { candidates: {} } },
7950
- { required: ["candidateWindow"], properties: { candidateWindow: {} } }
7951
- ],
7894
+ required: ["issueId", "body"],
7952
7895
  additionalProperties: false
7953
7896
  },
7954
- constraints: { rate_bucket: "inbox.write" },
7955
- effects: ["Create:InboxItem"],
7897
+ constraints: { rate_bucket: "linear.write" },
7898
+ effects: ["Create:Comment"],
7956
7899
  risk: "high",
7957
7900
  target_bindings: {
7958
- resource_id: { source: "param", param: "to" }
7901
+ resource_id: { source: "param", param: "issueId" }
7959
7902
  },
7960
7903
  version: "1.0.0"
7961
- }
7962
- ],
7963
- capabilities: [
7964
- {
7965
- capability: "slack.messaging.basic",
7966
- description: "Post, update, and delete messages in channels",
7967
- includes: ["slack.message.post", "slack.message.update", "slack.message.delete"],
7968
- version: "1.0.0"
7969
- },
7970
- {
7971
- capability: "slack.read.basic",
7972
- description: "Read channels, messages, and user info",
7973
- includes: ["slack.channel.read", "slack.user.read", "slack.message.read", "slack.message.read_paginated", "slack.batch.read"],
7974
- version: "1.0.0"
7975
7904
  },
7976
7905
  {
7977
- capability: "github.read.basic",
7978
- description: "Read issues, pull requests and repository contents from repositories",
7979
- includes: ["github.issue.list", "github.issue.read", "github.pr.list", "github.pr.read", "github.pr.files.list", "github.pr.review.list", "github.pr.search", "github.repo.search", "github.repo.collaborator.list", "github.content.get", "github.tree.get", "github.branch.list", "github.commit.get", "github.commit.list", "github.commit.search", "github.tag.list", "github.release.list", "github.release.getLatest", "github.release.getByTag", "github.code.search", "github.issue.search", "github.issue.types.list", "github.label.get", "github.label.list", "github.workflow.get", "github.workflow.list", "github.workflow.jobLogs.get", "github.repo.starred.list", "github.user.me.get", "github.org.teams.list", "github.team.members.list", "github.user.search", "github.notification.list", "github.notification.get", "github.gist.get", "github.gist.list"],
7906
+ action: "linear.comment.list",
7907
+ resource_type: "linear:comment",
7908
+ required_relations: ["viewer", "editor", "admin", "owner"],
7909
+ required_scopes: ["read"],
7910
+ capability: "linear.read.basic",
7911
+ input_schema: {
7912
+ type: "object",
7913
+ properties: {
7914
+ issueId: { type: "string", minLength: 1, description: "Issue ID to list comments for" },
7915
+ limit: { type: "number", minimum: 1, maximum: 250, description: "Max number of comments (default 50)" }
7916
+ },
7917
+ required: ["issueId"],
7918
+ additionalProperties: false
7919
+ },
7920
+ constraints: { rate_bucket: "linear.read" },
7921
+ effects: ["Read:CommentList"],
7922
+ risk: "low",
7923
+ target_bindings: {
7924
+ resource_id: { source: "param", param: "issueId" }
7925
+ },
7980
7926
  version: "1.0.0"
7981
7927
  },
7982
7928
  {
7983
- capability: "github.issues.triage",
7984
- description: "Create and update issues, post issue comments, manage sub-issues and labels",
7985
- includes: ["github.issue.create", "github.issue.update", "github.issue.comment.create", "github.issue.subissue.write", "github.label.write"],
7929
+ action: "linear.project.list",
7930
+ resource_type: "linear:project",
7931
+ required_relations: ["viewer", "editor", "admin", "owner"],
7932
+ required_scopes: ["read"],
7933
+ capability: "linear.read.basic",
7934
+ input_schema: {
7935
+ type: "object",
7936
+ properties: {
7937
+ teamId: { type: "string", description: "Filter by team ID" },
7938
+ limit: { type: "number", minimum: 1, maximum: 250, description: "Max number of projects (default 50)" }
7939
+ },
7940
+ additionalProperties: false
7941
+ },
7942
+ constraints: { rate_bucket: "linear.read" },
7943
+ effects: ["Read:ProjectList"],
7944
+ risk: "low",
7945
+ target_bindings: {
7946
+ resource_id: { source: "param", param: "teamId", required: false }
7947
+ },
7986
7948
  version: "1.0.0"
7987
7949
  },
7988
7950
  {
7989
- capability: "github.pulls.write",
7990
- description: "Create, update, merge, and review pull requests",
7991
- includes: ["github.pr.create", "github.pr.update", "github.pr.merge", "github.pr.review.create", "github.pr.comment.reply", "github.pr.branch.update"],
7951
+ action: "linear.project.read",
7952
+ resource_type: "linear:project",
7953
+ required_relations: ["viewer", "editor", "admin", "owner"],
7954
+ required_scopes: ["read"],
7955
+ capability: "linear.read.basic",
7956
+ input_schema: {
7957
+ type: "object",
7958
+ properties: {
7959
+ projectId: { type: "string", minLength: 1, description: "Project ID" }
7960
+ },
7961
+ required: ["projectId"],
7962
+ additionalProperties: false
7963
+ },
7964
+ constraints: { rate_bucket: "linear.read" },
7965
+ effects: ["Read:Project"],
7966
+ risk: "low",
7967
+ target_bindings: {
7968
+ resource_id: { source: "param", param: "projectId" }
7969
+ },
7992
7970
  version: "1.0.0"
7993
7971
  },
7994
7972
  {
7995
- capability: "github.repos.write",
7996
- description: "\u30EA\u30DD\u30B8\u30C8\u30EA\u306E\u4F5C\u6210\u30FB\u30D5\u30A9\u30FC\u30AF\u30FB\u30D5\u30A1\u30A4\u30EB\u66F4\u65B0\u30FB\u30D6\u30E9\u30F3\u30C1\u4F5C\u6210\u30FB\u30EF\u30FC\u30AF\u30D5\u30ED\u30FC\u5B9F\u884C\u30FB\u30B9\u30BF\u30FC\u64CD\u4F5C",
7997
- includes: ["github.repo.create", "github.repo.fork", "github.content.createOrUpdate", "github.content.delete", "github.branch.create", "github.workflow.run", "github.repo.star", "github.repo.unstar"],
7973
+ action: "linear.team.list",
7974
+ resource_type: "linear:team",
7975
+ required_relations: ["viewer", "editor", "admin", "owner"],
7976
+ required_scopes: ["read"],
7977
+ capability: "linear.read.basic",
7978
+ input_schema: {
7979
+ type: "object",
7980
+ properties: {
7981
+ limit: { type: "number", minimum: 1, maximum: 250, description: "Max number of teams (default 50)" }
7982
+ },
7983
+ additionalProperties: false
7984
+ },
7985
+ constraints: { rate_bucket: "linear.read" },
7986
+ effects: ["Read:TeamList"],
7987
+ risk: "low",
7988
+ // No teamId parameter: this action lists ALL accessible teams — intentionally
7989
+ // not scoped to a single team. required:false signals that missing resource
7990
+ // binding is expected (not an omission), consistent with slack.channel.read.
7991
+ target_bindings: {
7992
+ resource_id: { source: "param", param: "teamId", required: false }
7993
+ },
7998
7994
  version: "1.0.0"
7999
7995
  },
8000
7996
  {
8001
- capability: "github.notifications.write",
8002
- description: "\u901A\u77E5\u306E\u65E2\u8AAD\u5316\u30FB\u30B9\u30EC\u30C3\u30C9/\u30EA\u30DD\u30B8\u30C8\u30EA\u306E\u8CFC\u8AAD\u8A2D\u5B9A",
8003
- includes: ["github.notification.markRead", "github.notification.markAllRead", "github.notification.subscription.set", "github.notification.repoSubscription.set"],
7997
+ action: "linear.workflowState.list",
7998
+ resource_type: "linear:workflowState",
7999
+ required_relations: ["viewer", "editor", "admin", "owner"],
8000
+ required_scopes: ["read"],
8001
+ capability: "linear.read.basic",
8002
+ input_schema: {
8003
+ type: "object",
8004
+ properties: {
8005
+ teamId: { type: "string", description: "Filter by team ID" },
8006
+ limit: { type: "number", minimum: 1, maximum: 250, description: "Max number of workflow states to return (default 50)" }
8007
+ },
8008
+ additionalProperties: false
8009
+ },
8010
+ constraints: { rate_bucket: "linear.read" },
8011
+ effects: ["Read:WorkflowStateList"],
8012
+ risk: "low",
8013
+ target_bindings: {
8014
+ resource_id: { source: "param", param: "teamId", required: false }
8015
+ },
8004
8016
  version: "1.0.0"
8005
8017
  },
8006
8018
  {
8007
- capability: "github.gists.write",
8008
- description: "Gist \u306E\u4F5C\u6210\u30FB\u66F4\u65B0",
8009
- includes: ["github.gist.create", "github.gist.update"],
8019
+ action: "linear.viewer.read",
8020
+ resource_type: "linear:viewer",
8021
+ required_relations: ["viewer", "editor", "admin", "owner"],
8022
+ required_scopes: ["read"],
8023
+ capability: "linear.read.basic",
8024
+ input_schema: {
8025
+ type: "object",
8026
+ properties: {},
8027
+ additionalProperties: false
8028
+ },
8029
+ constraints: { rate_bucket: "linear.read" },
8030
+ effects: ["Read:Viewer"],
8031
+ risk: "low",
8032
+ // No parameters: this action reads the currently authenticated user — there is
8033
+ // no resource to scope to. required:false signals intentional exemption, not
8034
+ // omission, consistent with the slack.channel.read precedent.
8035
+ target_bindings: {
8036
+ resource_id: { source: "param", param: "viewerId", required: false }
8037
+ },
8010
8038
  version: "1.0.0"
8011
8039
  },
8012
8040
  {
8013
- capability: "gmail.read.basic",
8014
- description: "Read and search Gmail messages and labels",
8015
- includes: ["gmail.message.search", "gmail.message.read", "gmail.label.read", "gmail.batch.read"],
8041
+ action: "linear.label.list",
8042
+ resource_type: "linear:label",
8043
+ required_relations: ["viewer", "editor", "admin", "owner"],
8044
+ required_scopes: ["read"],
8045
+ capability: "linear.read.basic",
8046
+ input_schema: {
8047
+ type: "object",
8048
+ properties: {
8049
+ teamId: { type: "string", description: "Filter labels by team ID" },
8050
+ limit: { type: "number", minimum: 1, maximum: 250, description: "Max number of labels to return (default 50)" }
8051
+ },
8052
+ additionalProperties: false
8053
+ },
8054
+ constraints: { rate_bucket: "linear.read" },
8055
+ effects: ["Read:LabelList"],
8056
+ risk: "low",
8057
+ target_bindings: {
8058
+ resource_id: { source: "param", param: "teamId", required: false }
8059
+ },
8016
8060
  version: "1.0.0"
8017
8061
  },
8018
8062
  {
8019
- capability: "gmail.compose",
8020
- description: "Send emails and create drafts via Gmail",
8021
- includes: ["gmail.message.send", "gmail.draft.create"],
8063
+ action: "linear.user.list",
8064
+ resource_type: "linear:team",
8065
+ required_relations: ["viewer", "editor", "admin", "owner"],
8066
+ required_scopes: ["read"],
8067
+ capability: "linear.read.basic",
8068
+ input_schema: {
8069
+ type: "object",
8070
+ properties: {
8071
+ teamId: { type: "string", description: "Filter by team ID (lists team members only)" },
8072
+ limit: { type: "number", minimum: 1, maximum: 250, description: "Max number of users to return (default 50)" }
8073
+ },
8074
+ additionalProperties: false
8075
+ },
8076
+ constraints: { rate_bucket: "linear.read" },
8077
+ effects: ["Read:UserList"],
8078
+ risk: "low",
8079
+ target_bindings: {
8080
+ resource_id: { source: "param", param: "teamId", required: false }
8081
+ },
8022
8082
  version: "1.0.0"
8023
8083
  },
8024
8084
  {
8025
- capability: "gmail.manage",
8026
- description: "Trash and permanently delete Gmail messages",
8027
- includes: ["gmail.message.trash", "gmail.message.delete"],
8085
+ action: "linear.issue.archive",
8086
+ resource_type: "linear:issue",
8087
+ required_relations: ["editor", "act_as"],
8088
+ required_scopes: ["write"],
8089
+ capability: "linear.write.basic",
8090
+ input_schema: {
8091
+ type: "object",
8092
+ properties: {
8093
+ issueId: { type: "string", minLength: 1, description: "Issue ID or identifier to archive (e.g. ENG-123)" }
8094
+ },
8095
+ required: ["issueId"],
8096
+ additionalProperties: false
8097
+ },
8098
+ constraints: { rate_bucket: "linear.write" },
8099
+ effects: ["Archive:Issue"],
8100
+ risk: "high",
8101
+ target_bindings: {
8102
+ resource_id: { source: "param", param: "issueId" }
8103
+ },
8028
8104
  version: "1.0.0"
8029
8105
  },
8030
8106
  {
8031
- capability: "calendar.read.basic",
8032
- description: "Read and list Google Calendar events, and check free/busy availability",
8033
- includes: ["calendar.event.list", "calendar.event.read", "calendar.freebusy"],
8107
+ action: "linear.project.create",
8108
+ resource_type: "linear:project",
8109
+ required_relations: ["editor", "act_as"],
8110
+ required_scopes: ["write"],
8111
+ capability: "linear.write.basic",
8112
+ input_schema: {
8113
+ type: "object",
8114
+ properties: {
8115
+ name: { type: "string", minLength: 1, description: "Project name" },
8116
+ teamIds: { type: "array", items: { type: "string" }, minItems: 1, description: "Team IDs to associate with the project (at least one required)" },
8117
+ teamId: { type: "string", description: "Primary team ID (first element of teamIds; used for authorization scope)" },
8118
+ description: { type: "string", description: "Project description (Markdown)" },
8119
+ statusId: { type: "string", description: "Project status ID. Note: this is a ProjectStatus ID, not a WorkflowState ID. ProjectStatus can be retrieved via the Linear API projectStatuses query." },
8120
+ startDate: { type: "string", description: "Start date (ISO 8601, e.g. 2024-01-01)" },
8121
+ targetDate: { type: "string", description: "Target completion date (ISO 8601)" }
8122
+ },
8123
+ required: ["name", "teamIds"],
8124
+ additionalProperties: false
8125
+ },
8126
+ constraints: { rate_bucket: "linear.write" },
8127
+ effects: ["Create:Project"],
8128
+ risk: "high",
8129
+ target_bindings: {
8130
+ // teamId はスキーマの scalar フィールド (teamIds[0] の alias)。
8131
+ // teamId が明示指定されている場合はそれを使い、未指定の場合は
8132
+ // fallback_param: 'teamIds' で teamIds[0] にフォールバック(resolver は
8133
+ // 配列の first element を自動的にスカラーに変換する)。
8134
+ // extractResources も同じ優先順位 (teamId → teamIds[0]) で解決するため
8135
+ // 両者のバインドが常に一致する。required:true で高リスク CREATE の
8136
+ // resource binding 必須契約を明示 (teamIds は minItems:1 なので常に解決する)。
8137
+ resource_id: { source: "param", param: "teamId", fallback_param: "teamIds", required: true }
8138
+ },
8034
8139
  version: "1.0.0"
8035
8140
  },
8036
8141
  {
8037
- capability: "calendar.write",
8038
- description: "Create, update, and delete Google Calendar events",
8039
- includes: ["calendar.event.create", "calendar.event.update", "calendar.event.delete"],
8142
+ action: "linear.project.update",
8143
+ resource_type: "linear:project",
8144
+ required_relations: ["editor", "act_as"],
8145
+ required_scopes: ["write"],
8146
+ capability: "linear.write.basic",
8147
+ input_schema: {
8148
+ type: "object",
8149
+ properties: {
8150
+ projectId: { type: "string", minLength: 1, description: "Project ID to update" },
8151
+ name: { type: "string", description: "New project name" },
8152
+ description: { type: "string", description: "New project description (Markdown)" },
8153
+ statusId: { type: "string", description: "New project status ID. Note: this is a ProjectStatus ID, not a WorkflowState ID." },
8154
+ startDate: { type: "string", description: "New start date (ISO 8601)" },
8155
+ targetDate: { type: "string", description: "New target date (ISO 8601)" }
8156
+ },
8157
+ required: ["projectId"],
8158
+ additionalProperties: false
8159
+ },
8160
+ constraints: { rate_bucket: "linear.write" },
8161
+ effects: ["Update:Project"],
8162
+ risk: "high",
8163
+ target_bindings: {
8164
+ resource_id: { source: "param", param: "projectId" }
8165
+ },
8040
8166
  version: "1.0.0"
8041
8167
  },
8168
+ // ─── Linear Comment ops ───
8042
8169
  {
8043
- capability: "jira.read.basic",
8044
- description: "Read Jira issues, projects, boards, sprints, issue link types, and users",
8045
- includes: ["jira.project.read", "jira.board.read", "jira.sprint.read", "jira.issue.list", "jira.issue.search", "jira.worklog.read", "jira.issue.read", "jira.batch.read", "jira.comment.read", "jira.transition.list", "jira.issuelinktype.list", "jira.user.search"],
8170
+ action: "linear.comment.update",
8171
+ resource_type: "linear:comment",
8172
+ required_relations: ["editor", "act_as"],
8173
+ required_scopes: ["comments:create"],
8174
+ capability: "linear.write.basic",
8175
+ input_schema: {
8176
+ type: "object",
8177
+ properties: {
8178
+ commentId: { type: "string", minLength: 1, description: "Comment ID to update" },
8179
+ body: { type: "string", minLength: 1, description: "New comment body (Markdown)" }
8180
+ },
8181
+ required: ["commentId", "body"],
8182
+ additionalProperties: false
8183
+ },
8184
+ constraints: { rate_bucket: "linear.write" },
8185
+ effects: ["Update:Comment"],
8186
+ risk: "high",
8187
+ target_bindings: {
8188
+ resource_id: { source: "param", param: "commentId" }
8189
+ },
8046
8190
  version: "1.0.0"
8047
8191
  },
8048
8192
  {
8049
- capability: "jira.write.basic",
8050
- description: "Create, update, delete Jira issues, manage issue links, and add/delete comments",
8051
- includes: ["jira.issue.create", "jira.issue.update", "jira.issue.delete", "jira.comment.create", "jira.comment.delete", "jira.issue.transition", "jira.issuelink.create", "jira.issuelink.delete"],
8193
+ action: "linear.comment.delete",
8194
+ resource_type: "linear:comment",
8195
+ required_relations: ["editor", "act_as"],
8196
+ required_scopes: ["write"],
8197
+ capability: "linear.write.basic",
8198
+ input_schema: {
8199
+ type: "object",
8200
+ properties: {
8201
+ commentId: { type: "string", minLength: 1, description: "Comment ID to delete" }
8202
+ },
8203
+ required: ["commentId"],
8204
+ additionalProperties: false
8205
+ },
8206
+ constraints: { rate_bucket: "linear.write" },
8207
+ effects: ["Delete:Comment"],
8208
+ risk: "high",
8209
+ target_bindings: {
8210
+ resource_id: { source: "param", param: "commentId" }
8211
+ },
8052
8212
  version: "1.0.0"
8053
8213
  },
8054
8214
  {
8055
- capability: "inbox.write",
8056
- description: "Send and respond to agent inbox tasks",
8057
- includes: ["inbox.send", "inbox.respond", "inbox.complete", "scheduling.request"],
8215
+ action: "linear.comment.resolve",
8216
+ resource_type: "linear:comment",
8217
+ required_relations: ["editor", "act_as"],
8218
+ required_scopes: ["write"],
8219
+ capability: "linear.write.basic",
8220
+ input_schema: {
8221
+ type: "object",
8222
+ properties: {
8223
+ commentId: { type: "string", minLength: 1, description: "Comment ID to resolve" }
8224
+ },
8225
+ required: ["commentId"],
8226
+ additionalProperties: false
8227
+ },
8228
+ constraints: { rate_bucket: "linear.write" },
8229
+ effects: ["Update:Comment"],
8230
+ risk: "high",
8231
+ target_bindings: {
8232
+ resource_id: { source: "param", param: "commentId" }
8233
+ },
8058
8234
  version: "1.0.0"
8059
8235
  },
8060
8236
  {
8061
- capability: "inbox.read",
8062
- description: "Read agent inbox tasks",
8063
- includes: ["inbox.check", "inbox.checkByToken"],
8237
+ action: "linear.comment.unresolve",
8238
+ resource_type: "linear:comment",
8239
+ required_relations: ["editor", "act_as"],
8240
+ required_scopes: ["write"],
8241
+ capability: "linear.write.basic",
8242
+ input_schema: {
8243
+ type: "object",
8244
+ properties: {
8245
+ commentId: { type: "string", minLength: 1, description: "Comment ID to unresolve" }
8246
+ },
8247
+ required: ["commentId"],
8248
+ additionalProperties: false
8249
+ },
8250
+ constraints: { rate_bucket: "linear.write" },
8251
+ effects: ["Update:Comment"],
8252
+ risk: "high",
8253
+ target_bindings: {
8254
+ resource_id: { source: "param", param: "commentId" }
8255
+ },
8064
8256
  version: "1.0.0"
8065
- }
8066
- ]
8067
- };
8068
-
8069
- // src/registry/resource-type-labels.ts
8070
- var RESOURCE_TYPE_LABELS = {
8071
- "github:repo": "\u5BFE\u8C61\u30EA\u30DD\u30B8\u30C8\u30EA",
8072
- "github:org": "\u5BFE\u8C61\u7D44\u7E54"
8073
- };
8074
-
8075
- // src/registry/action-input-validator.ts
8076
- var SCHEMA_INDEX = (() => {
8077
- const map = /* @__PURE__ */ new Map();
8078
- for (const a of ACTION_REGISTRY.actions) {
8079
- if (a && typeof a.action === "string" && a.input_schema) {
8080
- map.set(a.action, a.input_schema);
8081
- }
8082
- }
8083
- return map;
8084
- })();
8085
- function describeExpectedShape(schema) {
8086
- const props = schema.properties ?? {};
8087
- const required = Array.isArray(schema.required) ? schema.required : [];
8088
- const requiredSet = new Set(required);
8089
- const parts = [];
8090
- const orderedKeys = [
8091
- ...required.filter((k) => k in props),
8092
- ...Object.keys(props).filter((k) => !requiredSet.has(k))
8093
- ];
8094
- for (const key of orderedKeys) {
8095
- const prop = props[key] || {};
8096
- const optionalMark = requiredSet.has(key) ? "" : "?";
8097
- const enumVals = Array.isArray(prop.enum) ? prop.enum : void 0;
8098
- if (enumVals && enumVals.length > 0) {
8099
- const rendered = enumVals.map((v) => typeof v === "string" ? `'${v}'` : String(v)).join(" | ");
8100
- parts.push(`${key}${optionalMark}: ${rendered}`);
8101
- } else {
8102
- parts.push(`${key}${optionalMark}`);
8103
- }
8104
- }
8105
- return `{ ${parts.join(", ")} }`;
8106
- }
8107
- function matchesType(value, type) {
8108
- if (!type) return true;
8109
- switch (type) {
8110
- case "string":
8111
- return typeof value === "string";
8112
- case "integer":
8113
- return typeof value === "number" && Number.isInteger(value);
8114
- case "number":
8115
- return typeof value === "number";
8116
- case "boolean":
8117
- return typeof value === "boolean";
8118
- case "array":
8119
- return Array.isArray(value);
8120
- case "object":
8121
- return typeof value === "object" && value !== null && !Array.isArray(value);
8122
- default:
8123
- return true;
8124
- }
8125
- }
8126
- function validateActionInput(action, params) {
8127
- const schema = SCHEMA_INDEX.get(action);
8128
- if (!schema) {
8129
- return { valid: true };
8130
- }
8131
- const props = schema.properties ?? {};
8132
- const required = Array.isArray(schema.required) ? schema.required : [];
8133
- const additionalProps = schema.additionalProperties;
8134
- const safeParams = params && typeof params === "object" && !Array.isArray(params) ? params : {};
8135
- const missing = [];
8136
- const unknown = [];
8137
- const enumErrors = [];
8138
- const typeErrors = [];
8139
- for (const key of required) {
8140
- if (!(key in safeParams) || safeParams[key] === void 0 || safeParams[key] === null) {
8141
- missing.push(key);
8142
- }
8143
- }
8144
- if (additionalProps === false) {
8145
- for (const key of Object.keys(safeParams)) {
8146
- if (!(key in props)) {
8147
- unknown.push(key);
8148
- }
8149
- }
8150
- }
8151
- for (const key of Object.keys(props)) {
8152
- if (!(key in safeParams)) continue;
8153
- const value = safeParams[key];
8154
- if (value === void 0 || value === null) continue;
8155
- const prop = props[key] || {};
8156
- const enumVals = Array.isArray(prop.enum) ? prop.enum : void 0;
8157
- if (enumVals && enumVals.length > 0) {
8158
- if (!enumVals.includes(value)) {
8159
- enumErrors.push(key);
8160
- continue;
8161
- }
8162
- }
8163
- if (!matchesType(value, prop.type)) {
8164
- typeErrors.push(key);
8165
- }
8166
- }
8167
- if (missing.length === 0 && unknown.length === 0 && enumErrors.length === 0 && typeErrors.length === 0) {
8168
- return { valid: true };
8169
- }
8170
- const segments = [];
8171
- if (missing.length > 0) {
8172
- segments.push(`missing required parameter(s) [${missing.join(", ")}]`);
8173
- }
8174
- if (unknown.length > 0) {
8175
- segments.push(`unknown parameter(s) [${unknown.join(", ")}]`);
8176
- }
8177
- if (enumErrors.length > 0) {
8178
- const details = enumErrors.map((key) => {
8179
- const enumVals = props[key]?.enum || [];
8180
- const rendered = enumVals.map((v) => typeof v === "string" ? `'${v}'` : String(v)).join(" | ");
8181
- return `${key} (allowed: ${rendered})`;
8182
- }).join(", ");
8183
- segments.push(`invalid value for enum parameter(s) [${details}]`);
8184
- }
8185
- if (typeErrors.length > 0) {
8186
- const details = typeErrors.map((key) => `${key} (expected ${props[key]?.type})`).join(", ");
8187
- segments.push(`wrong type for parameter(s) [${details}]`);
8188
- }
8189
- const message = `${action}: ${segments.join("; ")}. Expected shape: ${describeExpectedShape(schema)}`;
8190
- return { valid: false, errors: [message] };
8191
- }
8192
-
8193
- // src/registry/resource-types.ts
8194
- var RESOURCE_TYPES = {
8195
- // Slack
8196
- SLACK_CHANNEL: "slack:channel",
8197
- SLACK_USER: "slack:user",
8198
- SLACK_WORKSPACE: "slack:workspace",
8199
- // GitHub
8200
- GITHUB_REPO: "github:repo",
8201
- GITHUB_ORG: "github:org",
8202
- GITHUB_ISSUE: "github:issue",
8203
- // Google Drive
8204
- GOOGLE_DRIVE_FILE: "google:drive:file",
8205
- GOOGLE_DRIVE_FOLDER: "google:drive:folder",
8206
- // Gmail
8207
- GMAIL_THREAD: "gmail:thread",
8208
- GMAIL_LABEL: "gmail:label",
8209
- // Jira
8210
- JIRA_PROJECT: "jira:project",
8211
- JIRA_BOARD: "jira:board",
8212
- JIRA_ISSUE: "jira:issue",
8213
- JIRA_SPRINT: "jira:sprint",
8214
- // HubSpot
8215
- HUBSPOT_OBJECT: "hubspot:object",
8216
- HUBSPOT_PROPERTY: "hubspot:property",
8217
- HUBSPOT_SCHEMA: "hubspot:schema",
8257
+ },
8258
+ // ─── Linear Issue ops ───
8259
+ {
8260
+ action: "linear.issue.unarchive",
8261
+ resource_type: "linear:issue",
8262
+ required_relations: ["editor", "act_as"],
8263
+ required_scopes: ["write"],
8264
+ capability: "linear.write.basic",
8265
+ input_schema: {
8266
+ type: "object",
8267
+ properties: {
8268
+ issueId: { type: "string", minLength: 1, description: "Issue ID or identifier to unarchive (e.g. ENG-123)" }
8269
+ },
8270
+ required: ["issueId"],
8271
+ additionalProperties: false
8272
+ },
8273
+ constraints: { rate_bucket: "linear.write" },
8274
+ effects: ["Update:Issue"],
8275
+ risk: "high",
8276
+ target_bindings: {
8277
+ resource_id: { source: "param", param: "issueId" }
8278
+ },
8279
+ version: "1.0.0"
8280
+ },
8281
+ {
8282
+ action: "linear.issue.addLabel",
8283
+ resource_type: "linear:issue",
8284
+ required_relations: ["editor", "act_as"],
8285
+ required_scopes: ["write"],
8286
+ capability: "linear.write.basic",
8287
+ input_schema: {
8288
+ type: "object",
8289
+ properties: {
8290
+ issueId: { type: "string", minLength: 1, description: "Issue ID or identifier" },
8291
+ labelId: { type: "string", minLength: 1, description: "Label ID to add" }
8292
+ },
8293
+ required: ["issueId", "labelId"],
8294
+ additionalProperties: false
8295
+ },
8296
+ constraints: { rate_bucket: "linear.write" },
8297
+ effects: ["Update:Issue"],
8298
+ risk: "high",
8299
+ target_bindings: {
8300
+ resource_id: { source: "param", param: "issueId" }
8301
+ },
8302
+ version: "1.0.0"
8303
+ },
8304
+ {
8305
+ action: "linear.issue.removeLabel",
8306
+ resource_type: "linear:issue",
8307
+ required_relations: ["editor", "act_as"],
8308
+ required_scopes: ["write"],
8309
+ capability: "linear.write.basic",
8310
+ input_schema: {
8311
+ type: "object",
8312
+ properties: {
8313
+ issueId: { type: "string", minLength: 1, description: "Issue ID or identifier" },
8314
+ labelId: { type: "string", minLength: 1, description: "Label ID to remove" }
8315
+ },
8316
+ required: ["issueId", "labelId"],
8317
+ additionalProperties: false
8318
+ },
8319
+ constraints: { rate_bucket: "linear.write" },
8320
+ effects: ["Update:Issue"],
8321
+ risk: "high",
8322
+ target_bindings: {
8323
+ resource_id: { source: "param", param: "issueId" }
8324
+ },
8325
+ version: "1.0.0"
8326
+ },
8327
+ {
8328
+ action: "linear.issue.subscribe",
8329
+ resource_type: "linear:issue",
8330
+ required_relations: ["editor", "act_as"],
8331
+ required_scopes: ["write"],
8332
+ capability: "linear.write.basic",
8333
+ input_schema: {
8334
+ type: "object",
8335
+ properties: {
8336
+ issueId: { type: "string", minLength: 1, description: "Issue ID or identifier to subscribe to" }
8337
+ },
8338
+ required: ["issueId"],
8339
+ additionalProperties: false
8340
+ },
8341
+ constraints: { rate_bucket: "linear.write" },
8342
+ effects: ["Update:Issue"],
8343
+ risk: "high",
8344
+ target_bindings: {
8345
+ resource_id: { source: "param", param: "issueId" }
8346
+ },
8347
+ version: "1.0.0"
8348
+ },
8349
+ {
8350
+ action: "linear.issue.delete",
8351
+ resource_type: "linear:issue",
8352
+ required_relations: ["admin", "owner", "act_as"],
8353
+ required_scopes: ["write"],
8354
+ capability: "linear.write.basic",
8355
+ input_schema: {
8356
+ type: "object",
8357
+ properties: {
8358
+ issueId: { type: "string", minLength: 1, description: "Issue ID or identifier to permanently delete" }
8359
+ },
8360
+ required: ["issueId"],
8361
+ additionalProperties: false
8362
+ },
8363
+ constraints: { rate_bucket: "linear.write" },
8364
+ effects: ["Delete:Issue"],
8365
+ risk: "critical",
8366
+ target_bindings: {
8367
+ resource_id: { source: "param", param: "issueId" }
8368
+ },
8369
+ version: "1.0.0"
8370
+ },
8371
+ // ─── Linear Issue Relations ───
8372
+ {
8373
+ action: "linear.issueRelation.create",
8374
+ resource_type: "linear:issueRelation",
8375
+ required_relations: ["editor", "act_as"],
8376
+ required_scopes: ["write"],
8377
+ capability: "linear.write.basic",
8378
+ input_schema: {
8379
+ type: "object",
8380
+ properties: {
8381
+ issueId: { type: "string", minLength: 1, description: "Issue ID to create a relation from" },
8382
+ relatedIssueId: { type: "string", minLength: 1, description: "Related issue ID" },
8383
+ type: { type: "string", enum: ["blocks", "duplicate", "related", "similar"], description: "Relation type" }
8384
+ },
8385
+ required: ["issueId", "relatedIssueId", "type"],
8386
+ additionalProperties: false
8387
+ },
8388
+ constraints: { rate_bucket: "linear.write" },
8389
+ effects: ["Create:IssueRelation"],
8390
+ risk: "high",
8391
+ target_bindings: {
8392
+ resource_id: { source: "param", param: "issueId" }
8393
+ },
8394
+ version: "1.0.0"
8395
+ },
8396
+ {
8397
+ action: "linear.issueRelation.list",
8398
+ resource_type: "linear:issueRelation",
8399
+ required_relations: ["viewer", "editor", "admin", "owner"],
8400
+ required_scopes: ["read"],
8401
+ capability: "linear.read.basic",
8402
+ input_schema: {
8403
+ type: "object",
8404
+ properties: {
8405
+ issueId: { type: "string", minLength: 1, description: "Issue ID to list relations for" }
8406
+ },
8407
+ required: ["issueId"],
8408
+ additionalProperties: false
8409
+ },
8410
+ constraints: { rate_bucket: "linear.read" },
8411
+ effects: ["Read:IssueRelationList"],
8412
+ risk: "low",
8413
+ target_bindings: {
8414
+ resource_id: { source: "param", param: "issueId" }
8415
+ },
8416
+ version: "1.0.0"
8417
+ },
8418
+ {
8419
+ action: "linear.issueRelation.delete",
8420
+ resource_type: "linear:issueRelation",
8421
+ required_relations: ["editor", "act_as"],
8422
+ required_scopes: ["write"],
8423
+ capability: "linear.write.basic",
8424
+ input_schema: {
8425
+ type: "object",
8426
+ properties: {
8427
+ relationId: { type: "string", minLength: 1, description: "Issue relation ID to delete" }
8428
+ },
8429
+ required: ["relationId"],
8430
+ additionalProperties: false
8431
+ },
8432
+ constraints: { rate_bucket: "linear.write" },
8433
+ effects: ["Delete:IssueRelation"],
8434
+ risk: "high",
8435
+ target_bindings: {
8436
+ resource_id: { source: "param", param: "relationId" }
8437
+ },
8438
+ version: "1.0.0"
8439
+ },
8440
+ // ─── Linear Cycles ───
8441
+ {
8442
+ action: "linear.cycle.list",
8443
+ resource_type: "linear:cycle",
8444
+ required_relations: ["viewer", "editor", "admin", "owner"],
8445
+ required_scopes: ["read"],
8446
+ capability: "linear.read.basic",
8447
+ input_schema: {
8448
+ type: "object",
8449
+ properties: {
8450
+ teamId: { type: "string", description: "Filter by team ID" },
8451
+ limit: { type: "number", minimum: 1, maximum: 250, description: "Max number of cycles to return (default 50)" }
8452
+ },
8453
+ additionalProperties: false
8454
+ },
8455
+ constraints: { rate_bucket: "linear.read" },
8456
+ effects: ["Read:CycleList"],
8457
+ risk: "low",
8458
+ target_bindings: {
8459
+ resource_id: { source: "param", param: "teamId", required: false }
8460
+ },
8461
+ version: "1.0.0"
8462
+ },
8463
+ {
8464
+ action: "linear.cycle.read",
8465
+ resource_type: "linear:cycle",
8466
+ required_relations: ["viewer", "editor", "admin", "owner"],
8467
+ required_scopes: ["read"],
8468
+ capability: "linear.read.basic",
8469
+ input_schema: {
8470
+ type: "object",
8471
+ properties: {
8472
+ cycleId: { type: "string", minLength: 1, description: "Cycle ID" }
8473
+ },
8474
+ required: ["cycleId"],
8475
+ additionalProperties: false
8476
+ },
8477
+ constraints: { rate_bucket: "linear.read" },
8478
+ effects: ["Read:Cycle"],
8479
+ risk: "low",
8480
+ target_bindings: {
8481
+ resource_id: { source: "param", param: "cycleId" }
8482
+ },
8483
+ version: "1.0.0"
8484
+ },
8485
+ {
8486
+ action: "linear.cycle.create",
8487
+ resource_type: "linear:cycle",
8488
+ required_relations: ["editor", "act_as"],
8489
+ required_scopes: ["write"],
8490
+ capability: "linear.write.basic",
8491
+ input_schema: {
8492
+ type: "object",
8493
+ properties: {
8494
+ teamId: { type: "string", minLength: 1, description: "Team ID to create the cycle in" },
8495
+ name: { type: "string", description: "Cycle name" },
8496
+ startsAt: { type: "string", minLength: 1, description: "Cycle start date (ISO 8601)" },
8497
+ endsAt: { type: "string", minLength: 1, description: "Cycle end date (ISO 8601)" },
8498
+ description: { type: "string", description: "Cycle description" }
8499
+ },
8500
+ required: ["teamId", "startsAt", "endsAt"],
8501
+ additionalProperties: false
8502
+ },
8503
+ constraints: { rate_bucket: "linear.write" },
8504
+ effects: ["Create:Cycle"],
8505
+ risk: "high",
8506
+ target_bindings: {
8507
+ resource_id: { source: "param", param: "teamId" }
8508
+ },
8509
+ version: "1.0.0"
8510
+ },
8511
+ {
8512
+ action: "linear.cycle.update",
8513
+ resource_type: "linear:cycle",
8514
+ required_relations: ["editor", "act_as"],
8515
+ required_scopes: ["write"],
8516
+ capability: "linear.write.basic",
8517
+ input_schema: {
8518
+ type: "object",
8519
+ properties: {
8520
+ cycleId: { type: "string", minLength: 1, description: "Cycle ID to update" },
8521
+ name: { type: "string", description: "New cycle name" },
8522
+ startsAt: { type: "string", description: "New start date (ISO 8601)" },
8523
+ endsAt: { type: "string", description: "New end date (ISO 8601)" },
8524
+ description: { type: "string", description: "New description" },
8525
+ completedAt: { type: "string", description: "Completion date (ISO 8601) or null to unset" }
8526
+ },
8527
+ required: ["cycleId"],
8528
+ additionalProperties: false
8529
+ },
8530
+ constraints: { rate_bucket: "linear.write" },
8531
+ effects: ["Update:Cycle"],
8532
+ risk: "high",
8533
+ target_bindings: {
8534
+ resource_id: { source: "param", param: "cycleId" }
8535
+ },
8536
+ version: "1.0.0"
8537
+ },
8538
+ // ─── Linear Labels ───
8539
+ {
8540
+ action: "linear.label.create",
8541
+ resource_type: "linear:label",
8542
+ required_relations: ["editor", "act_as"],
8543
+ required_scopes: ["write"],
8544
+ capability: "linear.write.basic",
8545
+ input_schema: {
8546
+ type: "object",
8547
+ properties: {
8548
+ name: { type: "string", minLength: 1, description: "Label name" },
8549
+ color: { type: "string", description: "Label color (hex, e.g. #FF0000)" },
8550
+ description: { type: "string", description: "Label description" },
8551
+ teamId: { type: "string", description: "Team ID to scope the label to (omit for workspace-level label)" }
8552
+ },
8553
+ required: ["name"],
8554
+ additionalProperties: false
8555
+ },
8556
+ constraints: { rate_bucket: "linear.write" },
8557
+ effects: ["Create:Label"],
8558
+ risk: "high",
8559
+ target_bindings: {
8560
+ resource_id: { source: "param", param: "teamId", required: false }
8561
+ },
8562
+ version: "1.0.0"
8563
+ },
8564
+ {
8565
+ action: "linear.label.update",
8566
+ resource_type: "linear:label",
8567
+ required_relations: ["editor", "act_as"],
8568
+ required_scopes: ["write"],
8569
+ capability: "linear.write.basic",
8570
+ input_schema: {
8571
+ type: "object",
8572
+ properties: {
8573
+ labelId: { type: "string", minLength: 1, description: "Label ID to update" },
8574
+ name: { type: "string", description: "New label name" },
8575
+ color: { type: "string", description: "New label color (hex)" },
8576
+ description: { type: "string", description: "New description" }
8577
+ },
8578
+ required: ["labelId"],
8579
+ additionalProperties: false
8580
+ },
8581
+ constraints: { rate_bucket: "linear.write" },
8582
+ effects: ["Update:Label"],
8583
+ risk: "high",
8584
+ target_bindings: {
8585
+ resource_id: { source: "param", param: "labelId" }
8586
+ },
8587
+ version: "1.0.0"
8588
+ },
8589
+ // ─── Linear Attachments ───
8590
+ {
8591
+ action: "linear.attachment.create",
8592
+ resource_type: "linear:attachment",
8593
+ required_relations: ["editor", "act_as"],
8594
+ required_scopes: ["write"],
8595
+ capability: "linear.write.basic",
8596
+ input_schema: {
8597
+ type: "object",
8598
+ properties: {
8599
+ issueId: { type: "string", minLength: 1, description: "Issue ID to attach to" },
8600
+ title: { type: "string", minLength: 1, description: "Attachment title" },
8601
+ url: { type: "string", minLength: 1, description: "Attachment URL" },
8602
+ subtitle: { type: "string", description: "Attachment subtitle" }
8603
+ },
8604
+ required: ["issueId", "title", "url"],
8605
+ additionalProperties: false
8606
+ },
8607
+ constraints: { rate_bucket: "linear.write" },
8608
+ effects: ["Create:Attachment"],
8609
+ risk: "high",
8610
+ target_bindings: {
8611
+ resource_id: { source: "param", param: "issueId" }
8612
+ },
8613
+ version: "1.0.0"
8614
+ },
8615
+ {
8616
+ action: "linear.attachment.list",
8617
+ resource_type: "linear:attachment",
8618
+ required_relations: ["viewer", "editor", "admin", "owner"],
8619
+ required_scopes: ["read"],
8620
+ capability: "linear.read.basic",
8621
+ input_schema: {
8622
+ type: "object",
8623
+ properties: {
8624
+ issueId: { type: "string", minLength: 1, description: "Issue ID to list attachments for" }
8625
+ },
8626
+ required: ["issueId"],
8627
+ additionalProperties: false
8628
+ },
8629
+ constraints: { rate_bucket: "linear.read" },
8630
+ effects: ["Read:AttachmentList"],
8631
+ risk: "low",
8632
+ target_bindings: {
8633
+ resource_id: { source: "param", param: "issueId" }
8634
+ },
8635
+ version: "1.0.0"
8636
+ },
8637
+ {
8638
+ action: "linear.attachment.delete",
8639
+ resource_type: "linear:attachment",
8640
+ required_relations: ["editor", "act_as"],
8641
+ required_scopes: ["write"],
8642
+ capability: "linear.write.basic",
8643
+ input_schema: {
8644
+ type: "object",
8645
+ properties: {
8646
+ attachmentId: { type: "string", minLength: 1, description: "Attachment ID to delete" }
8647
+ },
8648
+ required: ["attachmentId"],
8649
+ additionalProperties: false
8650
+ },
8651
+ constraints: { rate_bucket: "linear.write" },
8652
+ effects: ["Delete:Attachment"],
8653
+ risk: "high",
8654
+ target_bindings: {
8655
+ resource_id: { source: "param", param: "attachmentId" }
8656
+ },
8657
+ version: "1.0.0"
8658
+ },
8659
+ // ─── Agent Inbox Actions (internal) ───
8660
+ // Inbox actions back the Agent Inbox MCP tools (task delegation between
8661
+ // agents/people). They are internal (no external OAuth provider), so they
8662
+ // carry a single nominal base scope `inbox` to satisfy the registry
8663
+ // meta-schema's `minItems: 1` (same pattern as hubspot.account.link.get).
8664
+ {
8665
+ action: "inbox.send",
8666
+ resource_type: "inbox:item",
8667
+ required_relations: ["editor", "act_as"],
8668
+ required_scopes: ["inbox"],
8669
+ capability: "inbox.write",
8670
+ input_schema: {
8671
+ type: "object",
8672
+ properties: {
8673
+ to: { type: "string", minLength: 1, description: "Recipient (user id / handle) the task request is sent to" },
8674
+ taskType: { type: "string", minLength: 1, description: "Type of task being requested" },
8675
+ payload: { type: "object", description: "Task-specific payload data" },
8676
+ message: { type: "string", description: "Optional human-readable message" }
8677
+ },
8678
+ required: ["to", "taskType", "payload"],
8679
+ additionalProperties: false
8680
+ },
8681
+ constraints: { rate_bucket: "inbox.write" },
8682
+ effects: ["Create:InboxItem"],
8683
+ risk: "high",
8684
+ target_bindings: {
8685
+ resource_id: { source: "param", param: "to" }
8686
+ },
8687
+ version: "1.0.0"
8688
+ },
8689
+ {
8690
+ action: "inbox.respond",
8691
+ resource_type: "inbox:item",
8692
+ required_relations: ["editor", "act_as"],
8693
+ required_scopes: ["inbox"],
8694
+ capability: "inbox.write",
8695
+ input_schema: {
8696
+ type: "object",
8697
+ properties: {
8698
+ id: { type: "string", minLength: 1, description: "Inbox item id being responded to" },
8699
+ action: { type: "string", enum: ["accept", "decline", "counter"], description: "Response action" },
8700
+ data: { type: "object", description: "Optional response data (e.g. counter-proposal)" }
8701
+ },
8702
+ required: ["id", "action"],
8703
+ additionalProperties: false
8704
+ },
8705
+ constraints: { rate_bucket: "inbox.write" },
8706
+ effects: ["Update:InboxItem"],
8707
+ // high (not medium): an agent-mediated response (MCP invoke) must always
8708
+ // go through human approval — the Phase 1 "always confirm" guarantee made
8709
+ // enforceable. target_bindings below binds the concrete inbox item id so
8710
+ // the high-risk approval has a specific resource constraint (the public
8711
+ // /scheduling/:token link flow does NOT go through this gate — it calls
8712
+ // InboxService.respond directly, system-key-signed).
8713
+ risk: "high",
8714
+ target_bindings: {
8715
+ resource_id: { source: "param", param: "id" }
8716
+ },
8717
+ version: "1.0.0"
8718
+ },
8719
+ {
8720
+ action: "inbox.check",
8721
+ resource_type: "inbox:item",
8722
+ required_relations: ["viewer", "editor", "admin", "owner"],
8723
+ required_scopes: ["inbox"],
8724
+ capability: "inbox.read",
8725
+ input_schema: {
8726
+ type: "object",
8727
+ properties: {
8728
+ types: { type: "array", items: { type: "string" }, description: "Filter by task types" },
8729
+ status: { type: "string", description: "Filter by item status" }
8730
+ },
8731
+ additionalProperties: false
8732
+ },
8733
+ constraints: { rate_bucket: "inbox.read" },
8734
+ effects: ["Read:InboxItem"],
8735
+ risk: "low",
8736
+ target_bindings: {
8737
+ resource_id: { source: "param", param: "id", required: false }
8738
+ },
8739
+ version: "1.0.0"
8740
+ },
8741
+ {
8742
+ action: "inbox.checkByToken",
8743
+ resource_type: "inbox:item",
8744
+ required_relations: ["viewer", "editor", "admin", "owner"],
8745
+ required_scopes: ["inbox"],
8746
+ capability: "inbox.read",
8747
+ input_schema: {
8748
+ type: "object",
8749
+ properties: {
8750
+ token: { type: "string", minLength: 1, description: "Opaque access token for a single inbox item" }
8751
+ },
8752
+ required: ["token"],
8753
+ additionalProperties: false
8754
+ },
8755
+ constraints: { rate_bucket: "inbox.read" },
8756
+ effects: ["Read:InboxItem"],
8757
+ risk: "low",
8758
+ target_bindings: {
8759
+ // inbox.checkByToken authenticates via the opaque HMAC token itself —
8760
+ // the token IS the authorization credential and must NOT appear in logs
8761
+ // or API error responses (resolvedResourceId surfaces on resource mismatch).
8762
+ // This action is dispatched before requireActor() so it bypasses the
8763
+ // normal grant-mediated authz path entirely. We deliberately bind to a
8764
+ // context key that the runtime never populates so that resource_id always
8765
+ // resolves to null and the secret token never reaches resolvedResourceId.
8766
+ resource_id: { source: "context", key: "inbox_item_id" }
8767
+ },
8768
+ version: "1.0.0"
8769
+ },
8770
+ {
8771
+ action: "inbox.complete",
8772
+ resource_type: "inbox:item",
8773
+ required_relations: ["editor", "act_as"],
8774
+ required_scopes: ["inbox"],
8775
+ capability: "inbox.write",
8776
+ input_schema: {
8777
+ type: "object",
8778
+ properties: {
8779
+ id: { type: "string", minLength: 1, description: "Inbox item id being completed" },
8780
+ result: { type: "object", description: "Result payload for the completed task" }
8781
+ },
8782
+ required: ["id", "result"],
8783
+ additionalProperties: false
8784
+ },
8785
+ constraints: { rate_bucket: "inbox.write" },
8786
+ effects: ["Update:InboxItem"],
8787
+ // low: inbox.complete marks an inbox item as done by the owning agent —
8788
+ // this is an internal state update on the agent's own task list, not an
8789
+ // external-facing write that needs human approval. (inbox.send / inbox.respond
8790
+ // are high because they create messages visible to other people.)
8791
+ risk: "low",
8792
+ target_bindings: {
8793
+ resource_id: { source: "param", param: "id" }
8794
+ },
8795
+ version: "1.0.0"
8796
+ },
8797
+ // ─── Scheduling Actions (internal) ───
8798
+ // scheduling.request is a meeting-time negotiation façade over inbox.send.
8799
+ // Candidate slots may be supplied two ways (server-side EXCLUSIVE — exactly
8800
+ // one): (a) `candidates` — the agent computes them LLM-side from the user
8801
+ // calendar and the server validates + freebusy-filters them, or (b)
8802
+ // `candidateWindow` — the agent hands the server a { start, end } window and
8803
+ // the server generates busy-free candidates from the sender's Google
8804
+ // Calendar. Like the inbox actions it is internal (no external OAuth
8805
+ // provider), so it carries the single nominal base scope `inbox`.
8806
+ //
8807
+ // NOTE: the candidates/candidateWindow exclusivity is expressed here as
8808
+ // `oneOf` for documentation + the deep JSON-Schema authorities, but the SDK's
8809
+ // hand-written `validateActionInput` is a SHALLOW shape gate that does NOT
8810
+ // interpret `oneOf` (neither key is in top-level `required`). The exclusivity
8811
+ // (exactly one of candidates/candidateWindow) is ENFORCED server-side in
8812
+ // SchedulingRequestService — see that service for the 400s on both-given /
8813
+ // both-missing.
8814
+ // Spec: docs/specs/2026-06-10-inbox-intent-routing-design.md §2.1
8815
+ {
8816
+ action: "scheduling.request",
8817
+ resource_type: "inbox:item",
8818
+ required_relations: ["editor", "act_as"],
8819
+ required_scopes: ["inbox"],
8820
+ capability: "inbox.write",
8821
+ input_schema: {
8822
+ type: "object",
8823
+ properties: {
8824
+ to: { type: "string", minLength: 1, description: "Counterpart (user id / email) to negotiate a meeting time with" },
8825
+ topic: { type: "string", minLength: 1, description: "Meeting topic shown to the counterpart" },
8826
+ durationMinutes: { type: "integer", minimum: 5, maximum: 480, description: "Meeting length in minutes" },
8827
+ candidates: {
8828
+ type: "array",
8829
+ minItems: 1,
8830
+ maxItems: 10,
8831
+ description: "Explicit candidate slots computed by the agent from the user calendar. The server validates them AND (when Google Calendar is connected) filters out any that conflict with the sender's calendar. Mutually exclusive with candidateWindow \u2014 supply exactly one.",
8832
+ items: {
8833
+ type: "object",
8834
+ properties: {
8835
+ start: { type: "string", description: "ISO 8601 start" },
8836
+ end: { type: "string", description: "ISO 8601 end" }
8837
+ },
8838
+ required: ["start", "end"],
8839
+ additionalProperties: false
8840
+ }
8841
+ },
8842
+ // candidateWindow is `{start,end}` OR an ARRAY of `{start,end}` ranges
8843
+ // (multi-range). We declare `type: ['object', 'array']` — the SDK
8844
+ // shallow validator (matchesType) does not handle an ARRAY of types
8845
+ // (its switch is on a single string), so it hits `default: return true`
8846
+ // and passes BOTH the single object and the array form (B-1 — an array
8847
+ // must NOT be rejected before reaching the server). The union type also
8848
+ // keeps the AJV strict-mode meta-schema happy (a `required`/`properties`
8849
+ // subschema needs SOME type). The nested `properties`/`required` below
8850
+ // describe the object form for the deep JSON-Schema authorities; the
8851
+ // array element shape and the deep constraints (ISO, start<end, ≤5
8852
+ // ranges, ≤62-day total span) are validated server-side in
8853
+ // SchedulingRequestService.validateWindowRanges.
8854
+ candidateWindow: {
8855
+ type: ["object", "array"],
8856
+ description: 'A search window OR an ARRAY of search windows the server fills with busy-free candidate slots from the sender\'s Google Calendar. Each range is `{ start, end }` (ISO 8601) \u2014 an independent contiguous interval the server searches within, spreading candidates across ranges. "\u5E73\u65E5\u5348\u5F8C" = one range per business day (Mon 13-18 / Tue 13-18 / \u2026); "\u6708\u66DC\u5348\u524D or \u6728\u66DC\u5348\u5F8C" = two ranges. A single contiguous span = one range. Max 5 ranges, total span \u2264 62 days. Mutually exclusive with candidates \u2014 supply exactly one. Requires a connected Google Calendar.',
8857
+ properties: {
8858
+ start: { type: "string", description: "ISO 8601 range start" },
8859
+ end: { type: "string", description: "ISO 8601 range end" }
8860
+ },
8861
+ required: ["start", "end"],
8862
+ additionalProperties: false
8863
+ },
8864
+ hold: {
8865
+ type: "boolean",
8866
+ description: "When true (or omitted, when the sender's delegation policy has holds enabled), tentatively hold the offered slots on the sender's calendar as [\u4EEE] events until the counterpart responds or the request expires. Pass false to skip holds for this request. Only takes effect when the sender has an enabled scheduling delegation policy."
8867
+ },
8868
+ message: { type: "string", description: "Optional human-readable message" }
8869
+ },
8870
+ // candidates / candidateWindow are intentionally NOT in `required`: the
8871
+ // exclusive-choice is documented via `oneOf` and enforced server-side.
8872
+ // Each oneOf branch re-declares its property locally (empty `properties`
8873
+ // entry) so AJV strict mode (`strictRequired`) sees the required key as
8874
+ // defined within the branch scope — the value shape itself is validated
8875
+ // by the top-level `properties` above.
8876
+ required: ["to", "topic", "durationMinutes"],
8877
+ oneOf: [
8878
+ { required: ["candidates"], properties: { candidates: {} } },
8879
+ { required: ["candidateWindow"], properties: { candidateWindow: {} } }
8880
+ ],
8881
+ additionalProperties: false
8882
+ },
8883
+ constraints: { rate_bucket: "inbox.write" },
8884
+ effects: ["Create:InboxItem"],
8885
+ risk: "high",
8886
+ target_bindings: {
8887
+ resource_id: { source: "param", param: "to" }
8888
+ },
8889
+ version: "1.0.0"
8890
+ }
8891
+ ],
8892
+ capabilities: [
8893
+ {
8894
+ capability: "slack.messaging.basic",
8895
+ description: "Post, update, and delete messages in channels",
8896
+ includes: ["slack.message.post", "slack.message.update", "slack.message.delete"],
8897
+ version: "1.0.0"
8898
+ },
8899
+ {
8900
+ capability: "slack.read.basic",
8901
+ description: "Read channels, messages, and user info",
8902
+ includes: ["slack.channel.read", "slack.user.read", "slack.message.read", "slack.message.read_paginated", "slack.batch.read"],
8903
+ version: "1.0.0"
8904
+ },
8905
+ {
8906
+ capability: "github.read.basic",
8907
+ description: "Read issues, pull requests and repository contents from repositories",
8908
+ includes: ["github.issue.list", "github.issue.read", "github.pr.list", "github.pr.read", "github.pr.files.list", "github.pr.review.list", "github.pr.search", "github.repo.search", "github.repo.collaborator.list", "github.content.get", "github.tree.get", "github.branch.list", "github.commit.get", "github.commit.list", "github.commit.search", "github.tag.list", "github.release.list", "github.release.getLatest", "github.release.getByTag", "github.code.search", "github.issue.search", "github.issue.types.list", "github.label.get", "github.label.list", "github.workflow.get", "github.workflow.list", "github.workflow.jobLogs.get", "github.repo.starred.list", "github.user.me.get", "github.org.teams.list", "github.team.members.list", "github.user.search", "github.notification.list", "github.notification.get", "github.gist.get", "github.gist.list"],
8909
+ version: "1.0.0"
8910
+ },
8911
+ {
8912
+ capability: "github.issues.triage",
8913
+ description: "Create and update issues, post issue comments, manage sub-issues and labels",
8914
+ includes: ["github.issue.create", "github.issue.update", "github.issue.comment.create", "github.issue.subissue.write", "github.label.write"],
8915
+ version: "1.0.0"
8916
+ },
8917
+ {
8918
+ capability: "github.pulls.write",
8919
+ description: "Create, update, merge, and review pull requests",
8920
+ includes: ["github.pr.create", "github.pr.update", "github.pr.merge", "github.pr.review.create", "github.pr.comment.reply", "github.pr.branch.update"],
8921
+ version: "1.0.0"
8922
+ },
8923
+ {
8924
+ capability: "github.repos.write",
8925
+ description: "\u30EA\u30DD\u30B8\u30C8\u30EA\u306E\u4F5C\u6210\u30FB\u30D5\u30A9\u30FC\u30AF\u30FB\u30D5\u30A1\u30A4\u30EB\u66F4\u65B0\u30FB\u30D6\u30E9\u30F3\u30C1\u4F5C\u6210\u30FB\u30EF\u30FC\u30AF\u30D5\u30ED\u30FC\u5B9F\u884C\u30FB\u30B9\u30BF\u30FC\u64CD\u4F5C",
8926
+ includes: ["github.repo.create", "github.repo.fork", "github.content.createOrUpdate", "github.content.delete", "github.branch.create", "github.workflow.run", "github.repo.star", "github.repo.unstar"],
8927
+ version: "1.0.0"
8928
+ },
8929
+ {
8930
+ capability: "github.notifications.write",
8931
+ description: "\u901A\u77E5\u306E\u65E2\u8AAD\u5316\u30FB\u30B9\u30EC\u30C3\u30C9/\u30EA\u30DD\u30B8\u30C8\u30EA\u306E\u8CFC\u8AAD\u8A2D\u5B9A",
8932
+ includes: ["github.notification.markRead", "github.notification.markAllRead", "github.notification.subscription.set", "github.notification.repoSubscription.set"],
8933
+ version: "1.0.0"
8934
+ },
8935
+ {
8936
+ capability: "github.gists.write",
8937
+ description: "Gist \u306E\u4F5C\u6210\u30FB\u66F4\u65B0",
8938
+ includes: ["github.gist.create", "github.gist.update"],
8939
+ version: "1.0.0"
8940
+ },
8941
+ {
8942
+ capability: "gmail.read.basic",
8943
+ description: "Read and search Gmail messages and labels",
8944
+ includes: ["gmail.message.search", "gmail.message.read", "gmail.label.read", "gmail.batch.read"],
8945
+ version: "1.0.0"
8946
+ },
8947
+ {
8948
+ capability: "gmail.compose",
8949
+ description: "Send emails and create drafts via Gmail",
8950
+ includes: ["gmail.message.send", "gmail.draft.create"],
8951
+ version: "1.0.0"
8952
+ },
8953
+ {
8954
+ capability: "gmail.manage",
8955
+ description: "Trash and permanently delete Gmail messages",
8956
+ includes: ["gmail.message.trash", "gmail.message.delete"],
8957
+ version: "1.0.0"
8958
+ },
8959
+ {
8960
+ capability: "calendar.read.basic",
8961
+ description: "Read and list Google Calendar events, and check free/busy availability",
8962
+ includes: ["calendar.event.list", "calendar.event.read", "calendar.freebusy"],
8963
+ version: "1.0.0"
8964
+ },
8965
+ {
8966
+ capability: "calendar.write",
8967
+ description: "Create, update, and delete Google Calendar events",
8968
+ includes: ["calendar.event.create", "calendar.event.update", "calendar.event.delete"],
8969
+ version: "1.0.0"
8970
+ },
8971
+ {
8972
+ capability: "jira.read.basic",
8973
+ description: "Read Jira issues, projects, boards, sprints, issue link types, and users",
8974
+ includes: ["jira.project.read", "jira.board.read", "jira.sprint.read", "jira.issue.list", "jira.issue.search", "jira.worklog.read", "jira.issue.read", "jira.batch.read", "jira.comment.read", "jira.transition.list", "jira.issuelinktype.list", "jira.user.search"],
8975
+ version: "1.0.0"
8976
+ },
8977
+ {
8978
+ capability: "jira.write.basic",
8979
+ description: "Create, update, delete Jira issues, manage issue links, and add/delete comments",
8980
+ includes: ["jira.issue.create", "jira.issue.update", "jira.issue.delete", "jira.comment.create", "jira.comment.delete", "jira.issue.transition", "jira.issuelink.create", "jira.issuelink.delete"],
8981
+ version: "1.0.0"
8982
+ },
8983
+ {
8984
+ capability: "inbox.write",
8985
+ description: "Send and respond to agent inbox tasks",
8986
+ includes: ["inbox.send", "inbox.respond", "inbox.complete", "scheduling.request"],
8987
+ version: "1.0.0"
8988
+ },
8989
+ {
8990
+ capability: "inbox.read",
8991
+ description: "Read agent inbox tasks",
8992
+ includes: ["inbox.check", "inbox.checkByToken"],
8993
+ version: "1.0.0"
8994
+ },
8995
+ {
8996
+ capability: "linear.read.basic",
8997
+ description: "Read Linear issues, comments, projects, teams, workflow states, labels, users, viewer info, issue relations, cycles, and attachments",
8998
+ includes: [
8999
+ "linear.issue.list",
9000
+ "linear.issue.read",
9001
+ "linear.issue.search",
9002
+ "linear.comment.list",
9003
+ "linear.project.list",
9004
+ "linear.project.read",
9005
+ "linear.team.list",
9006
+ "linear.workflowState.list",
9007
+ "linear.viewer.read",
9008
+ "linear.label.list",
9009
+ "linear.user.list",
9010
+ "linear.issueRelation.list",
9011
+ "linear.cycle.list",
9012
+ "linear.cycle.read",
9013
+ "linear.attachment.list"
9014
+ ],
9015
+ version: "1.0.0"
9016
+ },
9017
+ {
9018
+ capability: "linear.write.basic",
9019
+ description: "Create, update, archive, delete Linear issues, comments, projects, labels, cycles, attachments, and issue relations",
9020
+ includes: [
9021
+ "linear.issue.create",
9022
+ "linear.issue.update",
9023
+ "linear.comment.create",
9024
+ "linear.issue.archive",
9025
+ "linear.project.create",
9026
+ "linear.project.update",
9027
+ "linear.comment.update",
9028
+ "linear.comment.delete",
9029
+ "linear.comment.resolve",
9030
+ "linear.comment.unresolve",
9031
+ "linear.issue.unarchive",
9032
+ "linear.issue.addLabel",
9033
+ "linear.issue.removeLabel",
9034
+ "linear.issue.subscribe",
9035
+ "linear.issue.delete",
9036
+ "linear.issueRelation.create",
9037
+ "linear.issueRelation.delete",
9038
+ "linear.cycle.create",
9039
+ "linear.cycle.update",
9040
+ "linear.label.create",
9041
+ "linear.label.update",
9042
+ "linear.attachment.create",
9043
+ "linear.attachment.delete"
9044
+ ],
9045
+ version: "1.0.0"
9046
+ },
9047
+ {
9048
+ capability: "inbox.write",
9049
+ description: "Send and respond to agent inbox tasks",
9050
+ includes: ["inbox.send", "inbox.respond", "inbox.complete", "scheduling.request"],
9051
+ version: "1.0.0"
9052
+ },
9053
+ {
9054
+ capability: "inbox.read",
9055
+ description: "Read agent inbox tasks",
9056
+ includes: ["inbox.check", "inbox.checkByToken"],
9057
+ version: "1.0.0"
9058
+ }
9059
+ ]
9060
+ };
9061
+
9062
+ // src/registry/resource-type-labels.ts
9063
+ var RESOURCE_TYPE_LABELS = {
9064
+ "github:repo": "\u5BFE\u8C61\u30EA\u30DD\u30B8\u30C8\u30EA",
9065
+ "github:org": "\u5BFE\u8C61\u7D44\u7E54"
9066
+ };
9067
+
9068
+ // src/registry/action-input-validator.ts
9069
+ var SCHEMA_INDEX = (() => {
9070
+ const map = /* @__PURE__ */ new Map();
9071
+ for (const a of ACTION_REGISTRY.actions) {
9072
+ if (a && typeof a.action === "string" && a.input_schema) {
9073
+ map.set(a.action, a.input_schema);
9074
+ }
9075
+ }
9076
+ return map;
9077
+ })();
9078
+ function describeExpectedShape(schema) {
9079
+ const props = schema.properties ?? {};
9080
+ const required = Array.isArray(schema.required) ? schema.required : [];
9081
+ const requiredSet = new Set(required);
9082
+ const parts = [];
9083
+ const orderedKeys = [
9084
+ ...required.filter((k) => k in props),
9085
+ ...Object.keys(props).filter((k) => !requiredSet.has(k))
9086
+ ];
9087
+ for (const key of orderedKeys) {
9088
+ const prop = props[key] || {};
9089
+ const optionalMark = requiredSet.has(key) ? "" : "?";
9090
+ const enumVals = Array.isArray(prop.enum) ? prop.enum : void 0;
9091
+ if (enumVals && enumVals.length > 0) {
9092
+ const rendered = enumVals.map((v) => typeof v === "string" ? `'${v}'` : String(v)).join(" | ");
9093
+ parts.push(`${key}${optionalMark}: ${rendered}`);
9094
+ } else {
9095
+ parts.push(`${key}${optionalMark}`);
9096
+ }
9097
+ }
9098
+ return `{ ${parts.join(", ")} }`;
9099
+ }
9100
+ function matchesType(value, type) {
9101
+ if (!type) return true;
9102
+ switch (type) {
9103
+ case "string":
9104
+ return typeof value === "string";
9105
+ case "integer":
9106
+ return typeof value === "number" && Number.isInteger(value);
9107
+ case "number":
9108
+ return typeof value === "number";
9109
+ case "boolean":
9110
+ return typeof value === "boolean";
9111
+ case "array":
9112
+ return Array.isArray(value);
9113
+ case "object":
9114
+ return typeof value === "object" && value !== null && !Array.isArray(value);
9115
+ default:
9116
+ return true;
9117
+ }
9118
+ }
9119
+ function validateActionInput(action, params) {
9120
+ const schema = SCHEMA_INDEX.get(action);
9121
+ if (!schema) {
9122
+ return { valid: true };
9123
+ }
9124
+ const props = schema.properties ?? {};
9125
+ const required = Array.isArray(schema.required) ? schema.required : [];
9126
+ const additionalProps = schema.additionalProperties;
9127
+ const safeParams = params && typeof params === "object" && !Array.isArray(params) ? params : {};
9128
+ const missing = [];
9129
+ const unknown = [];
9130
+ const enumErrors = [];
9131
+ const typeErrors = [];
9132
+ for (const key of required) {
9133
+ if (!(key in safeParams) || safeParams[key] === void 0 || safeParams[key] === null) {
9134
+ missing.push(key);
9135
+ }
9136
+ }
9137
+ if (additionalProps === false) {
9138
+ for (const key of Object.keys(safeParams)) {
9139
+ if (!(key in props)) {
9140
+ unknown.push(key);
9141
+ }
9142
+ }
9143
+ }
9144
+ for (const key of Object.keys(props)) {
9145
+ if (!(key in safeParams)) continue;
9146
+ const value = safeParams[key];
9147
+ if (value === void 0 || value === null) continue;
9148
+ const prop = props[key] || {};
9149
+ const enumVals = Array.isArray(prop.enum) ? prop.enum : void 0;
9150
+ if (enumVals && enumVals.length > 0) {
9151
+ if (!enumVals.includes(value)) {
9152
+ enumErrors.push(key);
9153
+ continue;
9154
+ }
9155
+ }
9156
+ if (!matchesType(value, prop.type)) {
9157
+ typeErrors.push(key);
9158
+ }
9159
+ }
9160
+ if (missing.length === 0 && unknown.length === 0 && enumErrors.length === 0 && typeErrors.length === 0) {
9161
+ return { valid: true };
9162
+ }
9163
+ const segments = [];
9164
+ if (missing.length > 0) {
9165
+ segments.push(`missing required parameter(s) [${missing.join(", ")}]`);
9166
+ }
9167
+ if (unknown.length > 0) {
9168
+ segments.push(`unknown parameter(s) [${unknown.join(", ")}]`);
9169
+ }
9170
+ if (enumErrors.length > 0) {
9171
+ const details = enumErrors.map((key) => {
9172
+ const enumVals = props[key]?.enum || [];
9173
+ const rendered = enumVals.map((v) => typeof v === "string" ? `'${v}'` : String(v)).join(" | ");
9174
+ return `${key} (allowed: ${rendered})`;
9175
+ }).join(", ");
9176
+ segments.push(`invalid value for enum parameter(s) [${details}]`);
9177
+ }
9178
+ if (typeErrors.length > 0) {
9179
+ const details = typeErrors.map((key) => `${key} (expected ${props[key]?.type})`).join(", ");
9180
+ segments.push(`wrong type for parameter(s) [${details}]`);
9181
+ }
9182
+ const message = `${action}: ${segments.join("; ")}. Expected shape: ${describeExpectedShape(schema)}`;
9183
+ return { valid: false, errors: [message] };
9184
+ }
9185
+
9186
+ // src/registry/resource-types.ts
9187
+ var RESOURCE_TYPES = {
9188
+ // Slack
9189
+ SLACK_CHANNEL: "slack:channel",
9190
+ SLACK_USER: "slack:user",
9191
+ SLACK_WORKSPACE: "slack:workspace",
9192
+ // GitHub
9193
+ GITHUB_REPO: "github:repo",
9194
+ GITHUB_ORG: "github:org",
9195
+ GITHUB_ISSUE: "github:issue",
9196
+ // Google Drive
9197
+ GOOGLE_DRIVE_FILE: "google:drive:file",
9198
+ GOOGLE_DRIVE_FOLDER: "google:drive:folder",
9199
+ // Gmail
9200
+ GMAIL_THREAD: "gmail:thread",
9201
+ GMAIL_LABEL: "gmail:label",
9202
+ // Jira
9203
+ JIRA_PROJECT: "jira:project",
9204
+ JIRA_BOARD: "jira:board",
9205
+ JIRA_ISSUE: "jira:issue",
9206
+ JIRA_SPRINT: "jira:sprint",
9207
+ // HubSpot
9208
+ HUBSPOT_OBJECT: "hubspot:object",
9209
+ HUBSPOT_PROPERTY: "hubspot:property",
9210
+ HUBSPOT_SCHEMA: "hubspot:schema",
8218
9211
  HUBSPOT_ASSOCIATION: "hubspot:association",
8219
9212
  HUBSPOT_ENGAGEMENT: "hubspot:engagement",
8220
9213
  HUBSPOT_WORKFLOW: "hubspot:workflow",
@@ -8436,188 +9429,773 @@ var ACTION_DISPLAY_CONFIGS = {
8436
9429
  "slack.message.post": {
8437
9430
  summaryTemplate: (p) => {
8438
9431
  const parts = [];
8439
- if (p.channel) parts.push(p.channel + ":");
8440
- if (p.text) parts.push(String(p.text));
9432
+ if (p.channel) parts.push(p.channel + ":");
9433
+ if (p.text) parts.push(String(p.text));
9434
+ return parts.join(" ");
9435
+ },
9436
+ displayFields: [
9437
+ { key: "channel", label: "Channel" },
9438
+ { key: "text", label: "Message" }
9439
+ ]
9440
+ },
9441
+ "gmail.message.send": {
9442
+ summaryTemplate: (p) => {
9443
+ const parts = [];
9444
+ if (p.to) parts.push(`To: ${p.to}`);
9445
+ if (p.subject) parts.push(`Subject: ${p.subject}`);
9446
+ return parts.join(", ");
9447
+ },
9448
+ displayFields: [
9449
+ { key: "to", label: "To" },
9450
+ { key: "subject", label: "Subject" },
9451
+ { key: "body", label: "Body" }
9452
+ ]
9453
+ },
9454
+ "gmail.draft.create": {
9455
+ summaryTemplate: (p) => {
9456
+ const parts = [];
9457
+ if (p.to) parts.push(`To: ${p.to}`);
9458
+ if (p.subject) parts.push(`Subject: ${p.subject}`);
9459
+ return parts.join(", ");
9460
+ },
9461
+ displayFields: [
9462
+ { key: "to", label: "To" },
9463
+ { key: "subject", label: "Subject" },
9464
+ { key: "body", label: "Body" }
9465
+ ]
9466
+ },
9467
+ "calendar.event.create": {
9468
+ summaryTemplate: (p) => {
9469
+ const parts = [];
9470
+ if (p.summary) parts.push(p.summary);
9471
+ if (p.start) parts.push(`(${formatCalendarTime(p.start)})`);
9472
+ return parts.join(" ");
9473
+ },
9474
+ displayFields: [
9475
+ { key: "summary", label: "Event" },
9476
+ { key: "start", label: "Start" },
9477
+ { key: "end", label: "End" },
9478
+ { key: "attendees", label: "Attendees" }
9479
+ ]
9480
+ },
9481
+ "calendar.event.update": {
9482
+ summaryTemplate: (p) => {
9483
+ const parts = [];
9484
+ if (p.summary) parts.push(p.summary);
9485
+ if (p.start) parts.push(`(${formatCalendarTime(p.start)})`);
9486
+ return parts.join(" ");
9487
+ },
9488
+ displayFields: [
9489
+ { key: "summary", label: "Event" },
9490
+ { key: "start", label: "Start" },
9491
+ { key: "end", label: "End" },
9492
+ { key: "attendees", label: "Attendees" }
9493
+ ]
9494
+ },
9495
+ "jira.issue.create": {
9496
+ summaryTemplate: (p) => {
9497
+ const parts = [];
9498
+ const projectKey = jiraField(
9499
+ p,
9500
+ ["projectKey", "project"],
9501
+ "project",
9502
+ (v) => typeof v === "string" ? v : v?.key
9503
+ );
9504
+ const summary = jiraField(p, ["summary"], "summary");
9505
+ if (projectKey) parts.push(`${projectKey}:`);
9506
+ if (summary) parts.push(summary);
9507
+ return parts.join(" ");
9508
+ },
9509
+ // AIDENTITY-54: nested `fields.X` 形式と top-level canonical の両方を
9510
+ // 拾えるよう extract を使う。assignee は null (unassign) も表示。
9511
+ // legacy alias (project / issuetype 等) も top-level 候補に含めて後方互換を保つ。
9512
+ displayFields: [
9513
+ {
9514
+ label: "Project",
9515
+ extract: (p) => jiraField(
9516
+ p,
9517
+ ["projectKey", "project"],
9518
+ "project",
9519
+ (v) => typeof v === "string" ? v : v?.key
9520
+ )
9521
+ },
9522
+ {
9523
+ label: "Type",
9524
+ extract: (p) => jiraField(
9525
+ p,
9526
+ ["issueTypeName", "issueType", "issuetype"],
9527
+ "issuetype",
9528
+ (v) => typeof v === "string" ? v : v?.name
9529
+ )
9530
+ },
9531
+ { label: "Summary", extract: (p) => jiraField(p, ["summary"], "summary") },
9532
+ { label: "Description", extract: (p) => jiraField(p, ["description"], "description") },
9533
+ {
9534
+ label: "Priority",
9535
+ extract: (p) => jiraField(
9536
+ p,
9537
+ ["priority"],
9538
+ "priority",
9539
+ (v) => typeof v === "string" ? v : v?.name
9540
+ )
9541
+ },
9542
+ { label: "Assignee", extract: extractJiraAssigneeDisplay },
9543
+ { label: "Labels", extract: (p) => jiraField(p, ["labels"], "labels") }
9544
+ ]
9545
+ },
9546
+ "jira.issue.update": {
9547
+ summaryTemplate: (p) => {
9548
+ const parts = [];
9549
+ const key = p.issueIdOrKey ?? p.issueKey;
9550
+ const summary = jiraField(p, ["summary"], "summary");
9551
+ if (key) parts.push(`${key}:`);
9552
+ if (summary) parts.push(summary);
9553
+ return parts.join(" ");
9554
+ },
9555
+ displayFields: [
9556
+ // canonical は issueIdOrKey、agent が issueKey で送ってくる旧仕様も拾う。
9557
+ { label: "Issue", extract: (p) => p.issueIdOrKey ?? p.issueKey },
9558
+ { label: "Summary", extract: (p) => jiraField(p, ["summary"], "summary") },
9559
+ { label: "Description", extract: (p) => jiraField(p, ["description"], "description") },
9560
+ {
9561
+ label: "Priority",
9562
+ extract: (p) => jiraField(
9563
+ p,
9564
+ ["priority"],
9565
+ "priority",
9566
+ (v) => typeof v === "string" ? v : v?.name
9567
+ )
9568
+ },
9569
+ // AIDENTITY-54: top-level alias (string / object) と null (unassign) も解決。
9570
+ { label: "Assignee", extract: extractJiraAssigneeDisplay },
9571
+ { label: "Labels", extract: (p) => jiraField(p, ["labels"], "labels") }
9572
+ ]
9573
+ },
9574
+ // AIDENTITY-65: comment 本体は string と ADF document の両方を受けるため、
9575
+ // detail 表示の ADF 描画は formatValueFull 側に任せて key 指定で OK。
9576
+ "jira.comment.create": {
9577
+ summaryTemplate: (p) => {
9578
+ const parts = [];
9579
+ if (p.issueIdOrKey) parts.push(`${p.issueIdOrKey}:`);
9580
+ if (p.body) parts.push(typeof p.body === "string" ? p.body : "[ADF]");
9581
+ return parts.join(" ");
9582
+ },
9583
+ displayFields: [
9584
+ { key: "issueIdOrKey", label: "Issue" },
9585
+ { key: "body", label: "Comment" }
9586
+ ]
9587
+ },
9588
+ // AIDENTITY-66: 破壊的操作なので「どの issue のどの comment を消すか」を明示する
9589
+ // (jira.issue.delete / jira.issuelink.delete と同じ destructive 表現の方針)。
9590
+ "jira.comment.delete": {
9591
+ summaryTemplate: (p) => {
9592
+ const issue = p.issueIdOrKey ?? p.issueKey;
9593
+ const commentId = p.commentId ?? p.id;
9594
+ if (issue && commentId) return `Delete comment ${commentId} on ${issue}`;
9595
+ if (commentId) return `Delete comment ${commentId}`;
9596
+ return "";
9597
+ },
9598
+ displayFields: [
9599
+ { label: "Issue", extract: (p) => p.issueIdOrKey ?? p.issueKey },
9600
+ { label: "Comment", extract: (p) => p.commentId ?? p.id }
9601
+ ]
9602
+ },
9603
+ // AIDENTITY-65: API enricher が 'Link' label を upsert で書き換える。
9604
+ "jira.issuelink.delete": {
9605
+ summaryTemplate: (p) => {
9606
+ const parts = [];
9607
+ if (p.linkId) parts.push(`Delete link ${p.linkId}`);
9608
+ return parts.join(" ");
9609
+ },
9610
+ displayFields: [
9611
+ { key: "linkId", label: "Link" }
9612
+ ]
9613
+ },
9614
+ // ─── HubSpot ───
9615
+ "hubspot.crm.objects.list": {
9616
+ summaryTemplate: (p) => {
9617
+ const parts = [];
9618
+ if (p.objectType) parts.push(String(p.objectType));
9619
+ parts.push("list");
9620
+ return parts.join(" ");
9621
+ },
9622
+ displayFields: [
9623
+ { key: "objectType", label: "Object Type" },
9624
+ { key: "limit", label: "Limit" },
9625
+ { key: "properties", label: "Properties" }
9626
+ ]
9627
+ },
9628
+ "hubspot.crm.objects.search": {
9629
+ summaryTemplate: (p) => {
9630
+ const parts = [];
9631
+ if (p.objectType) parts.push(String(p.objectType));
9632
+ if (p.query) parts.push(`"${String(p.query)}"`);
9633
+ return parts.join(" ");
9634
+ },
9635
+ displayFields: [
9636
+ { key: "objectType", label: "Object Type" },
9637
+ { key: "query", label: "Query" },
9638
+ { key: "limit", label: "Limit" }
9639
+ ]
9640
+ },
9641
+ "hubspot.crm.objects.batchRead": {
9642
+ summaryTemplate: (p) => {
9643
+ const parts = [];
9644
+ if (p.objectType) parts.push(String(p.objectType));
9645
+ if (Array.isArray(p.inputs)) parts.push(`(${p.inputs.length} items)`);
9646
+ return parts.join(" ");
9647
+ },
9648
+ displayFields: [
9649
+ { key: "objectType", label: "Object Type" },
9650
+ { key: "inputs", label: "Records" }
9651
+ ]
9652
+ },
9653
+ "hubspot.crm.objects.batchCreate": {
9654
+ summaryTemplate: (p) => {
9655
+ const parts = [];
9656
+ if (p.objectType) parts.push(String(p.objectType));
9657
+ if (Array.isArray(p.inputs)) parts.push(`create ${p.inputs.length}`);
9658
+ return parts.join(" ");
9659
+ },
9660
+ displayFields: [
9661
+ { key: "objectType", label: "Object Type" },
9662
+ { key: "inputs", label: "Records" }
9663
+ ]
9664
+ },
9665
+ "hubspot.crm.objects.batchUpdate": {
9666
+ summaryTemplate: (p) => {
9667
+ const parts = [];
9668
+ if (p.objectType) parts.push(String(p.objectType));
9669
+ if (Array.isArray(p.inputs)) parts.push(`update ${p.inputs.length}`);
9670
+ return parts.join(" ");
9671
+ },
9672
+ displayFields: [
9673
+ { key: "objectType", label: "Object Type" },
9674
+ { key: "inputs", label: "Records" }
9675
+ ]
9676
+ },
9677
+ "hubspot.crm.properties.list": {
9678
+ summaryTemplate: (p) => {
9679
+ const parts = [];
9680
+ if (p.objectType) parts.push(String(p.objectType));
9681
+ parts.push("properties list");
9682
+ return parts.join(" ");
9683
+ },
9684
+ displayFields: [
9685
+ { key: "objectType", label: "Object Type" }
9686
+ ]
9687
+ },
9688
+ "hubspot.crm.properties.create": {
9689
+ summaryTemplate: (p) => {
9690
+ const parts = [];
9691
+ if (p.objectType) parts.push(String(p.objectType));
9692
+ if (p.name) parts.push(String(p.name));
9693
+ return parts.join(" ");
9694
+ },
9695
+ displayFields: [
9696
+ { key: "objectType", label: "Object Type" },
9697
+ { key: "name", label: "Property Name" },
9698
+ { key: "label", label: "Label" },
9699
+ { key: "type", label: "Type" }
9700
+ ]
9701
+ },
9702
+ "hubspot.crm.engagements.create": {
9703
+ summaryTemplate: (p) => {
9704
+ const parts = [];
9705
+ if (p.type) parts.push(String(p.type));
9706
+ parts.push("engagement");
9707
+ return parts.join(" ");
9708
+ },
9709
+ displayFields: [
9710
+ { key: "type", label: "Type" },
9711
+ { key: "metadata", label: "Metadata" }
9712
+ ]
9713
+ },
9714
+ "hubspot.automation.workflows.list": {
9715
+ summaryTemplate: (_p) => "List workflows",
9716
+ displayFields: [
9717
+ { key: "limit", label: "Limit" }
9718
+ ]
9719
+ },
9720
+ "hubspot.account.userDetails.get": {
9721
+ summaryTemplate: (_p) => "Get HubSpot account details",
9722
+ displayFields: []
9723
+ },
9724
+ "hubspot.account.link.get": {
9725
+ summaryTemplate: (p) => {
9726
+ const parts = [];
9727
+ if (p.portalId) parts.push(`portal:${p.portalId}`);
9728
+ if (Array.isArray(p.pageRequests)) parts.push(`(${p.pageRequests.length} links)`);
9729
+ return parts.join(" ");
9730
+ },
9731
+ displayFields: [
9732
+ { key: "portalId", label: "Portal ID" },
9733
+ { key: "pageRequests", label: "Page Requests" }
9734
+ ]
9735
+ },
9736
+ // ─── Linear ───
9737
+ "linear.issue.create": {
9738
+ summaryTemplate: (p) => {
9739
+ const parts = [];
9740
+ if (p.teamId) parts.push(`${p.teamId}:`);
9741
+ if (p.title) parts.push(String(p.title));
9742
+ return parts.join(" ");
9743
+ },
9744
+ displayFields: [
9745
+ { key: "teamId", label: "Team" },
9746
+ { key: "title", label: "Title" },
9747
+ { key: "description", label: "Description" },
9748
+ { key: "stateId", label: "State" },
9749
+ { key: "assigneeId", label: "Assignee" },
9750
+ { key: "priority", label: "Priority" },
9751
+ { key: "labelIds", label: "Labels" }
9752
+ ]
9753
+ },
9754
+ "linear.issue.update": {
9755
+ summaryTemplate: (p) => {
9756
+ const parts = [];
9757
+ if (p.issueId) parts.push(`${p.issueId}:`);
9758
+ if (p.title) parts.push(String(p.title));
9759
+ return parts.join(" ");
9760
+ },
9761
+ displayFields: [
9762
+ { key: "issueId", label: "Issue" },
9763
+ { key: "title", label: "Title" },
9764
+ { key: "description", label: "Description" },
9765
+ { key: "stateId", label: "State" },
9766
+ { key: "assigneeId", label: "Assignee" },
9767
+ { key: "priority", label: "Priority" },
9768
+ { key: "labelIds", label: "Labels" }
9769
+ ]
9770
+ },
9771
+ "linear.comment.create": {
9772
+ summaryTemplate: (p) => {
9773
+ const parts = [];
9774
+ if (p.issueId) parts.push(`${p.issueId}:`);
9775
+ if (p.body) parts.push(String(p.body));
9776
+ return parts.join(" ");
9777
+ },
9778
+ displayFields: [
9779
+ { key: "issueId", label: "Issue" },
9780
+ { key: "body", label: "Comment" }
9781
+ ]
9782
+ },
9783
+ "linear.issue.archive": {
9784
+ summaryTemplate: (p) => {
9785
+ const parts = [];
9786
+ if (p.issueId) parts.push(`${p.issueId}:`);
9787
+ parts.push("Archive");
9788
+ return parts.join(" ");
9789
+ },
9790
+ displayFields: [
9791
+ { key: "issueId", label: "Issue" }
9792
+ ]
9793
+ },
9794
+ "linear.label.list": {
9795
+ summaryTemplate: (p) => {
9796
+ const parts = [];
9797
+ if (p.teamId) parts.push(`${p.teamId}:`);
9798
+ parts.push("List labels");
9799
+ return parts.join(" ");
9800
+ },
9801
+ displayFields: [
9802
+ { key: "teamId", label: "Team" },
9803
+ { key: "limit", label: "Limit" }
9804
+ ]
9805
+ },
9806
+ "linear.user.list": {
9807
+ summaryTemplate: (p) => {
9808
+ const parts = [];
9809
+ if (p.teamId) parts.push(`${p.teamId}:`);
9810
+ parts.push("List users");
9811
+ return parts.join(" ");
9812
+ },
9813
+ displayFields: [
9814
+ { key: "teamId", label: "Team" },
9815
+ { key: "limit", label: "Limit" }
9816
+ ]
9817
+ },
9818
+ "linear.project.create": {
9819
+ summaryTemplate: (p) => {
9820
+ const parts = [];
9821
+ if (p.teamIds) parts.push(`${Array.isArray(p.teamIds) ? p.teamIds.join(",") : String(p.teamIds)}:`);
9822
+ if (p.name) parts.push(String(p.name));
9823
+ return parts.join(" ");
9824
+ },
9825
+ displayFields: [
9826
+ { key: "teamIds", label: "Teams" },
9827
+ { key: "name", label: "Name" },
9828
+ { key: "description", label: "Description" },
9829
+ { key: "statusId", label: "Status ID" },
9830
+ { key: "startDate", label: "Start Date" },
9831
+ { key: "targetDate", label: "Target Date" }
9832
+ ]
9833
+ },
9834
+ "linear.project.update": {
9835
+ summaryTemplate: (p) => {
9836
+ const parts = [];
9837
+ if (p.projectId) parts.push(`${p.projectId}:`);
9838
+ if (p.name) parts.push(String(p.name));
9839
+ return parts.join(" ");
9840
+ },
9841
+ displayFields: [
9842
+ { key: "projectId", label: "Project" },
9843
+ { key: "name", label: "Name" },
9844
+ { key: "description", label: "Description" },
9845
+ { key: "statusId", label: "Status ID" },
9846
+ { key: "startDate", label: "Start Date" },
9847
+ { key: "targetDate", label: "Target Date" }
9848
+ ]
9849
+ },
9850
+ // ─── Linear Comment ops ───
9851
+ "linear.comment.update": {
9852
+ summaryTemplate: (p) => {
9853
+ const parts = [];
9854
+ if (p.commentId) parts.push(`${p.commentId}:`);
9855
+ parts.push("Update comment");
9856
+ return parts.join(" ");
9857
+ },
9858
+ displayFields: [
9859
+ { key: "commentId", label: "Comment" },
9860
+ { key: "body", label: "Body" }
9861
+ ]
9862
+ },
9863
+ "linear.comment.delete": {
9864
+ summaryTemplate: (p) => {
9865
+ const parts = [];
9866
+ if (p.commentId) parts.push(`Delete comment ${p.commentId}`);
8441
9867
  return parts.join(" ");
8442
9868
  },
8443
9869
  displayFields: [
8444
- { key: "channel", label: "Channel" },
8445
- { key: "text", label: "Message" }
9870
+ { key: "commentId", label: "Comment" }
8446
9871
  ]
8447
9872
  },
8448
- "gmail.message.send": {
9873
+ "linear.comment.resolve": {
8449
9874
  summaryTemplate: (p) => {
8450
9875
  const parts = [];
8451
- if (p.to) parts.push(`To: ${p.to}`);
8452
- if (p.subject) parts.push(`Subject: ${p.subject}`);
8453
- return parts.join(", ");
9876
+ if (p.commentId) parts.push(`${p.commentId}:`);
9877
+ parts.push("Resolve comment");
9878
+ return parts.join(" ");
8454
9879
  },
8455
9880
  displayFields: [
8456
- { key: "to", label: "To" },
8457
- { key: "subject", label: "Subject" },
8458
- { key: "body", label: "Body" }
9881
+ { key: "commentId", label: "Comment" }
8459
9882
  ]
8460
9883
  },
8461
- "gmail.draft.create": {
9884
+ "linear.comment.unresolve": {
8462
9885
  summaryTemplate: (p) => {
8463
9886
  const parts = [];
8464
- if (p.to) parts.push(`To: ${p.to}`);
8465
- if (p.subject) parts.push(`Subject: ${p.subject}`);
8466
- return parts.join(", ");
9887
+ if (p.commentId) parts.push(`${p.commentId}:`);
9888
+ parts.push("Unresolve comment");
9889
+ return parts.join(" ");
8467
9890
  },
8468
9891
  displayFields: [
8469
- { key: "to", label: "To" },
8470
- { key: "subject", label: "Subject" },
8471
- { key: "body", label: "Body" }
9892
+ { key: "commentId", label: "Comment" }
8472
9893
  ]
8473
9894
  },
8474
- "calendar.event.create": {
9895
+ // ─── Linear Issue ops ───
9896
+ "linear.issue.unarchive": {
8475
9897
  summaryTemplate: (p) => {
8476
9898
  const parts = [];
8477
- if (p.summary) parts.push(p.summary);
8478
- if (p.start) parts.push(`(${formatCalendarTime(p.start)})`);
9899
+ if (p.issueId) parts.push(`${p.issueId}:`);
9900
+ parts.push("Unarchive");
8479
9901
  return parts.join(" ");
8480
9902
  },
8481
9903
  displayFields: [
8482
- { key: "summary", label: "Event" },
8483
- { key: "start", label: "Start" },
8484
- { key: "end", label: "End" },
8485
- { key: "attendees", label: "Attendees" }
9904
+ { key: "issueId", label: "Issue" }
8486
9905
  ]
8487
9906
  },
8488
- "calendar.event.update": {
9907
+ "linear.issue.addLabel": {
8489
9908
  summaryTemplate: (p) => {
8490
9909
  const parts = [];
8491
- if (p.summary) parts.push(p.summary);
8492
- if (p.start) parts.push(`(${formatCalendarTime(p.start)})`);
9910
+ if (p.issueId) parts.push(`${p.issueId}:`);
9911
+ if (p.labelId) parts.push(`Add label ${p.labelId}`);
8493
9912
  return parts.join(" ");
8494
9913
  },
8495
9914
  displayFields: [
8496
- { key: "summary", label: "Event" },
8497
- { key: "start", label: "Start" },
8498
- { key: "end", label: "End" },
8499
- { key: "attendees", label: "Attendees" }
9915
+ { key: "issueId", label: "Issue" },
9916
+ { key: "labelId", label: "Label" }
8500
9917
  ]
8501
9918
  },
8502
- "jira.issue.create": {
9919
+ "linear.issue.removeLabel": {
8503
9920
  summaryTemplate: (p) => {
8504
9921
  const parts = [];
8505
- const projectKey = jiraField(
8506
- p,
8507
- ["projectKey", "project"],
8508
- "project",
8509
- (v) => typeof v === "string" ? v : v?.key
8510
- );
8511
- const summary = jiraField(p, ["summary"], "summary");
8512
- if (projectKey) parts.push(`${projectKey}:`);
8513
- if (summary) parts.push(summary);
9922
+ if (p.issueId) parts.push(`${p.issueId}:`);
9923
+ if (p.labelId) parts.push(`Remove label ${p.labelId}`);
8514
9924
  return parts.join(" ");
8515
9925
  },
8516
- // AIDENTITY-54: nested `fields.X` 形式と top-level canonical の両方を
8517
- // 拾えるよう extract を使う。assignee は null (unassign) も表示。
8518
- // legacy alias (project / issuetype 等) も top-level 候補に含めて後方互換を保つ。
8519
9926
  displayFields: [
8520
- {
8521
- label: "Project",
8522
- extract: (p) => jiraField(
8523
- p,
8524
- ["projectKey", "project"],
8525
- "project",
8526
- (v) => typeof v === "string" ? v : v?.key
8527
- )
8528
- },
8529
- {
8530
- label: "Type",
8531
- extract: (p) => jiraField(
8532
- p,
8533
- ["issueTypeName", "issueType", "issuetype"],
8534
- "issuetype",
8535
- (v) => typeof v === "string" ? v : v?.name
8536
- )
8537
- },
8538
- { label: "Summary", extract: (p) => jiraField(p, ["summary"], "summary") },
8539
- { label: "Description", extract: (p) => jiraField(p, ["description"], "description") },
8540
- {
8541
- label: "Priority",
8542
- extract: (p) => jiraField(
8543
- p,
8544
- ["priority"],
8545
- "priority",
8546
- (v) => typeof v === "string" ? v : v?.name
8547
- )
8548
- },
8549
- { label: "Assignee", extract: extractJiraAssigneeDisplay },
8550
- { label: "Labels", extract: (p) => jiraField(p, ["labels"], "labels") }
9927
+ { key: "issueId", label: "Issue" },
9928
+ { key: "labelId", label: "Label" }
8551
9929
  ]
8552
9930
  },
8553
- "jira.issue.update": {
9931
+ "linear.issue.subscribe": {
8554
9932
  summaryTemplate: (p) => {
8555
9933
  const parts = [];
8556
- const key = p.issueIdOrKey ?? p.issueKey;
8557
- const summary = jiraField(p, ["summary"], "summary");
8558
- if (key) parts.push(`${key}:`);
8559
- if (summary) parts.push(summary);
9934
+ if (p.issueId) parts.push(`${p.issueId}:`);
9935
+ parts.push("Subscribe");
8560
9936
  return parts.join(" ");
8561
9937
  },
8562
9938
  displayFields: [
8563
- // canonical issueIdOrKey、agent issueKey で送ってくる旧仕様も拾う。
8564
- { label: "Issue", extract: (p) => p.issueIdOrKey ?? p.issueKey },
8565
- { label: "Summary", extract: (p) => jiraField(p, ["summary"], "summary") },
8566
- { label: "Description", extract: (p) => jiraField(p, ["description"], "description") },
8567
- {
8568
- label: "Priority",
8569
- extract: (p) => jiraField(
8570
- p,
8571
- ["priority"],
8572
- "priority",
8573
- (v) => typeof v === "string" ? v : v?.name
8574
- )
8575
- },
8576
- // AIDENTITY-54: top-level alias (string / object) と null (unassign) も解決。
8577
- { label: "Assignee", extract: extractJiraAssigneeDisplay },
8578
- { label: "Labels", extract: (p) => jiraField(p, ["labels"], "labels") }
9939
+ { key: "issueId", label: "Issue" }
8579
9940
  ]
8580
9941
  },
8581
- // AIDENTITY-65: comment 本体は string と ADF document の両方を受けるため、
8582
- // detail 表示の ADF 描画は formatValueFull 側に任せて key 指定で OK。
8583
- "jira.comment.create": {
9942
+ "linear.issue.delete": {
8584
9943
  summaryTemplate: (p) => {
8585
9944
  const parts = [];
8586
- if (p.issueIdOrKey) parts.push(`${p.issueIdOrKey}:`);
8587
- if (p.body) parts.push(typeof p.body === "string" ? p.body : "[ADF]");
9945
+ if (p.issueId) parts.push(`Delete issue ${p.issueId}`);
8588
9946
  return parts.join(" ");
8589
9947
  },
8590
9948
  displayFields: [
8591
- { key: "issueIdOrKey", label: "Issue" },
8592
- { key: "body", label: "Comment" }
9949
+ { key: "issueId", label: "Issue" }
8593
9950
  ]
8594
9951
  },
8595
- // AIDENTITY-66: 破壊的操作なので「どの issue のどの comment を消すか」を明示する
8596
- // (jira.issue.delete / jira.issuelink.delete と同じ destructive 表現の方針)。
8597
- "jira.comment.delete": {
9952
+ // ─── Linear Issue Relations ───
9953
+ "linear.issueRelation.create": {
8598
9954
  summaryTemplate: (p) => {
8599
- const issue = p.issueIdOrKey ?? p.issueKey;
8600
- const commentId = p.commentId ?? p.id;
8601
- if (issue && commentId) return `Delete comment ${commentId} on ${issue}`;
8602
- if (commentId) return `Delete comment ${commentId}`;
8603
- return "";
9955
+ const parts = [];
9956
+ if (p.issueId) parts.push(`${p.issueId}`);
9957
+ if (p.type) parts.push(String(p.type));
9958
+ if (p.relatedIssueId) parts.push(String(p.relatedIssueId));
9959
+ return parts.join(" ");
8604
9960
  },
8605
9961
  displayFields: [
8606
- { label: "Issue", extract: (p) => p.issueIdOrKey ?? p.issueKey },
8607
- { label: "Comment", extract: (p) => p.commentId ?? p.id }
9962
+ { key: "issueId", label: "Issue" },
9963
+ { key: "type", label: "Relation Type" },
9964
+ { key: "relatedIssueId", label: "Related Issue" }
8608
9965
  ]
8609
9966
  },
8610
- // AIDENTITY-65: API enricher が 'Link' label を upsert で書き換える。
8611
- "jira.issuelink.delete": {
9967
+ "linear.issueRelation.list": {
8612
9968
  summaryTemplate: (p) => {
8613
9969
  const parts = [];
8614
- if (p.linkId) parts.push(`Delete link ${p.linkId}`);
9970
+ if (p.issueId) parts.push(`${p.issueId}:`);
9971
+ parts.push("List relations");
8615
9972
  return parts.join(" ");
8616
9973
  },
8617
9974
  displayFields: [
8618
- { key: "linkId", label: "Link" }
9975
+ { key: "issueId", label: "Issue" }
9976
+ ]
9977
+ },
9978
+ "linear.issueRelation.delete": {
9979
+ summaryTemplate: (p) => {
9980
+ const parts = [];
9981
+ if (p.relationId) parts.push(`Delete relation ${p.relationId}`);
9982
+ return parts.join(" ");
9983
+ },
9984
+ displayFields: [
9985
+ { key: "relationId", label: "Relation" }
9986
+ ]
9987
+ },
9988
+ // ─── Linear Cycles ───
9989
+ "linear.cycle.list": {
9990
+ summaryTemplate: (p) => {
9991
+ const parts = [];
9992
+ if (p.teamId) parts.push(`${p.teamId}:`);
9993
+ parts.push("List cycles");
9994
+ return parts.join(" ");
9995
+ },
9996
+ displayFields: [
9997
+ { key: "teamId", label: "Team" },
9998
+ { key: "limit", label: "Limit" }
9999
+ ]
10000
+ },
10001
+ "linear.cycle.read": {
10002
+ summaryTemplate: (p) => {
10003
+ const parts = [];
10004
+ if (p.cycleId) parts.push(`${p.cycleId}:`);
10005
+ parts.push("Read cycle");
10006
+ return parts.join(" ");
10007
+ },
10008
+ displayFields: [
10009
+ { key: "cycleId", label: "Cycle" }
10010
+ ]
10011
+ },
10012
+ "linear.cycle.create": {
10013
+ summaryTemplate: (p) => {
10014
+ const parts = [];
10015
+ if (p.teamId) parts.push(`${p.teamId}:`);
10016
+ if (p.name) parts.push(String(p.name));
10017
+ else if (p.startsAt) parts.push(`Cycle ${p.startsAt}`);
10018
+ return parts.join(" ");
10019
+ },
10020
+ displayFields: [
10021
+ { key: "teamId", label: "Team" },
10022
+ { key: "name", label: "Name" },
10023
+ { key: "startsAt", label: "Starts At" },
10024
+ { key: "endsAt", label: "Ends At" }
10025
+ ]
10026
+ },
10027
+ "linear.cycle.update": {
10028
+ summaryTemplate: (p) => {
10029
+ const parts = [];
10030
+ if (p.cycleId) parts.push(`${p.cycleId}:`);
10031
+ if (p.name) parts.push(String(p.name));
10032
+ else parts.push("Update cycle");
10033
+ return parts.join(" ");
10034
+ },
10035
+ displayFields: [
10036
+ { key: "cycleId", label: "Cycle" },
10037
+ { key: "name", label: "Name" },
10038
+ { key: "startsAt", label: "Starts At" },
10039
+ { key: "endsAt", label: "Ends At" }
10040
+ ]
10041
+ },
10042
+ // ─── Linear Labels ───
10043
+ "linear.label.create": {
10044
+ summaryTemplate: (p) => {
10045
+ const parts = [];
10046
+ if (p.name) parts.push(String(p.name));
10047
+ return parts.join(" ");
10048
+ },
10049
+ displayFields: [
10050
+ { key: "name", label: "Name" },
10051
+ { key: "color", label: "Color" },
10052
+ { key: "teamId", label: "Team" }
10053
+ ]
10054
+ },
10055
+ "linear.label.update": {
10056
+ summaryTemplate: (p) => {
10057
+ const parts = [];
10058
+ if (p.labelId) parts.push(`${p.labelId}:`);
10059
+ if (p.name) parts.push(String(p.name));
10060
+ else parts.push("Update label");
10061
+ return parts.join(" ");
10062
+ },
10063
+ displayFields: [
10064
+ { key: "labelId", label: "Label" },
10065
+ { key: "name", label: "Name" },
10066
+ { key: "color", label: "Color" }
10067
+ ]
10068
+ },
10069
+ // ─── Linear Attachments ───
10070
+ "linear.attachment.create": {
10071
+ summaryTemplate: (p) => {
10072
+ const parts = [];
10073
+ if (p.issueId) parts.push(`${p.issueId}:`);
10074
+ if (p.title) parts.push(String(p.title));
10075
+ return parts.join(" ");
10076
+ },
10077
+ displayFields: [
10078
+ { key: "issueId", label: "Issue" },
10079
+ { key: "title", label: "Title" },
10080
+ { key: "url", label: "URL" }
10081
+ ]
10082
+ },
10083
+ "linear.attachment.list": {
10084
+ summaryTemplate: (p) => {
10085
+ const parts = [];
10086
+ if (p.issueId) parts.push(`${p.issueId}:`);
10087
+ parts.push("List attachments");
10088
+ return parts.join(" ");
10089
+ },
10090
+ displayFields: [
10091
+ { key: "issueId", label: "Issue" }
10092
+ ]
10093
+ },
10094
+ "linear.attachment.delete": {
10095
+ summaryTemplate: (p) => {
10096
+ const parts = [];
10097
+ if (p.attachmentId) parts.push(`Delete attachment ${p.attachmentId}`);
10098
+ return parts.join(" ");
10099
+ },
10100
+ displayFields: [
10101
+ { key: "attachmentId", label: "Attachment" }
10102
+ ]
10103
+ },
10104
+ // ─── Linear read actions (登録漏れ補完) ───
10105
+ "linear.issue.list": {
10106
+ summaryTemplate: (p) => {
10107
+ const parts = [];
10108
+ if (p.teamId) parts.push(`${p.teamId}:`);
10109
+ parts.push("List issues");
10110
+ return parts.join(" ");
10111
+ },
10112
+ displayFields: [
10113
+ { key: "teamId", label: "Team" },
10114
+ { key: "assigneeId", label: "Assignee" },
10115
+ { key: "stateId", label: "State" },
10116
+ { key: "limit", label: "Limit" }
10117
+ ]
10118
+ },
10119
+ "linear.issue.read": {
10120
+ summaryTemplate: (p) => {
10121
+ const parts = [];
10122
+ if (p.issueId) parts.push(`${p.issueId}:`);
10123
+ parts.push("Read issue");
10124
+ return parts.join(" ");
10125
+ },
10126
+ displayFields: [
10127
+ { key: "issueId", label: "Issue" }
10128
+ ]
10129
+ },
10130
+ "linear.issue.search": {
10131
+ summaryTemplate: (p) => {
10132
+ const parts = [];
10133
+ if (p.teamId) parts.push(`${p.teamId}:`);
10134
+ if (p.query) parts.push(String(p.query));
10135
+ return parts.join(" ");
10136
+ },
10137
+ displayFields: [
10138
+ { key: "query", label: "Query" },
10139
+ { key: "teamId", label: "Team" },
10140
+ { key: "limit", label: "Limit" }
10141
+ ]
10142
+ },
10143
+ "linear.comment.list": {
10144
+ summaryTemplate: (p) => {
10145
+ const parts = [];
10146
+ if (p.issueId) parts.push(`${p.issueId}:`);
10147
+ parts.push("List comments");
10148
+ return parts.join(" ");
10149
+ },
10150
+ displayFields: [
10151
+ { key: "issueId", label: "Issue" }
10152
+ ]
10153
+ },
10154
+ "linear.project.list": {
10155
+ summaryTemplate: (p) => {
10156
+ const parts = [];
10157
+ if (p.teamId) parts.push(`${p.teamId}:`);
10158
+ parts.push("List projects");
10159
+ return parts.join(" ");
10160
+ },
10161
+ displayFields: [
10162
+ { key: "teamId", label: "Team" },
10163
+ { key: "limit", label: "Limit" }
10164
+ ]
10165
+ },
10166
+ "linear.project.read": {
10167
+ summaryTemplate: (p) => {
10168
+ const parts = [];
10169
+ if (p.projectId) parts.push(`${p.projectId}:`);
10170
+ parts.push("Read project");
10171
+ return parts.join(" ");
10172
+ },
10173
+ displayFields: [
10174
+ { key: "projectId", label: "Project" }
10175
+ ]
10176
+ },
10177
+ "linear.team.list": {
10178
+ summaryTemplate: (_p) => "List teams",
10179
+ displayFields: [
10180
+ { key: "limit", label: "Limit" }
10181
+ ]
10182
+ },
10183
+ "linear.workflowState.list": {
10184
+ summaryTemplate: (p) => {
10185
+ const parts = [];
10186
+ if (p.teamId) parts.push(`${p.teamId}:`);
10187
+ parts.push("List workflow states");
10188
+ return parts.join(" ");
10189
+ },
10190
+ displayFields: [
10191
+ { key: "teamId", label: "Team" },
10192
+ { key: "limit", label: "Limit" }
8619
10193
  ]
8620
10194
  },
10195
+ "linear.viewer.read": {
10196
+ summaryTemplate: (_p) => "Read viewer (current user)",
10197
+ displayFields: []
10198
+ },
8621
10199
  // AIDENTITY-83: email / displayName から accountId を解決する read action。
8622
10200
  "jira.user.search": {
8623
10201
  summaryTemplate: (p) => {
@@ -8640,7 +10218,8 @@ var ACTION_DISPLAY_CONFIGS = {
8640
10218
  displayFields: [
8641
10219
  { key: "to", label: "To" },
8642
10220
  { key: "taskType", label: "Task" },
8643
- { key: "message", label: "Message" }
10221
+ { key: "message", label: "Message" },
10222
+ { key: "payload", label: "Payload" }
8644
10223
  ]
8645
10224
  },
8646
10225
  "inbox.respond": {
@@ -8668,15 +10247,25 @@ var ACTION_DISPLAY_CONFIGS = {
8668
10247
  ]
8669
10248
  },
8670
10249
  "inbox.checkByToken": {
8671
- summaryTemplate: (p) => p.token ? `Token: ${p.token}` : "",
8672
- displayFields: [
8673
- { key: "token", label: "Token" }
8674
- ]
10250
+ // token is an opaque access credential never render it in summaries or display fields.
10251
+ summaryTemplate: (_p) => "Check inbox by token",
10252
+ displayFields: []
8675
10253
  },
8676
10254
  "inbox.complete": {
8677
10255
  summaryTemplate: (p) => p.id ? `Complete #${p.id}` : "",
8678
10256
  displayFields: [
8679
- { key: "id", label: "Item" }
10257
+ { key: "id", label: "Item" },
10258
+ { key: "result", label: "Result" }
10259
+ ]
10260
+ },
10261
+ "scheduling.request": {
10262
+ summaryTemplate: (p) => p.topic ? `Request scheduling: ${p.topic}` : "Request scheduling",
10263
+ displayFields: [
10264
+ { key: "to", label: "To" },
10265
+ { key: "topic", label: "Topic" },
10266
+ { key: "durationMinutes", label: "Duration (min)" },
10267
+ { key: "candidates", label: "Candidates" },
10268
+ { key: "message", label: "Message" }
8680
10269
  ]
8681
10270
  }
8682
10271
  };
@@ -8984,7 +10573,7 @@ function isWriteAction(action) {
8984
10573
  if (!meta) {
8985
10574
  return true;
8986
10575
  }
8987
- const writeEffectPrefixes = ["Create:", "Update:", "Delete:", "Write:", "Execute:", "Merge:", "Run:"];
10576
+ const writeEffectPrefixes = ["Create:", "Update:", "Delete:", "Write:", "Execute:", "Merge:", "Run:", "Archive:"];
8988
10577
  if (meta.effects?.some((e) => writeEffectPrefixes.some((p) => e.startsWith(p)))) {
8989
10578
  return true;
8990
10579
  }