@vess-id/ai-identity 0.16.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) {
@@ -6531,6 +6531,33 @@ var ACTION_REGISTRY = {
6531
6531
  },
6532
6532
  version: "1.0.0"
6533
6533
  },
6534
+ {
6535
+ action: "calendar.freebusy",
6536
+ resource_type: "calendar:calendar",
6537
+ required_relations: ["viewer", "editor", "admin", "owner"],
6538
+ required_scopes: ["https://www.googleapis.com/auth/calendar.readonly"],
6539
+ capability: "calendar.read.basic",
6540
+ // Availability probe used to check a calendar's busy/free intervals before
6541
+ // proposing meeting slots. Returns only busy time ranges — never event
6542
+ // details (title, attendees, description) — so it stays low-risk read.
6543
+ input_schema: {
6544
+ type: "object",
6545
+ properties: {
6546
+ calendarId: { type: "string", description: "Calendar ID (email address). Defaults to primary calendar." },
6547
+ timeMin: { type: "string", description: 'Lower bound (inclusive) of the window to check, as ISO 8601 datetime, e.g. "2025-01-15T00:00:00Z"' },
6548
+ timeMax: { type: "string", description: 'Upper bound (exclusive) of the window to check, as ISO 8601 datetime, e.g. "2025-01-16T00:00:00Z"' }
6549
+ },
6550
+ required: ["timeMin", "timeMax"],
6551
+ additionalProperties: false
6552
+ },
6553
+ constraints: { rate_bucket: "calendar.read" },
6554
+ effects: ["Read:FreeBusy"],
6555
+ risk: "low",
6556
+ target_bindings: {
6557
+ resource_id: { source: "param", param: "calendarId", required: false, default: "primary" }
6558
+ },
6559
+ version: "1.0.0"
6560
+ },
6534
6561
  {
6535
6562
  action: "calendar.event.create",
6536
6563
  resource_type: "calendar:event",
@@ -7723,449 +7750,1478 @@ var ACTION_REGISTRY = {
7723
7750
  target_bindings: { resource_id: { source: "param", param: "portalId" } },
7724
7751
  version: "1.0.0"
7725
7752
  },
7726
- // ─── Agent Inbox Actions (internal) ───
7727
- // Inbox actions back the Agent Inbox MCP tools (task delegation between
7728
- // agents/people). They are internal (no external OAuth provider), so they
7729
- // carry a single nominal base scope `inbox` to satisfy the registry
7730
- // meta-schema's `minItems: 1` (same pattern as hubspot.account.link.get).
7753
+ // ─── Linear Actions ───
7731
7754
  {
7732
- action: "inbox.send",
7733
- resource_type: "inbox:item",
7734
- required_relations: ["editor", "act_as"],
7735
- required_scopes: ["inbox"],
7736
- 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",
7737
7760
  input_schema: {
7738
7761
  type: "object",
7739
7762
  properties: {
7740
- to: { type: "string", minLength: 1, description: "Recipient (user id / handle) the task request is sent to" },
7741
- taskType: { type: "string", minLength: 1, description: "Type of task being requested" },
7742
- payload: { type: "object", description: "Task-specific payload data" },
7743
- 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)" }
7744
7769
  },
7745
- required: ["to", "taskType", "payload"],
7746
7770
  additionalProperties: false
7747
7771
  },
7748
- constraints: { rate_bucket: "inbox.write" },
7749
- effects: ["Create:InboxItem"],
7750
- risk: "high",
7772
+ constraints: { rate_bucket: "linear.read" },
7773
+ effects: ["Read:IssueList"],
7774
+ risk: "low",
7751
7775
  target_bindings: {
7752
- resource_id: { source: "param", param: "to" }
7776
+ resource_id: { source: "param", param: "teamId", required: false }
7753
7777
  },
7754
7778
  version: "1.0.0"
7755
7779
  },
7756
7780
  {
7757
- action: "inbox.respond",
7758
- resource_type: "inbox:item",
7759
- required_relations: ["editor", "act_as"],
7760
- required_scopes: ["inbox"],
7761
- 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",
7762
7786
  input_schema: {
7763
7787
  type: "object",
7764
7788
  properties: {
7765
- id: { type: "string", minLength: 1, description: "Inbox item id being responded to" },
7766
- action: { type: "string", enum: ["accept", "decline", "counter"], description: "Response action" },
7767
- 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)" }
7768
7790
  },
7769
- required: ["id", "action"],
7791
+ required: ["issueId"],
7770
7792
  additionalProperties: false
7771
7793
  },
7772
- constraints: { rate_bucket: "inbox.write" },
7773
- effects: ["Update:InboxItem"],
7774
- // high (not medium): an agent-mediated response (MCP invoke) must always
7775
- // go through human approval — the Phase 1 "always confirm" guarantee made
7776
- // enforceable. target_bindings below binds the concrete inbox item id so
7777
- // the high-risk approval has a specific resource constraint (the public
7778
- // /scheduling/:token link flow does NOT go through this gate — it calls
7779
- // InboxService.respond directly, system-key-signed).
7780
- risk: "high",
7794
+ constraints: { rate_bucket: "linear.read" },
7795
+ effects: ["Read:Issue"],
7796
+ risk: "low",
7781
7797
  target_bindings: {
7782
- resource_id: { source: "param", param: "id" }
7798
+ resource_id: { source: "param", param: "issueId" }
7783
7799
  },
7784
7800
  version: "1.0.0"
7785
7801
  },
7786
7802
  {
7787
- action: "inbox.check",
7788
- resource_type: "inbox:item",
7803
+ action: "linear.issue.search",
7804
+ resource_type: "linear:issue",
7789
7805
  required_relations: ["viewer", "editor", "admin", "owner"],
7790
- required_scopes: ["inbox"],
7791
- capability: "inbox.read",
7806
+ required_scopes: ["read"],
7807
+ capability: "linear.read.basic",
7792
7808
  input_schema: {
7793
7809
  type: "object",
7794
7810
  properties: {
7795
- types: { type: "array", items: { type: "string" }, description: "Filter by task types" },
7796
- 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)" }
7797
7814
  },
7815
+ required: ["query"],
7798
7816
  additionalProperties: false
7799
7817
  },
7800
- constraints: { rate_bucket: "inbox.read" },
7801
- effects: ["Read:InboxItem"],
7818
+ constraints: { rate_bucket: "linear.read" },
7819
+ effects: ["Read:IssueList"],
7802
7820
  risk: "low",
7803
7821
  target_bindings: {
7804
- resource_id: { source: "param", param: "id", required: false }
7822
+ resource_id: { source: "param", param: "teamId", required: false }
7805
7823
  },
7806
7824
  version: "1.0.0"
7807
7825
  },
7808
7826
  {
7809
- action: "inbox.checkByToken",
7810
- resource_type: "inbox:item",
7811
- required_relations: ["viewer", "editor", "admin", "owner"],
7812
- required_scopes: ["inbox"],
7813
- 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",
7814
7832
  input_schema: {
7815
7833
  type: "object",
7816
7834
  properties: {
7817
- 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" }
7818
7842
  },
7819
- required: ["token"],
7843
+ required: ["teamId", "title"],
7820
7844
  additionalProperties: false
7821
7845
  },
7822
- constraints: { rate_bucket: "inbox.read" },
7823
- effects: ["Read:InboxItem"],
7824
- risk: "low",
7846
+ constraints: { rate_bucket: "linear.write" },
7847
+ effects: ["Create:Issue"],
7848
+ risk: "high",
7825
7849
  target_bindings: {
7826
- resource_id: { source: "param", param: "token" }
7850
+ resource_id: { source: "param", param: "teamId" }
7827
7851
  },
7828
7852
  version: "1.0.0"
7829
7853
  },
7830
7854
  {
7831
- action: "inbox.complete",
7832
- resource_type: "inbox:item",
7855
+ action: "linear.issue.update",
7856
+ resource_type: "linear:issue",
7833
7857
  required_relations: ["editor", "act_as"],
7834
- required_scopes: ["inbox"],
7835
- capability: "inbox.write",
7858
+ required_scopes: ["write"],
7859
+ capability: "linear.write.basic",
7836
7860
  input_schema: {
7837
7861
  type: "object",
7838
7862
  properties: {
7839
- id: { type: "string", minLength: 1, description: "Inbox item id being completed" },
7840
- 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" }
7841
7870
  },
7842
- required: ["id", "result"],
7871
+ required: ["issueId"],
7843
7872
  additionalProperties: false
7844
7873
  },
7845
- constraints: { rate_bucket: "inbox.write" },
7846
- effects: ["Update:InboxItem"],
7847
- risk: "low",
7874
+ constraints: { rate_bucket: "linear.write" },
7875
+ effects: ["Update:Issue"],
7876
+ risk: "high",
7848
7877
  target_bindings: {
7849
- resource_id: { source: "param", param: "id" }
7878
+ resource_id: { source: "param", param: "issueId" }
7850
7879
  },
7851
7880
  version: "1.0.0"
7852
7881
  },
7853
- // ─── Scheduling Actions (internal) ───
7854
- // scheduling.request is a meeting-time negotiation façade over inbox.send.
7855
- // Candidate slots are computed LLM-side from the user calendar; the server
7856
- // only validates them. Like the inbox actions it is internal (no external
7857
- // OAuth provider), so it carries the single nominal base scope `inbox`.
7858
- // Spec: docs/specs/2026-06-10-inbox-intent-routing-design.md §2.1
7859
7882
  {
7860
- action: "scheduling.request",
7861
- resource_type: "inbox:item",
7883
+ action: "linear.comment.create",
7884
+ resource_type: "linear:comment",
7862
7885
  required_relations: ["editor", "act_as"],
7863
- required_scopes: ["inbox"],
7864
- capability: "inbox.write",
7886
+ required_scopes: ["comments:create"],
7887
+ capability: "linear.write.basic",
7865
7888
  input_schema: {
7866
7889
  type: "object",
7867
7890
  properties: {
7868
- to: { type: "string", minLength: 1, description: "Counterpart (user id / email) to negotiate a meeting time with" },
7869
- topic: { type: "string", minLength: 1, description: "Meeting topic shown to the counterpart" },
7870
- durationMinutes: { type: "integer", minimum: 5, maximum: 480, description: "Meeting length in minutes" },
7871
- candidates: {
7872
- type: "array",
7873
- minItems: 1,
7874
- maxItems: 10,
7875
- description: "Candidate slots computed by the agent from the user calendar (LLM-side computation; the server only validates)",
7876
- items: {
7877
- type: "object",
7878
- properties: {
7879
- start: { type: "string", description: "ISO 8601 start" },
7880
- end: { type: "string", description: "ISO 8601 end" }
7881
- },
7882
- required: ["start", "end"],
7883
- additionalProperties: false
7884
- }
7885
- },
7886
- 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)" }
7887
7893
  },
7888
- required: ["to", "topic", "durationMinutes", "candidates"],
7894
+ required: ["issueId", "body"],
7889
7895
  additionalProperties: false
7890
7896
  },
7891
- constraints: { rate_bucket: "inbox.write" },
7892
- effects: ["Create:InboxItem"],
7897
+ constraints: { rate_bucket: "linear.write" },
7898
+ effects: ["Create:Comment"],
7893
7899
  risk: "high",
7894
7900
  target_bindings: {
7895
- resource_id: { source: "param", param: "to" }
7901
+ resource_id: { source: "param", param: "issueId" }
7896
7902
  },
7897
7903
  version: "1.0.0"
7898
- }
7899
- ],
7900
- capabilities: [
7901
- {
7902
- capability: "slack.messaging.basic",
7903
- description: "Post, update, and delete messages in channels",
7904
- includes: ["slack.message.post", "slack.message.update", "slack.message.delete"],
7905
- version: "1.0.0"
7906
7904
  },
7907
7905
  {
7908
- capability: "slack.read.basic",
7909
- description: "Read channels, messages, and user info",
7910
- includes: ["slack.channel.read", "slack.user.read", "slack.message.read", "slack.message.read_paginated", "slack.batch.read"],
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
+ },
7911
7926
  version: "1.0.0"
7912
7927
  },
7913
7928
  {
7914
- capability: "github.read.basic",
7915
- description: "Read issues, pull requests and repository contents from repositories",
7916
- 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"],
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
+ },
7917
7948
  version: "1.0.0"
7918
7949
  },
7919
7950
  {
7920
- capability: "github.issues.triage",
7921
- description: "Create and update issues, post issue comments, manage sub-issues and labels",
7922
- includes: ["github.issue.create", "github.issue.update", "github.issue.comment.create", "github.issue.subissue.write", "github.label.write"],
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
+ },
7923
7970
  version: "1.0.0"
7924
7971
  },
7925
7972
  {
7926
- capability: "github.pulls.write",
7927
- description: "Create, update, merge, and review pull requests",
7928
- includes: ["github.pr.create", "github.pr.update", "github.pr.merge", "github.pr.review.create", "github.pr.comment.reply", "github.pr.branch.update"],
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
+ },
7929
7994
  version: "1.0.0"
7930
7995
  },
7931
7996
  {
7932
- capability: "github.repos.write",
7933
- 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",
7934
- 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"],
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
+ },
7935
8016
  version: "1.0.0"
7936
8017
  },
7937
8018
  {
7938
- capability: "github.notifications.write",
7939
- description: "\u901A\u77E5\u306E\u65E2\u8AAD\u5316\u30FB\u30B9\u30EC\u30C3\u30C9/\u30EA\u30DD\u30B8\u30C8\u30EA\u306E\u8CFC\u8AAD\u8A2D\u5B9A",
7940
- includes: ["github.notification.markRead", "github.notification.markAllRead", "github.notification.subscription.set", "github.notification.repoSubscription.set"],
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
+ },
7941
8038
  version: "1.0.0"
7942
8039
  },
7943
8040
  {
7944
- capability: "github.gists.write",
7945
- description: "Gist \u306E\u4F5C\u6210\u30FB\u66F4\u65B0",
7946
- includes: ["github.gist.create", "github.gist.update"],
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
+ },
7947
8060
  version: "1.0.0"
7948
8061
  },
7949
8062
  {
7950
- capability: "gmail.read.basic",
7951
- description: "Read and search Gmail messages and labels",
7952
- includes: ["gmail.message.search", "gmail.message.read", "gmail.label.read", "gmail.batch.read"],
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
+ },
7953
8082
  version: "1.0.0"
7954
8083
  },
7955
8084
  {
7956
- capability: "gmail.compose",
7957
- description: "Send emails and create drafts via Gmail",
7958
- includes: ["gmail.message.send", "gmail.draft.create"],
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
+ },
7959
8104
  version: "1.0.0"
7960
8105
  },
7961
8106
  {
7962
- capability: "gmail.manage",
7963
- description: "Trash and permanently delete Gmail messages",
7964
- includes: ["gmail.message.trash", "gmail.message.delete"],
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
+ },
7965
8139
  version: "1.0.0"
7966
8140
  },
7967
8141
  {
7968
- capability: "calendar.read.basic",
7969
- description: "Read and list Google Calendar events",
7970
- includes: ["calendar.event.list", "calendar.event.read"],
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
+ },
7971
8166
  version: "1.0.0"
7972
8167
  },
8168
+ // ─── Linear Comment ops ───
7973
8169
  {
7974
- capability: "calendar.write",
7975
- description: "Create, update, and delete Google Calendar events",
7976
- includes: ["calendar.event.create", "calendar.event.update", "calendar.event.delete"],
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
+ },
7977
8190
  version: "1.0.0"
7978
8191
  },
7979
8192
  {
7980
- capability: "jira.read.basic",
7981
- description: "Read Jira issues, projects, boards, sprints, issue link types, and users",
7982
- 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"],
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
+ },
7983
8212
  version: "1.0.0"
7984
8213
  },
7985
8214
  {
7986
- capability: "jira.write.basic",
7987
- description: "Create, update, delete Jira issues, manage issue links, and add/delete comments",
7988
- 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"],
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
+ },
7989
8234
  version: "1.0.0"
7990
8235
  },
7991
8236
  {
7992
- capability: "inbox.write",
7993
- description: "Send and respond to agent inbox tasks",
7994
- includes: ["inbox.send", "inbox.respond", "inbox.complete", "scheduling.request"],
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
+ },
7995
8256
  version: "1.0.0"
7996
8257
  },
8258
+ // ─── Linear Issue ops ───
7997
8259
  {
7998
- capability: "inbox.read",
7999
- description: "Read agent inbox tasks",
8000
- includes: ["inbox.check", "inbox.checkByToken"],
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
+ },
8001
8279
  version: "1.0.0"
8002
- }
8003
- ]
8004
- };
8005
-
8006
- // src/registry/resource-type-labels.ts
8007
- var RESOURCE_TYPE_LABELS = {
8008
- "github:repo": "\u5BFE\u8C61\u30EA\u30DD\u30B8\u30C8\u30EA",
8009
- "github:org": "\u5BFE\u8C61\u7D44\u7E54"
8010
- };
8011
-
8012
- // src/registry/action-input-validator.ts
8013
- var SCHEMA_INDEX = (() => {
8014
- const map = /* @__PURE__ */ new Map();
8015
- for (const a of ACTION_REGISTRY.actions) {
8016
- if (a && typeof a.action === "string" && a.input_schema) {
8017
- map.set(a.action, a.input_schema);
8018
- }
8019
- }
8020
- return map;
8021
- })();
8022
- function describeExpectedShape(schema) {
8023
- const props = schema.properties ?? {};
8024
- const required = Array.isArray(schema.required) ? schema.required : [];
8025
- const requiredSet = new Set(required);
8026
- const parts = [];
8027
- const orderedKeys = [
8028
- ...required.filter((k) => k in props),
8029
- ...Object.keys(props).filter((k) => !requiredSet.has(k))
8030
- ];
8031
- for (const key of orderedKeys) {
8032
- const prop = props[key] || {};
8033
- const optionalMark = requiredSet.has(key) ? "" : "?";
8034
- const enumVals = Array.isArray(prop.enum) ? prop.enum : void 0;
8035
- if (enumVals && enumVals.length > 0) {
8036
- const rendered = enumVals.map((v) => typeof v === "string" ? `'${v}'` : String(v)).join(" | ");
8037
- parts.push(`${key}${optionalMark}: ${rendered}`);
8038
- } else {
8039
- parts.push(`${key}${optionalMark}`);
8040
- }
8041
- }
8042
- return `{ ${parts.join(", ")} }`;
8043
- }
8044
- function matchesType(value, type) {
8045
- if (!type) return true;
8046
- switch (type) {
8047
- case "string":
8048
- return typeof value === "string";
8049
- case "integer":
8050
- return typeof value === "number" && Number.isInteger(value);
8051
- case "number":
8052
- return typeof value === "number";
8053
- case "boolean":
8054
- return typeof value === "boolean";
8055
- case "array":
8056
- return Array.isArray(value);
8057
- case "object":
8058
- return typeof value === "object" && value !== null && !Array.isArray(value);
8059
- default:
8060
- return true;
8061
- }
8062
- }
8063
- function validateActionInput(action, params) {
8064
- const schema = SCHEMA_INDEX.get(action);
8065
- if (!schema) {
8066
- return { valid: true };
8067
- }
8068
- const props = schema.properties ?? {};
8069
- const required = Array.isArray(schema.required) ? schema.required : [];
8070
- const additionalProps = schema.additionalProperties;
8071
- const safeParams = params && typeof params === "object" && !Array.isArray(params) ? params : {};
8072
- const missing = [];
8073
- const unknown = [];
8074
- const enumErrors = [];
8075
- const typeErrors = [];
8076
- for (const key of required) {
8077
- if (!(key in safeParams) || safeParams[key] === void 0 || safeParams[key] === null) {
8078
- missing.push(key);
8079
- }
8080
- }
8081
- if (additionalProps === false) {
8082
- for (const key of Object.keys(safeParams)) {
8083
- if (!(key in props)) {
8084
- unknown.push(key);
8085
- }
8086
- }
8087
- }
8088
- for (const key of Object.keys(props)) {
8089
- if (!(key in safeParams)) continue;
8090
- const value = safeParams[key];
8091
- if (value === void 0 || value === null) continue;
8092
- const prop = props[key] || {};
8093
- const enumVals = Array.isArray(prop.enum) ? prop.enum : void 0;
8094
- if (enumVals && enumVals.length > 0) {
8095
- if (!enumVals.includes(value)) {
8096
- enumErrors.push(key);
8097
- continue;
8098
- }
8099
- }
8100
- if (!matchesType(value, prop.type)) {
8101
- typeErrors.push(key);
8102
- }
8103
- }
8104
- if (missing.length === 0 && unknown.length === 0 && enumErrors.length === 0 && typeErrors.length === 0) {
8105
- return { valid: true };
8106
- }
8107
- const segments = [];
8108
- if (missing.length > 0) {
8109
- segments.push(`missing required parameter(s) [${missing.join(", ")}]`);
8110
- }
8111
- if (unknown.length > 0) {
8112
- segments.push(`unknown parameter(s) [${unknown.join(", ")}]`);
8113
- }
8114
- if (enumErrors.length > 0) {
8115
- const details = enumErrors.map((key) => {
8116
- const enumVals = props[key]?.enum || [];
8117
- const rendered = enumVals.map((v) => typeof v === "string" ? `'${v}'` : String(v)).join(" | ");
8118
- return `${key} (allowed: ${rendered})`;
8119
- }).join(", ");
8120
- segments.push(`invalid value for enum parameter(s) [${details}]`);
8121
- }
8122
- if (typeErrors.length > 0) {
8123
- const details = typeErrors.map((key) => `${key} (expected ${props[key]?.type})`).join(", ");
8124
- segments.push(`wrong type for parameter(s) [${details}]`);
8125
- }
8126
- const message = `${action}: ${segments.join("; ")}. Expected shape: ${describeExpectedShape(schema)}`;
8127
- return { valid: false, errors: [message] };
8128
- }
8129
-
8130
- // src/registry/resource-types.ts
8131
- var RESOURCE_TYPES = {
8132
- // Slack
8133
- SLACK_CHANNEL: "slack:channel",
8134
- SLACK_USER: "slack:user",
8135
- SLACK_WORKSPACE: "slack:workspace",
8136
- // GitHub
8137
- GITHUB_REPO: "github:repo",
8138
- GITHUB_ORG: "github:org",
8139
- GITHUB_ISSUE: "github:issue",
8140
- // Google Drive
8141
- GOOGLE_DRIVE_FILE: "google:drive:file",
8142
- GOOGLE_DRIVE_FOLDER: "google:drive:folder",
8143
- // Gmail
8144
- GMAIL_THREAD: "gmail:thread",
8145
- GMAIL_LABEL: "gmail:label",
8146
- // Jira
8147
- JIRA_PROJECT: "jira:project",
8148
- JIRA_BOARD: "jira:board",
8149
- JIRA_ISSUE: "jira:issue",
8150
- JIRA_SPRINT: "jira:sprint",
8151
- // HubSpot
8152
- HUBSPOT_OBJECT: "hubspot:object",
8153
- HUBSPOT_PROPERTY: "hubspot:property",
8154
- HUBSPOT_SCHEMA: "hubspot:schema",
8155
- HUBSPOT_ASSOCIATION: "hubspot:association",
8156
- HUBSPOT_ENGAGEMENT: "hubspot:engagement",
8157
- HUBSPOT_WORKFLOW: "hubspot:workflow",
8158
- HUBSPOT_ACCOUNT: "hubspot:account",
8159
- // OS (local)
8160
- OS_SECRET: "os:secret",
8161
- OS_PROCESS: "os:process",
8162
- // Wildcard
8163
- ANY: "*"
8164
- };
8165
- var LEGACY_RESOURCE_TYPE_MAP = {
8166
- // Action Registry CamelCase format
8167
- SlackChannel: RESOURCE_TYPES.SLACK_CHANNEL,
8168
- GitHubRepo: RESOURCE_TYPES.GITHUB_REPO,
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",
9211
+ HUBSPOT_ASSOCIATION: "hubspot:association",
9212
+ HUBSPOT_ENGAGEMENT: "hubspot:engagement",
9213
+ HUBSPOT_WORKFLOW: "hubspot:workflow",
9214
+ HUBSPOT_ACCOUNT: "hubspot:account",
9215
+ // OS (local)
9216
+ OS_SECRET: "os:secret",
9217
+ OS_PROCESS: "os:process",
9218
+ // Wildcard
9219
+ ANY: "*"
9220
+ };
9221
+ var LEGACY_RESOURCE_TYPE_MAP = {
9222
+ // Action Registry CamelCase format
9223
+ SlackChannel: RESOURCE_TYPES.SLACK_CHANNEL,
9224
+ GitHubRepo: RESOURCE_TYPES.GITHUB_REPO,
8169
9225
  DriveFile: RESOURCE_TYPES.GOOGLE_DRIVE_FILE,
8170
9226
  JiraIssue: RESOURCE_TYPES.JIRA_ISSUE,
8171
9227
  JiraProject: RESOURCE_TYPES.JIRA_PROJECT,
@@ -8373,188 +9429,773 @@ var ACTION_DISPLAY_CONFIGS = {
8373
9429
  "slack.message.post": {
8374
9430
  summaryTemplate: (p) => {
8375
9431
  const parts = [];
8376
- if (p.channel) parts.push(p.channel + ":");
8377
- 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}`);
8378
9867
  return parts.join(" ");
8379
9868
  },
8380
9869
  displayFields: [
8381
- { key: "channel", label: "Channel" },
8382
- { key: "text", label: "Message" }
9870
+ { key: "commentId", label: "Comment" }
8383
9871
  ]
8384
9872
  },
8385
- "gmail.message.send": {
9873
+ "linear.comment.resolve": {
8386
9874
  summaryTemplate: (p) => {
8387
9875
  const parts = [];
8388
- if (p.to) parts.push(`To: ${p.to}`);
8389
- if (p.subject) parts.push(`Subject: ${p.subject}`);
8390
- return parts.join(", ");
9876
+ if (p.commentId) parts.push(`${p.commentId}:`);
9877
+ parts.push("Resolve comment");
9878
+ return parts.join(" ");
8391
9879
  },
8392
9880
  displayFields: [
8393
- { key: "to", label: "To" },
8394
- { key: "subject", label: "Subject" },
8395
- { key: "body", label: "Body" }
9881
+ { key: "commentId", label: "Comment" }
8396
9882
  ]
8397
9883
  },
8398
- "gmail.draft.create": {
9884
+ "linear.comment.unresolve": {
8399
9885
  summaryTemplate: (p) => {
8400
9886
  const parts = [];
8401
- if (p.to) parts.push(`To: ${p.to}`);
8402
- if (p.subject) parts.push(`Subject: ${p.subject}`);
8403
- return parts.join(", ");
9887
+ if (p.commentId) parts.push(`${p.commentId}:`);
9888
+ parts.push("Unresolve comment");
9889
+ return parts.join(" ");
8404
9890
  },
8405
9891
  displayFields: [
8406
- { key: "to", label: "To" },
8407
- { key: "subject", label: "Subject" },
8408
- { key: "body", label: "Body" }
9892
+ { key: "commentId", label: "Comment" }
8409
9893
  ]
8410
9894
  },
8411
- "calendar.event.create": {
9895
+ // ─── Linear Issue ops ───
9896
+ "linear.issue.unarchive": {
8412
9897
  summaryTemplate: (p) => {
8413
9898
  const parts = [];
8414
- if (p.summary) parts.push(p.summary);
8415
- if (p.start) parts.push(`(${formatCalendarTime(p.start)})`);
9899
+ if (p.issueId) parts.push(`${p.issueId}:`);
9900
+ parts.push("Unarchive");
8416
9901
  return parts.join(" ");
8417
9902
  },
8418
9903
  displayFields: [
8419
- { key: "summary", label: "Event" },
8420
- { key: "start", label: "Start" },
8421
- { key: "end", label: "End" },
8422
- { key: "attendees", label: "Attendees" }
9904
+ { key: "issueId", label: "Issue" }
8423
9905
  ]
8424
9906
  },
8425
- "calendar.event.update": {
9907
+ "linear.issue.addLabel": {
8426
9908
  summaryTemplate: (p) => {
8427
9909
  const parts = [];
8428
- if (p.summary) parts.push(p.summary);
8429
- 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}`);
8430
9912
  return parts.join(" ");
8431
9913
  },
8432
9914
  displayFields: [
8433
- { key: "summary", label: "Event" },
8434
- { key: "start", label: "Start" },
8435
- { key: "end", label: "End" },
8436
- { key: "attendees", label: "Attendees" }
9915
+ { key: "issueId", label: "Issue" },
9916
+ { key: "labelId", label: "Label" }
8437
9917
  ]
8438
9918
  },
8439
- "jira.issue.create": {
9919
+ "linear.issue.removeLabel": {
8440
9920
  summaryTemplate: (p) => {
8441
9921
  const parts = [];
8442
- const projectKey = jiraField(
8443
- p,
8444
- ["projectKey", "project"],
8445
- "project",
8446
- (v) => typeof v === "string" ? v : v?.key
8447
- );
8448
- const summary = jiraField(p, ["summary"], "summary");
8449
- if (projectKey) parts.push(`${projectKey}:`);
8450
- if (summary) parts.push(summary);
9922
+ if (p.issueId) parts.push(`${p.issueId}:`);
9923
+ if (p.labelId) parts.push(`Remove label ${p.labelId}`);
8451
9924
  return parts.join(" ");
8452
9925
  },
8453
- // AIDENTITY-54: nested `fields.X` 形式と top-level canonical の両方を
8454
- // 拾えるよう extract を使う。assignee は null (unassign) も表示。
8455
- // legacy alias (project / issuetype 等) も top-level 候補に含めて後方互換を保つ。
8456
9926
  displayFields: [
8457
- {
8458
- label: "Project",
8459
- extract: (p) => jiraField(
8460
- p,
8461
- ["projectKey", "project"],
8462
- "project",
8463
- (v) => typeof v === "string" ? v : v?.key
8464
- )
8465
- },
8466
- {
8467
- label: "Type",
8468
- extract: (p) => jiraField(
8469
- p,
8470
- ["issueTypeName", "issueType", "issuetype"],
8471
- "issuetype",
8472
- (v) => typeof v === "string" ? v : v?.name
8473
- )
8474
- },
8475
- { label: "Summary", extract: (p) => jiraField(p, ["summary"], "summary") },
8476
- { label: "Description", extract: (p) => jiraField(p, ["description"], "description") },
8477
- {
8478
- label: "Priority",
8479
- extract: (p) => jiraField(
8480
- p,
8481
- ["priority"],
8482
- "priority",
8483
- (v) => typeof v === "string" ? v : v?.name
8484
- )
8485
- },
8486
- { label: "Assignee", extract: extractJiraAssigneeDisplay },
8487
- { label: "Labels", extract: (p) => jiraField(p, ["labels"], "labels") }
9927
+ { key: "issueId", label: "Issue" },
9928
+ { key: "labelId", label: "Label" }
8488
9929
  ]
8489
9930
  },
8490
- "jira.issue.update": {
9931
+ "linear.issue.subscribe": {
8491
9932
  summaryTemplate: (p) => {
8492
9933
  const parts = [];
8493
- const key = p.issueIdOrKey ?? p.issueKey;
8494
- const summary = jiraField(p, ["summary"], "summary");
8495
- if (key) parts.push(`${key}:`);
8496
- if (summary) parts.push(summary);
9934
+ if (p.issueId) parts.push(`${p.issueId}:`);
9935
+ parts.push("Subscribe");
8497
9936
  return parts.join(" ");
8498
9937
  },
8499
9938
  displayFields: [
8500
- // canonical issueIdOrKey、agent issueKey で送ってくる旧仕様も拾う。
8501
- { label: "Issue", extract: (p) => p.issueIdOrKey ?? p.issueKey },
8502
- { label: "Summary", extract: (p) => jiraField(p, ["summary"], "summary") },
8503
- { label: "Description", extract: (p) => jiraField(p, ["description"], "description") },
8504
- {
8505
- label: "Priority",
8506
- extract: (p) => jiraField(
8507
- p,
8508
- ["priority"],
8509
- "priority",
8510
- (v) => typeof v === "string" ? v : v?.name
8511
- )
8512
- },
8513
- // AIDENTITY-54: top-level alias (string / object) と null (unassign) も解決。
8514
- { label: "Assignee", extract: extractJiraAssigneeDisplay },
8515
- { label: "Labels", extract: (p) => jiraField(p, ["labels"], "labels") }
9939
+ { key: "issueId", label: "Issue" }
8516
9940
  ]
8517
9941
  },
8518
- // AIDENTITY-65: comment 本体は string と ADF document の両方を受けるため、
8519
- // detail 表示の ADF 描画は formatValueFull 側に任せて key 指定で OK。
8520
- "jira.comment.create": {
9942
+ "linear.issue.delete": {
8521
9943
  summaryTemplate: (p) => {
8522
9944
  const parts = [];
8523
- if (p.issueIdOrKey) parts.push(`${p.issueIdOrKey}:`);
8524
- if (p.body) parts.push(typeof p.body === "string" ? p.body : "[ADF]");
9945
+ if (p.issueId) parts.push(`Delete issue ${p.issueId}`);
8525
9946
  return parts.join(" ");
8526
9947
  },
8527
9948
  displayFields: [
8528
- { key: "issueIdOrKey", label: "Issue" },
8529
- { key: "body", label: "Comment" }
9949
+ { key: "issueId", label: "Issue" }
8530
9950
  ]
8531
9951
  },
8532
- // AIDENTITY-66: 破壊的操作なので「どの issue のどの comment を消すか」を明示する
8533
- // (jira.issue.delete / jira.issuelink.delete と同じ destructive 表現の方針)。
8534
- "jira.comment.delete": {
9952
+ // ─── Linear Issue Relations ───
9953
+ "linear.issueRelation.create": {
8535
9954
  summaryTemplate: (p) => {
8536
- const issue = p.issueIdOrKey ?? p.issueKey;
8537
- const commentId = p.commentId ?? p.id;
8538
- if (issue && commentId) return `Delete comment ${commentId} on ${issue}`;
8539
- if (commentId) return `Delete comment ${commentId}`;
8540
- 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(" ");
8541
9960
  },
8542
9961
  displayFields: [
8543
- { label: "Issue", extract: (p) => p.issueIdOrKey ?? p.issueKey },
8544
- { 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" }
8545
9965
  ]
8546
9966
  },
8547
- // AIDENTITY-65: API enricher が 'Link' label を upsert で書き換える。
8548
- "jira.issuelink.delete": {
9967
+ "linear.issueRelation.list": {
8549
9968
  summaryTemplate: (p) => {
8550
9969
  const parts = [];
8551
- if (p.linkId) parts.push(`Delete link ${p.linkId}`);
9970
+ if (p.issueId) parts.push(`${p.issueId}:`);
9971
+ parts.push("List relations");
8552
9972
  return parts.join(" ");
8553
9973
  },
8554
9974
  displayFields: [
8555
- { 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" }
8556
10193
  ]
8557
10194
  },
10195
+ "linear.viewer.read": {
10196
+ summaryTemplate: (_p) => "Read viewer (current user)",
10197
+ displayFields: []
10198
+ },
8558
10199
  // AIDENTITY-83: email / displayName から accountId を解決する read action。
8559
10200
  "jira.user.search": {
8560
10201
  summaryTemplate: (p) => {
@@ -8577,7 +10218,8 @@ var ACTION_DISPLAY_CONFIGS = {
8577
10218
  displayFields: [
8578
10219
  { key: "to", label: "To" },
8579
10220
  { key: "taskType", label: "Task" },
8580
- { key: "message", label: "Message" }
10221
+ { key: "message", label: "Message" },
10222
+ { key: "payload", label: "Payload" }
8581
10223
  ]
8582
10224
  },
8583
10225
  "inbox.respond": {
@@ -8605,15 +10247,25 @@ var ACTION_DISPLAY_CONFIGS = {
8605
10247
  ]
8606
10248
  },
8607
10249
  "inbox.checkByToken": {
8608
- summaryTemplate: (p) => p.token ? `Token: ${p.token}` : "",
8609
- displayFields: [
8610
- { key: "token", label: "Token" }
8611
- ]
10250
+ // token is an opaque access credential never render it in summaries or display fields.
10251
+ summaryTemplate: (_p) => "Check inbox by token",
10252
+ displayFields: []
8612
10253
  },
8613
10254
  "inbox.complete": {
8614
10255
  summaryTemplate: (p) => p.id ? `Complete #${p.id}` : "",
8615
10256
  displayFields: [
8616
- { 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" }
8617
10269
  ]
8618
10270
  }
8619
10271
  };
@@ -8921,7 +10573,7 @@ function isWriteAction(action) {
8921
10573
  if (!meta) {
8922
10574
  return true;
8923
10575
  }
8924
- const writeEffectPrefixes = ["Create:", "Update:", "Delete:", "Write:", "Execute:", "Merge:", "Run:"];
10576
+ const writeEffectPrefixes = ["Create:", "Update:", "Delete:", "Write:", "Execute:", "Merge:", "Run:", "Archive:"];
8925
10577
  if (meta.effects?.some((e) => writeEffectPrefixes.some((p) => e.startsWith(p)))) {
8926
10578
  return true;
8927
10579
  }