@vess-id/ai-identity 0.14.0 → 0.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/dist/index.d.mts +6062 -96
  2. package/dist/index.js +1146 -41
  3. package/dist/index.js.map +1 -1
  4. package/dist/index.mjs +1145 -41
  5. package/dist/index.mjs.map +1 -1
  6. package/dist/registry/__tests__/action-input-validator.spec.d.ts +10 -0
  7. package/dist/registry/__tests__/action-input-validator.spec.d.ts.map +1 -0
  8. package/dist/registry/__tests__/action-registry-inbox.spec.d.ts +9 -0
  9. package/dist/registry/__tests__/action-registry-inbox.spec.d.ts.map +1 -0
  10. package/dist/registry/__tests__/action-registry-scheduling.spec.d.ts +13 -0
  11. package/dist/registry/__tests__/action-registry-scheduling.spec.d.ts.map +1 -0
  12. package/dist/registry/__tests__/guidance-examples.spec.d.ts +2 -0
  13. package/dist/registry/__tests__/guidance-examples.spec.d.ts.map +1 -0
  14. package/dist/registry/action-input-validator.d.ts +19 -0
  15. package/dist/registry/action-input-validator.d.ts.map +1 -0
  16. package/dist/registry/action-registry-json.d.ts +5975 -69
  17. package/dist/registry/action-registry-json.d.ts.map +1 -1
  18. package/dist/registry/action-summary.d.ts +6 -0
  19. package/dist/registry/action-summary.d.ts.map +1 -1
  20. package/dist/registry/index.d.ts +2 -0
  21. package/dist/registry/index.d.ts.map +1 -1
  22. package/dist/registry/providers.d.ts +1 -1
  23. package/dist/registry/providers.d.ts.map +1 -1
  24. package/dist/registry/resource-types.d.ts +7 -0
  25. package/dist/registry/resource-types.d.ts.map +1 -1
  26. package/dist/types/connector-plugin.d.ts +21 -0
  27. package/dist/types/connector-plugin.d.ts.map +1 -1
  28. package/dist/types/grant.d.ts +7 -0
  29. package/dist/types/grant.d.ts.map +1 -1
  30. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -164,6 +164,7 @@ __export(index_exports, {
164
164
  sha256Hex: () => sha256Hex,
165
165
  signJWT: () => signJWT,
166
166
  signRequest: () => signRequest,
167
+ validateActionInput: () => validateActionInput,
167
168
  validateRegistryObject: () => validateRegistryObject,
168
169
  vcStatusToCredentialStatus: () => vcStatusToCredentialStatus,
169
170
  verifyJWT: () => verifyJWT,
@@ -2926,6 +2927,13 @@ var GrantResourceType = /* @__PURE__ */ ((GrantResourceType2) => {
2926
2927
  GrantResourceType2["JIRA_PROJECT"] = "jira:project";
2927
2928
  GrantResourceType2["JIRA_BOARD"] = "jira:board";
2928
2929
  GrantResourceType2["JIRA_ISSUE"] = "jira:issue";
2930
+ GrantResourceType2["HUBSPOT_OBJECT"] = "hubspot:object";
2931
+ GrantResourceType2["HUBSPOT_PROPERTY"] = "hubspot:property";
2932
+ GrantResourceType2["HUBSPOT_SCHEMA"] = "hubspot:schema";
2933
+ GrantResourceType2["HUBSPOT_ASSOCIATION"] = "hubspot:association";
2934
+ GrantResourceType2["HUBSPOT_ENGAGEMENT"] = "hubspot:engagement";
2935
+ GrantResourceType2["HUBSPOT_WORKFLOW"] = "hubspot:workflow";
2936
+ GrantResourceType2["HUBSPOT_ACCOUNT"] = "hubspot:account";
2929
2937
  GrantResourceType2["OS_SECRET"] = "os:secret";
2930
2938
  GrantResourceType2["ANY"] = "*";
2931
2939
  return GrantResourceType2;
@@ -4259,6 +4267,7 @@ var CANONICAL_PROVIDERS = [
4259
4267
  "gmail",
4260
4268
  "calendar",
4261
4269
  "jira",
4270
+ "hubspot",
4262
4271
  "os"
4263
4272
  ];
4264
4273
  var PROVIDER_ALIASES = {};
@@ -4502,6 +4511,15 @@ var DummyVpVerifier = class {
4502
4511
  var ACTION_REGISTRY = {
4503
4512
  registry_version: "2025-09-28",
4504
4513
  actions: [
4514
+ // ─── Resource binding principle (high-risk CREATE actions) ───
4515
+ // A high-risk CREATE action's target_bindings.resource_id MUST bind to the
4516
+ // container/parent that already exists at approval + invoke time — never to
4517
+ // the not-yet-created resource's id (which does not exist until after the
4518
+ // call and is absent from input_schema). Cedar must resolve the resource at
4519
+ // evaluation time, and the server enforces a specific non-wildcard target,
4520
+ // so an unresolvable binding makes the action impossible to approve.
4521
+ // Examples: slack.message.post → channel, jira.issue.create → projectKey,
4522
+ // hubspot objects.batchCreate → objectType, engagements.create → type.
4505
4523
  // ─── Slack Actions ───
4506
4524
  {
4507
4525
  action: "slack.message.post",
@@ -4701,15 +4719,21 @@ var ACTION_REGISTRY = {
4701
4719
  required_relations: ["editor", "act_as"],
4702
4720
  required_scopes: ["repo", "write:issues"],
4703
4721
  capability: "github.issues.triage",
4722
+ // Schema mirrors the server contract (GitHubConnectorAdapter
4723
+ // getSupportedActions inputSchema — packages/api/src/tool/adapters/
4724
+ // github.adapter.ts): owner/repo are required params.
4704
4725
  input_schema: {
4705
4726
  type: "object",
4706
4727
  properties: {
4728
+ owner: { type: "string", minLength: 1, description: "Repository owner (username or organization)" },
4729
+ repo: { type: "string", minLength: 1, description: "Repository name" },
4707
4730
  title: { type: "string", minLength: 1 },
4708
4731
  body: { type: "string" },
4709
4732
  labels: { type: "array", items: { type: "string" } },
4710
- assignees: { type: "array", items: { type: "string" } }
4733
+ assignees: { type: "array", items: { type: "string" } },
4734
+ milestone: { type: "integer", minimum: 1, description: "Milestone number to associate with the issue" }
4711
4735
  },
4712
- required: ["title"],
4736
+ required: ["owner", "repo", "title"],
4713
4737
  additionalProperties: false
4714
4738
  },
4715
4739
  constraints: { rate_bucket: "github.write" },
@@ -4726,9 +4750,13 @@ var ACTION_REGISTRY = {
4726
4750
  required_relations: ["viewer", "editor", "admin", "owner"],
4727
4751
  required_scopes: ["repo", "read:issues"],
4728
4752
  capability: "github.read.basic",
4753
+ // Schema mirrors the server contract (GitHubConnectorAdapter):
4754
+ // owner/repo are required params.
4729
4755
  input_schema: {
4730
4756
  type: "object",
4731
4757
  properties: {
4758
+ owner: { type: "string", minLength: 1, description: "Repository owner (username or organization)" },
4759
+ repo: { type: "string", minLength: 1, description: "Repository name" },
4732
4760
  state: { type: "string", enum: ["open", "closed", "all"] },
4733
4761
  labels: { type: "string" },
4734
4762
  sort: { type: "string", enum: ["created", "updated", "comments"] },
@@ -4736,6 +4764,7 @@ var ACTION_REGISTRY = {
4736
4764
  per_page: { type: "integer", minimum: 1, maximum: 100 },
4737
4765
  page: { type: "integer", minimum: 1 }
4738
4766
  },
4767
+ required: ["owner", "repo"],
4739
4768
  additionalProperties: false
4740
4769
  },
4741
4770
  constraints: { rate_bucket: "github.read" },
@@ -4752,12 +4781,17 @@ var ACTION_REGISTRY = {
4752
4781
  required_relations: ["viewer", "editor", "admin", "owner"],
4753
4782
  required_scopes: ["repo", "read:issues"],
4754
4783
  capability: "github.read.basic",
4784
+ // Schema mirrors the server contract (GitHubConnectorAdapter):
4785
+ // owner/repo required, camelCase issueNumber (the adapter reads
4786
+ // params.issueNumber — snake_case issue_number was a drift).
4755
4787
  input_schema: {
4756
4788
  type: "object",
4757
4789
  properties: {
4758
- issue_number: { type: "integer", minimum: 1 }
4790
+ owner: { type: "string", minLength: 1, description: "Repository owner (username or organization)" },
4791
+ repo: { type: "string", minLength: 1, description: "Repository name" },
4792
+ issueNumber: { type: "integer", minimum: 1, description: "Issue number" }
4759
4793
  },
4760
- required: ["issue_number"],
4794
+ required: ["owner", "repo", "issueNumber"],
4761
4795
  additionalProperties: false
4762
4796
  },
4763
4797
  constraints: { rate_bucket: "github.read" },
@@ -4774,17 +4808,22 @@ var ACTION_REGISTRY = {
4774
4808
  required_relations: ["editor", "act_as"],
4775
4809
  required_scopes: ["repo", "write:issues"],
4776
4810
  capability: "github.issues.triage",
4811
+ // Schema mirrors the server contract (GitHubConnectorAdapter):
4812
+ // owner/repo required, camelCase issueNumber (the adapter reads
4813
+ // params.issueNumber — snake_case issue_number was a drift).
4777
4814
  input_schema: {
4778
4815
  type: "object",
4779
4816
  properties: {
4780
- issue_number: { type: "integer", minimum: 1 },
4817
+ owner: { type: "string", minLength: 1, description: "Repository owner (username or organization)" },
4818
+ repo: { type: "string", minLength: 1, description: "Repository name" },
4819
+ issueNumber: { type: "integer", minimum: 1, description: "Issue number to update" },
4781
4820
  title: { type: "string" },
4782
4821
  body: { type: "string" },
4783
4822
  state: { type: "string", enum: ["open", "closed"] },
4784
4823
  labels: { type: "array", items: { type: "string" } },
4785
4824
  assignees: { type: "array", items: { type: "string" } }
4786
4825
  },
4787
- required: ["issue_number"],
4826
+ required: ["owner", "repo", "issueNumber"],
4788
4827
  additionalProperties: false
4789
4828
  },
4790
4829
  constraints: { rate_bucket: "github.write" },
@@ -5076,7 +5115,9 @@ var ACTION_REGISTRY = {
5076
5115
  }
5077
5116
  },
5078
5117
  attendees: { type: "array", description: "List of attendee objects with email field", items: { type: "object", properties: { email: { type: "string" } } } },
5079
- location: { type: "string", description: "Event location" }
5118
+ location: { type: "string", description: "Event location" },
5119
+ addMeet: { type: "boolean", description: "Opt-in: attach a Google Meet link (default: false)" },
5120
+ meetRequestId: { type: "string", description: "Stable idempotency key for the Meet request (used only when addMeet is true)" }
5080
5121
  },
5081
5122
  required: ["summary", "start", "end"],
5082
5123
  additionalProperties: false
@@ -5124,7 +5165,9 @@ var ACTION_REGISTRY = {
5124
5165
  }
5125
5166
  },
5126
5167
  attendees: { type: "array", description: "List of attendee objects with email field", items: { type: "object", properties: { email: { type: "string" } } } },
5127
- location: { type: "string", description: "Event location" }
5168
+ location: { type: "string", description: "Event location" },
5169
+ addMeet: { type: "boolean", description: "Opt-in: attach a Google Meet link (default: false)" },
5170
+ meetRequestId: { type: "string", description: "Stable idempotency key for the Meet request (used only when addMeet is true)" }
5128
5171
  },
5129
5172
  required: ["eventId"],
5130
5173
  additionalProperties: false
@@ -5332,7 +5375,13 @@ var ACTION_REGISTRY = {
5332
5375
  properties: {
5333
5376
  projectKey: { type: "string", minLength: 1 },
5334
5377
  summary: { type: "string", minLength: 1 },
5335
- description: { type: "string" },
5378
+ description: {
5379
+ oneOf: [
5380
+ { type: "string", description: "Plain text description." },
5381
+ { type: "object", description: 'ADF document object for rich formatting: {type:"doc", version:1, content:[...]}.' }
5382
+ ],
5383
+ description: 'Issue description. Pass a plain string, OR an ADF document object ({type:"doc",version:1,content:[...]}) for rich formatting (headings, lists, code, links).'
5384
+ },
5336
5385
  issueTypeName: { type: "string", minLength: 1, description: "Issue type name (default: Task)" },
5337
5386
  priority: { type: "string" },
5338
5387
  assigneeAccountId: { type: "string" },
@@ -5360,7 +5409,13 @@ var ACTION_REGISTRY = {
5360
5409
  properties: {
5361
5410
  issueIdOrKey: { type: "string", minLength: 1 },
5362
5411
  summary: { type: "string" },
5363
- description: { type: "string" },
5412
+ description: {
5413
+ oneOf: [
5414
+ { type: "string", description: "Plain text description." },
5415
+ { type: "object", description: 'ADF document object for rich formatting: {type:"doc", version:1, content:[...]}.' }
5416
+ ],
5417
+ description: 'Issue description. Pass a plain string, OR an ADF document object ({type:"doc",version:1,content:[...]}) for rich formatting (headings, lists, code, links).'
5418
+ },
5364
5419
  priority: { type: "string" },
5365
5420
  assigneeAccountId: { type: "string" },
5366
5421
  labels: { type: "array", items: { type: "string" } }
@@ -5408,7 +5463,13 @@ var ACTION_REGISTRY = {
5408
5463
  type: "object",
5409
5464
  properties: {
5410
5465
  issueIdOrKey: { type: "string", minLength: 1 },
5411
- body: { type: "string", minLength: 1 }
5466
+ body: {
5467
+ oneOf: [
5468
+ { type: "string", minLength: 1, description: "Plain text comment body." },
5469
+ { type: "object", description: 'ADF document object for rich formatting: {type:"doc", version:1, content:[...]}.' }
5470
+ ],
5471
+ description: 'Comment body. Pass a plain string, OR an ADF document object ({type:"doc",version:1,content:[...]}) for rich formatting (headings, lists, code, links).'
5472
+ }
5412
5473
  },
5413
5474
  required: ["issueIdOrKey", "body"],
5414
5475
  additionalProperties: false
@@ -5422,6 +5483,34 @@ var ACTION_REGISTRY = {
5422
5483
  },
5423
5484
  version: "1.0.0"
5424
5485
  },
5486
+ {
5487
+ // AIDENTITY-66: delete a comment from a Jira issue. high-risk destructive
5488
+ // write — mirrors jira.issue.delete (admin/owner/act_as) but resource_type
5489
+ // は jira.comment.create と同じ jira:project (issue から project を derive)。
5490
+ action: "jira.comment.delete",
5491
+ resource_type: "jira:project",
5492
+ required_relations: ["admin", "owner", "act_as"],
5493
+ required_scopes: ["write:jira-work"],
5494
+ capability: "jira.write.basic",
5495
+ input_schema: {
5496
+ type: "object",
5497
+ properties: {
5498
+ issueIdOrKey: { type: "string", minLength: 1 },
5499
+ commentId: { type: "string", minLength: 1, description: "Comment id (from jira.comment.read)" }
5500
+ },
5501
+ required: ["issueIdOrKey", "commentId"],
5502
+ additionalProperties: false
5503
+ },
5504
+ constraints: { rate_bucket: "jira.write" },
5505
+ effects: ["Delete:Comment"],
5506
+ // high: deleting a comment is irreversible and visible to all project members,
5507
+ // consistent with jira.issue.delete / jira.comment.create.
5508
+ risk: "high",
5509
+ target_bindings: {
5510
+ resource_id: { source: "param", param: "issueIdOrKey", fallback_param: "issueKey", derive: "project_key" }
5511
+ },
5512
+ version: "1.0.0"
5513
+ },
5425
5514
  {
5426
5515
  action: "jira.comment.read",
5427
5516
  resource_type: "jira:project",
@@ -5587,6 +5676,42 @@ var ACTION_REGISTRY = {
5587
5676
  },
5588
5677
  version: "1.0.0"
5589
5678
  },
5679
+ {
5680
+ // AIDENTITY-83: email / displayName から accountId を解決する read action。
5681
+ // query は resource id ではなく検索語なので target_bindings は付けず
5682
+ // (jira.project.read 等の unscoped read と同様)、type-only match で評価する。
5683
+ action: "jira.user.search",
5684
+ resource_type: "jira:user",
5685
+ required_relations: ["viewer", "editor", "admin", "owner"],
5686
+ required_scopes: ["read:jira-user"],
5687
+ capability: "jira.read.basic",
5688
+ input_schema: {
5689
+ type: "object",
5690
+ properties: {
5691
+ query: {
5692
+ type: "string",
5693
+ minLength: 1,
5694
+ description: "Matched against displayName and emailAddress (prefix match). Pass an email address to resolve its accountId."
5695
+ },
5696
+ maxResults: {
5697
+ type: "integer",
5698
+ minimum: 1,
5699
+ maximum: 50,
5700
+ description: "Max users to return (default 10)"
5701
+ }
5702
+ },
5703
+ required: ["query"],
5704
+ additionalProperties: false
5705
+ },
5706
+ constraints: { rate_bucket: "jira.read" },
5707
+ effects: ["Read:User"],
5708
+ risk: "low",
5709
+ // query は resource id ではないので unscoped。required: false で type-only match。
5710
+ target_bindings: {
5711
+ resource_id: { source: "param", param: "query", required: false }
5712
+ },
5713
+ version: "1.0.0"
5714
+ },
5590
5715
  // ─── OS Actions (Local) ───
5591
5716
  {
5592
5717
  action: "os.secret.read",
@@ -5664,6 +5789,665 @@ var ACTION_REGISTRY = {
5664
5789
  resource_id: { source: "param", param: "command" }
5665
5790
  },
5666
5791
  version: "1.0.0"
5792
+ },
5793
+ // ─── HubSpot CRM Objects (objectType 汎用) ───
5794
+ // 公式 MCP (@hubspot/mcp-server) のツール集合を写像。object 系は objectType
5795
+ // パラメータ化された汎用エンドポイント。scope は objectType ごとに HubSpot 側で
5796
+ // 実行時強制されるため、required_scopes には代表 scope を宣言する (実際の許可範囲は
5797
+ // DEFAULT_SCOPES の固定 union)。
5798
+ {
5799
+ action: "hubspot.crm.objects.list",
5800
+ resource_type: "hubspot:object",
5801
+ required_relations: ["viewer", "editor", "admin", "owner"],
5802
+ required_scopes: ["crm.objects.contacts.read"],
5803
+ capability: "hubspot.crm.read",
5804
+ input_schema: {
5805
+ type: "object",
5806
+ properties: {
5807
+ objectType: { type: "string", description: "CRM object type (e.g. contacts, companies, deals) or custom object type ID" },
5808
+ limit: { type: "integer", minimum: 1, maximum: 100 },
5809
+ after: { type: "string" },
5810
+ properties: { type: "array", items: { type: "string" } },
5811
+ archived: { type: "boolean" }
5812
+ },
5813
+ required: ["objectType"],
5814
+ additionalProperties: false
5815
+ },
5816
+ constraints: { rate_bucket: "hubspot.read" },
5817
+ effects: ["Read:CrmObject"],
5818
+ risk: "low",
5819
+ target_bindings: {
5820
+ resource_id: { source: "param", param: "objectType" }
5821
+ },
5822
+ version: "1.0.0"
5823
+ },
5824
+ {
5825
+ action: "hubspot.crm.objects.search",
5826
+ resource_type: "hubspot:object",
5827
+ required_relations: ["viewer", "editor", "admin", "owner"],
5828
+ required_scopes: ["crm.objects.contacts.read"],
5829
+ capability: "hubspot.crm.read",
5830
+ input_schema: {
5831
+ type: "object",
5832
+ properties: {
5833
+ objectType: { type: "string", description: "CRM object type or custom object type ID" },
5834
+ query: { type: "string", maxLength: 3e3 },
5835
+ filterGroups: { type: "array" },
5836
+ properties: { type: "array", items: { type: "string" } },
5837
+ sorts: { type: "array", items: { type: "string" } },
5838
+ limit: { type: "integer", minimum: 1, maximum: 100 },
5839
+ after: { type: "string" }
5840
+ },
5841
+ required: ["objectType"],
5842
+ additionalProperties: false
5843
+ },
5844
+ constraints: { rate_bucket: "hubspot.read" },
5845
+ effects: ["Read:CrmObject"],
5846
+ risk: "low",
5847
+ target_bindings: {
5848
+ resource_id: { source: "param", param: "objectType" }
5849
+ },
5850
+ version: "1.0.0"
5851
+ },
5852
+ {
5853
+ action: "hubspot.crm.objects.batchRead",
5854
+ resource_type: "hubspot:object",
5855
+ required_relations: ["viewer", "editor", "admin", "owner"],
5856
+ required_scopes: ["crm.objects.contacts.read"],
5857
+ capability: "hubspot.crm.read",
5858
+ input_schema: {
5859
+ type: "object",
5860
+ properties: {
5861
+ objectType: { type: "string", description: "CRM object type or custom object type ID" },
5862
+ inputs: {
5863
+ type: "array",
5864
+ minItems: 1,
5865
+ items: { type: "object", properties: { id: { type: "string" } }, required: ["id"], additionalProperties: false }
5866
+ },
5867
+ properties: { type: "array", items: { type: "string" } },
5868
+ idProperty: { type: "string" }
5869
+ },
5870
+ required: ["objectType", "inputs"],
5871
+ additionalProperties: false
5872
+ },
5873
+ constraints: { rate_bucket: "hubspot.read" },
5874
+ effects: ["Read:CrmObject"],
5875
+ risk: "low",
5876
+ target_bindings: {
5877
+ resource_id: { source: "param", param: "objectType" }
5878
+ },
5879
+ version: "1.0.0"
5880
+ },
5881
+ {
5882
+ action: "hubspot.crm.objects.batchCreate",
5883
+ resource_type: "hubspot:object",
5884
+ required_relations: ["editor", "act_as"],
5885
+ required_scopes: ["crm.objects.contacts.write"],
5886
+ capability: "hubspot.crm.write",
5887
+ input_schema: {
5888
+ type: "object",
5889
+ properties: {
5890
+ objectType: { type: "string", description: "CRM object type or custom object type ID" },
5891
+ inputs: {
5892
+ type: "array",
5893
+ minItems: 1,
5894
+ items: {
5895
+ type: "object",
5896
+ properties: { properties: { type: "object" }, associations: { type: "array" } },
5897
+ required: ["properties"],
5898
+ additionalProperties: false
5899
+ }
5900
+ }
5901
+ },
5902
+ required: ["objectType", "inputs"],
5903
+ additionalProperties: false
5904
+ },
5905
+ constraints: { rate_bucket: "hubspot.write" },
5906
+ effects: ["Create:CrmObject"],
5907
+ risk: "high",
5908
+ target_bindings: {
5909
+ resource_id: { source: "param", param: "objectType" }
5910
+ },
5911
+ version: "1.0.0"
5912
+ },
5913
+ {
5914
+ action: "hubspot.crm.objects.batchUpdate",
5915
+ resource_type: "hubspot:object",
5916
+ required_relations: ["editor", "act_as"],
5917
+ required_scopes: ["crm.objects.contacts.write"],
5918
+ capability: "hubspot.crm.write",
5919
+ input_schema: {
5920
+ type: "object",
5921
+ properties: {
5922
+ objectType: { type: "string", description: "CRM object type or custom object type ID" },
5923
+ inputs: {
5924
+ type: "array",
5925
+ minItems: 1,
5926
+ items: {
5927
+ type: "object",
5928
+ properties: { id: { type: "string" }, properties: { type: "object" } },
5929
+ required: ["id", "properties"],
5930
+ additionalProperties: false
5931
+ }
5932
+ }
5933
+ },
5934
+ required: ["objectType", "inputs"],
5935
+ additionalProperties: false
5936
+ },
5937
+ constraints: { rate_bucket: "hubspot.write" },
5938
+ effects: ["Update:CrmObject"],
5939
+ risk: "high",
5940
+ target_bindings: {
5941
+ resource_id: { source: "param", param: "objectType" }
5942
+ },
5943
+ version: "1.0.0"
5944
+ },
5945
+ {
5946
+ action: "hubspot.crm.schemas.get",
5947
+ resource_type: "hubspot:schema",
5948
+ required_relations: ["viewer", "editor", "admin", "owner"],
5949
+ required_scopes: ["crm.schemas.custom.read"],
5950
+ capability: "hubspot.crm.read",
5951
+ input_schema: {
5952
+ type: "object",
5953
+ properties: {},
5954
+ additionalProperties: false
5955
+ },
5956
+ constraints: { rate_bucket: "hubspot.read" },
5957
+ effects: ["Read:CrmSchema"],
5958
+ risk: "low",
5959
+ target_bindings: {
5960
+ resource_id: { source: "param", param: "objectType", required: false }
5961
+ },
5962
+ version: "1.0.0"
5963
+ },
5964
+ // ─── HubSpot Properties ───
5965
+ {
5966
+ action: "hubspot.crm.properties.list",
5967
+ resource_type: "hubspot:property",
5968
+ required_relations: ["viewer", "editor", "admin", "owner"],
5969
+ required_scopes: ["crm.schemas.contacts.read"],
5970
+ capability: "hubspot.crm.read",
5971
+ input_schema: {
5972
+ type: "object",
5973
+ properties: {
5974
+ objectType: { type: "string", description: "CRM object type or custom object type ID" },
5975
+ archived: { type: "boolean" }
5976
+ },
5977
+ required: ["objectType"],
5978
+ additionalProperties: false
5979
+ },
5980
+ constraints: { rate_bucket: "hubspot.read" },
5981
+ effects: ["Read:CrmProperty"],
5982
+ risk: "low",
5983
+ target_bindings: { resource_id: { source: "param", param: "objectType" } },
5984
+ version: "1.0.0"
5985
+ },
5986
+ {
5987
+ action: "hubspot.crm.properties.get",
5988
+ resource_type: "hubspot:property",
5989
+ required_relations: ["viewer", "editor", "admin", "owner"],
5990
+ required_scopes: ["crm.schemas.contacts.read"],
5991
+ capability: "hubspot.crm.read",
5992
+ input_schema: {
5993
+ type: "object",
5994
+ properties: {
5995
+ objectType: { type: "string", description: "CRM object type or custom object type ID" },
5996
+ propertyName: { type: "string", description: "Internal property name" }
5997
+ },
5998
+ required: ["objectType", "propertyName"],
5999
+ additionalProperties: false
6000
+ },
6001
+ constraints: { rate_bucket: "hubspot.read" },
6002
+ effects: ["Read:CrmProperty"],
6003
+ risk: "low",
6004
+ target_bindings: { resource_id: { source: "param", param: "objectType" } },
6005
+ version: "1.0.0"
6006
+ },
6007
+ {
6008
+ action: "hubspot.crm.properties.create",
6009
+ resource_type: "hubspot:property",
6010
+ required_relations: ["editor", "act_as"],
6011
+ required_scopes: ["crm.schemas.contacts.write"],
6012
+ capability: "hubspot.crm.write",
6013
+ input_schema: {
6014
+ type: "object",
6015
+ properties: {
6016
+ objectType: { type: "string", description: "CRM object type or custom object type ID" },
6017
+ name: { type: "string" },
6018
+ label: { type: "string" },
6019
+ type: { type: "string" },
6020
+ fieldType: { type: "string" },
6021
+ groupName: { type: "string" },
6022
+ description: { type: "string" },
6023
+ options: { type: "array" }
6024
+ },
6025
+ required: ["objectType", "name", "label", "type", "fieldType", "groupName"],
6026
+ additionalProperties: false
6027
+ },
6028
+ constraints: { rate_bucket: "hubspot.write" },
6029
+ effects: ["Create:CrmProperty"],
6030
+ risk: "high",
6031
+ target_bindings: { resource_id: { source: "param", param: "objectType" } },
6032
+ version: "1.0.0"
6033
+ },
6034
+ {
6035
+ action: "hubspot.crm.properties.update",
6036
+ resource_type: "hubspot:property",
6037
+ required_relations: ["editor", "act_as"],
6038
+ required_scopes: ["crm.schemas.contacts.write"],
6039
+ capability: "hubspot.crm.write",
6040
+ input_schema: {
6041
+ type: "object",
6042
+ properties: {
6043
+ objectType: { type: "string", description: "CRM object type or custom object type ID" },
6044
+ propertyName: { type: "string" },
6045
+ label: { type: "string" },
6046
+ type: { type: "string" },
6047
+ fieldType: { type: "string" },
6048
+ groupName: { type: "string" },
6049
+ description: { type: "string" },
6050
+ options: { type: "array" }
6051
+ },
6052
+ required: ["objectType", "propertyName"],
6053
+ additionalProperties: false
6054
+ },
6055
+ constraints: { rate_bucket: "hubspot.write" },
6056
+ effects: ["Update:CrmProperty"],
6057
+ risk: "high",
6058
+ target_bindings: { resource_id: { source: "param", param: "objectType" } },
6059
+ version: "1.0.0"
6060
+ },
6061
+ // ─── HubSpot Associations (v4) ───
6062
+ {
6063
+ action: "hubspot.crm.associations.list",
6064
+ resource_type: "hubspot:association",
6065
+ required_relations: ["viewer", "editor", "admin", "owner"],
6066
+ required_scopes: ["crm.objects.contacts.read"],
6067
+ capability: "hubspot.crm.read",
6068
+ input_schema: {
6069
+ type: "object",
6070
+ properties: {
6071
+ objectType: { type: "string" },
6072
+ objectId: { type: "string" },
6073
+ toObjectType: { type: "string" },
6074
+ after: { type: "string" },
6075
+ limit: { type: "integer", minimum: 1, maximum: 100 }
6076
+ },
6077
+ required: ["objectType", "objectId", "toObjectType"],
6078
+ additionalProperties: false
6079
+ },
6080
+ constraints: { rate_bucket: "hubspot.read" },
6081
+ effects: ["Read:CrmAssociation"],
6082
+ risk: "low",
6083
+ target_bindings: { resource_id: { source: "param", param: "objectType" } },
6084
+ version: "1.0.0"
6085
+ },
6086
+ {
6087
+ action: "hubspot.crm.associations.getDefinitions",
6088
+ resource_type: "hubspot:association",
6089
+ required_relations: ["viewer", "editor", "admin", "owner"],
6090
+ required_scopes: ["crm.objects.contacts.read"],
6091
+ capability: "hubspot.crm.read",
6092
+ input_schema: {
6093
+ type: "object",
6094
+ properties: {
6095
+ fromObjectType: { type: "string" },
6096
+ toObjectType: { type: "string" }
6097
+ },
6098
+ required: ["fromObjectType", "toObjectType"],
6099
+ additionalProperties: false
6100
+ },
6101
+ constraints: { rate_bucket: "hubspot.read" },
6102
+ effects: ["Read:CrmAssociation"],
6103
+ risk: "low",
6104
+ target_bindings: { resource_id: { source: "param", param: "fromObjectType" } },
6105
+ version: "1.0.0"
6106
+ },
6107
+ {
6108
+ action: "hubspot.crm.associations.batchCreate",
6109
+ resource_type: "hubspot:association",
6110
+ required_relations: ["editor", "act_as"],
6111
+ required_scopes: ["crm.objects.contacts.write"],
6112
+ capability: "hubspot.crm.write",
6113
+ input_schema: {
6114
+ type: "object",
6115
+ properties: {
6116
+ fromObjectType: { type: "string" },
6117
+ toObjectType: { type: "string" },
6118
+ inputs: { type: "array", minItems: 1 }
6119
+ },
6120
+ required: ["fromObjectType", "toObjectType", "inputs"],
6121
+ additionalProperties: false
6122
+ },
6123
+ constraints: { rate_bucket: "hubspot.write" },
6124
+ effects: ["Create:CrmAssociation"],
6125
+ risk: "high",
6126
+ target_bindings: { resource_id: { source: "param", param: "fromObjectType" } },
6127
+ version: "1.0.0"
6128
+ },
6129
+ // ─── HubSpot Engagements (legacy v1: NOTE / TASK) ───
6130
+ {
6131
+ action: "hubspot.crm.engagements.get",
6132
+ resource_type: "hubspot:engagement",
6133
+ required_relations: ["viewer", "editor", "admin", "owner"],
6134
+ required_scopes: ["crm.objects.contacts.read"],
6135
+ capability: "hubspot.crm.read",
6136
+ input_schema: {
6137
+ type: "object",
6138
+ properties: { engagementId: { type: "string" } },
6139
+ required: ["engagementId"],
6140
+ additionalProperties: false
6141
+ },
6142
+ constraints: { rate_bucket: "hubspot.read" },
6143
+ effects: ["Read:CrmEngagement"],
6144
+ risk: "low",
6145
+ target_bindings: { resource_id: { source: "param", param: "engagementId" } },
6146
+ version: "1.0.0"
6147
+ },
6148
+ {
6149
+ action: "hubspot.crm.engagements.create",
6150
+ resource_type: "hubspot:engagement",
6151
+ required_relations: ["editor", "act_as"],
6152
+ required_scopes: ["crm.objects.contacts.write"],
6153
+ capability: "hubspot.crm.write",
6154
+ input_schema: {
6155
+ type: "object",
6156
+ properties: {
6157
+ type: { type: "string", enum: ["NOTE", "TASK"] },
6158
+ ownerId: { type: "number" },
6159
+ timestamp: { type: "number" },
6160
+ associations: { type: "object" },
6161
+ metadata: { type: "object" }
6162
+ },
6163
+ required: ["type", "ownerId", "metadata"],
6164
+ additionalProperties: false
6165
+ },
6166
+ constraints: { rate_bucket: "hubspot.write" },
6167
+ effects: ["Create:CrmEngagement"],
6168
+ risk: "high",
6169
+ // Bind to the engagement type (NOTE/TASK) as the container that exists at
6170
+ // call time, consistent with other create actions (see CREATE-binding note above).
6171
+ target_bindings: { resource_id: { source: "param", param: "type" } },
6172
+ version: "1.0.0"
6173
+ },
6174
+ {
6175
+ action: "hubspot.crm.engagements.update",
6176
+ resource_type: "hubspot:engagement",
6177
+ required_relations: ["editor", "act_as"],
6178
+ required_scopes: ["crm.objects.contacts.write"],
6179
+ capability: "hubspot.crm.write",
6180
+ input_schema: {
6181
+ type: "object",
6182
+ properties: {
6183
+ engagementId: { type: "string" },
6184
+ ownerId: { type: "number" },
6185
+ timestamp: { type: "number" },
6186
+ associations: { type: "object" },
6187
+ metadata: { type: "object" }
6188
+ },
6189
+ required: ["engagementId"],
6190
+ additionalProperties: false
6191
+ },
6192
+ constraints: { rate_bucket: "hubspot.write" },
6193
+ effects: ["Update:CrmEngagement"],
6194
+ risk: "high",
6195
+ target_bindings: { resource_id: { source: "param", param: "engagementId" } },
6196
+ version: "1.0.0"
6197
+ },
6198
+ // ─── HubSpot Workflows (automation v4 flows, read-only) ───
6199
+ {
6200
+ action: "hubspot.automation.workflows.list",
6201
+ resource_type: "hubspot:workflow",
6202
+ required_relations: ["viewer", "editor", "admin", "owner"],
6203
+ required_scopes: ["automation"],
6204
+ capability: "hubspot.automation.read",
6205
+ input_schema: {
6206
+ type: "object",
6207
+ properties: {
6208
+ after: { type: "string" },
6209
+ limit: { type: "integer", minimum: 1, maximum: 100 }
6210
+ },
6211
+ additionalProperties: false
6212
+ },
6213
+ constraints: { rate_bucket: "hubspot.read" },
6214
+ effects: ["Read:Workflow"],
6215
+ risk: "low",
6216
+ target_bindings: { resource_id: { source: "param", param: "flowId", required: false } },
6217
+ version: "1.0.0"
6218
+ },
6219
+ {
6220
+ action: "hubspot.automation.workflows.get",
6221
+ resource_type: "hubspot:workflow",
6222
+ required_relations: ["viewer", "editor", "admin", "owner"],
6223
+ required_scopes: ["automation"],
6224
+ capability: "hubspot.automation.read",
6225
+ input_schema: {
6226
+ type: "object",
6227
+ properties: { flowId: { type: "string" } },
6228
+ required: ["flowId"],
6229
+ additionalProperties: false
6230
+ },
6231
+ constraints: { rate_bucket: "hubspot.read" },
6232
+ effects: ["Read:Workflow"],
6233
+ risk: "low",
6234
+ target_bindings: { resource_id: { source: "param", param: "flowId" } },
6235
+ version: "1.0.0"
6236
+ },
6237
+ // ─── HubSpot Account / utility ───
6238
+ {
6239
+ action: "hubspot.account.userDetails.get",
6240
+ resource_type: "hubspot:account",
6241
+ required_relations: ["viewer", "editor", "admin", "owner"],
6242
+ required_scopes: ["oauth"],
6243
+ capability: "hubspot.account.read",
6244
+ input_schema: {
6245
+ type: "object",
6246
+ properties: {},
6247
+ additionalProperties: false
6248
+ },
6249
+ constraints: { rate_bucket: "hubspot.read" },
6250
+ effects: ["Read:Account"],
6251
+ risk: "low",
6252
+ target_bindings: { resource_id: { source: "param", param: "hubId", required: false } },
6253
+ version: "1.0.0"
6254
+ },
6255
+ {
6256
+ action: "hubspot.account.link.get",
6257
+ resource_type: "hubspot:account",
6258
+ required_relations: ["viewer", "editor", "admin", "owner"],
6259
+ // Pure URL builder; nominal base scope (always granted) keeps it
6260
+ // grantable and satisfies the registry's minItems:1 contract.
6261
+ required_scopes: ["oauth"],
6262
+ capability: "hubspot.account.read",
6263
+ input_schema: {
6264
+ type: "object",
6265
+ properties: {
6266
+ portalId: { type: "string" },
6267
+ uiDomain: { type: "string" },
6268
+ pageRequests: { type: "array", minItems: 1 }
6269
+ },
6270
+ required: ["portalId", "uiDomain", "pageRequests"],
6271
+ additionalProperties: false
6272
+ },
6273
+ constraints: { rate_bucket: "hubspot.read" },
6274
+ effects: ["Read:Account"],
6275
+ risk: "low",
6276
+ target_bindings: { resource_id: { source: "param", param: "portalId" } },
6277
+ version: "1.0.0"
6278
+ },
6279
+ // ─── Agent Inbox Actions (internal) ───
6280
+ // Inbox actions back the Agent Inbox MCP tools (task delegation between
6281
+ // agents/people). They are internal (no external OAuth provider), so they
6282
+ // carry a single nominal base scope `inbox` to satisfy the registry
6283
+ // meta-schema's `minItems: 1` (same pattern as hubspot.account.link.get).
6284
+ {
6285
+ action: "inbox.send",
6286
+ resource_type: "inbox:item",
6287
+ required_relations: ["editor", "act_as"],
6288
+ required_scopes: ["inbox"],
6289
+ capability: "inbox.write",
6290
+ input_schema: {
6291
+ type: "object",
6292
+ properties: {
6293
+ to: { type: "string", minLength: 1, description: "Recipient (user id / handle) the task request is sent to" },
6294
+ taskType: { type: "string", minLength: 1, description: "Type of task being requested" },
6295
+ payload: { type: "object", description: "Task-specific payload data" },
6296
+ message: { type: "string", description: "Optional human-readable message" }
6297
+ },
6298
+ required: ["to", "taskType", "payload"],
6299
+ additionalProperties: false
6300
+ },
6301
+ constraints: { rate_bucket: "inbox.write" },
6302
+ effects: ["Create:InboxItem"],
6303
+ risk: "high",
6304
+ target_bindings: {
6305
+ resource_id: { source: "param", param: "to" }
6306
+ },
6307
+ version: "1.0.0"
6308
+ },
6309
+ {
6310
+ action: "inbox.respond",
6311
+ resource_type: "inbox:item",
6312
+ required_relations: ["editor", "act_as"],
6313
+ required_scopes: ["inbox"],
6314
+ capability: "inbox.write",
6315
+ input_schema: {
6316
+ type: "object",
6317
+ properties: {
6318
+ id: { type: "string", minLength: 1, description: "Inbox item id being responded to" },
6319
+ action: { type: "string", enum: ["accept", "decline", "counter"], description: "Response action" },
6320
+ data: { type: "object", description: "Optional response data (e.g. counter-proposal)" }
6321
+ },
6322
+ required: ["id", "action"],
6323
+ additionalProperties: false
6324
+ },
6325
+ constraints: { rate_bucket: "inbox.write" },
6326
+ effects: ["Update:InboxItem"],
6327
+ // high (not medium): an agent-mediated response (MCP invoke) must always
6328
+ // go through human approval — the Phase 1 "always confirm" guarantee made
6329
+ // enforceable. target_bindings below binds the concrete inbox item id so
6330
+ // the high-risk approval has a specific resource constraint (the public
6331
+ // /scheduling/:token link flow does NOT go through this gate — it calls
6332
+ // InboxService.respond directly, system-key-signed).
6333
+ risk: "high",
6334
+ target_bindings: {
6335
+ resource_id: { source: "param", param: "id" }
6336
+ },
6337
+ version: "1.0.0"
6338
+ },
6339
+ {
6340
+ action: "inbox.check",
6341
+ resource_type: "inbox:item",
6342
+ required_relations: ["viewer", "editor", "admin", "owner"],
6343
+ required_scopes: ["inbox"],
6344
+ capability: "inbox.read",
6345
+ input_schema: {
6346
+ type: "object",
6347
+ properties: {
6348
+ types: { type: "array", items: { type: "string" }, description: "Filter by task types" },
6349
+ status: { type: "string", description: "Filter by item status" }
6350
+ },
6351
+ additionalProperties: false
6352
+ },
6353
+ constraints: { rate_bucket: "inbox.read" },
6354
+ effects: ["Read:InboxItem"],
6355
+ risk: "low",
6356
+ target_bindings: {
6357
+ resource_id: { source: "param", param: "id", required: false }
6358
+ },
6359
+ version: "1.0.0"
6360
+ },
6361
+ {
6362
+ action: "inbox.checkByToken",
6363
+ resource_type: "inbox:item",
6364
+ required_relations: ["viewer", "editor", "admin", "owner"],
6365
+ required_scopes: ["inbox"],
6366
+ capability: "inbox.read",
6367
+ input_schema: {
6368
+ type: "object",
6369
+ properties: {
6370
+ token: { type: "string", minLength: 1, description: "Opaque access token for a single inbox item" }
6371
+ },
6372
+ required: ["token"],
6373
+ additionalProperties: false
6374
+ },
6375
+ constraints: { rate_bucket: "inbox.read" },
6376
+ effects: ["Read:InboxItem"],
6377
+ risk: "low",
6378
+ target_bindings: {
6379
+ resource_id: { source: "param", param: "token" }
6380
+ },
6381
+ version: "1.0.0"
6382
+ },
6383
+ {
6384
+ action: "inbox.complete",
6385
+ resource_type: "inbox:item",
6386
+ required_relations: ["editor", "act_as"],
6387
+ required_scopes: ["inbox"],
6388
+ capability: "inbox.write",
6389
+ input_schema: {
6390
+ type: "object",
6391
+ properties: {
6392
+ id: { type: "string", minLength: 1, description: "Inbox item id being completed" },
6393
+ result: { type: "object", description: "Result payload for the completed task" }
6394
+ },
6395
+ required: ["id", "result"],
6396
+ additionalProperties: false
6397
+ },
6398
+ constraints: { rate_bucket: "inbox.write" },
6399
+ effects: ["Update:InboxItem"],
6400
+ risk: "low",
6401
+ target_bindings: {
6402
+ resource_id: { source: "param", param: "id" }
6403
+ },
6404
+ version: "1.0.0"
6405
+ },
6406
+ // ─── Scheduling Actions (internal) ───
6407
+ // scheduling.request is a meeting-time negotiation façade over inbox.send.
6408
+ // Candidate slots are computed LLM-side from the user calendar; the server
6409
+ // only validates them. Like the inbox actions it is internal (no external
6410
+ // OAuth provider), so it carries the single nominal base scope `inbox`.
6411
+ // Spec: docs/specs/2026-06-10-inbox-intent-routing-design.md §2.1
6412
+ {
6413
+ action: "scheduling.request",
6414
+ resource_type: "inbox:item",
6415
+ required_relations: ["editor", "act_as"],
6416
+ required_scopes: ["inbox"],
6417
+ capability: "inbox.write",
6418
+ input_schema: {
6419
+ type: "object",
6420
+ properties: {
6421
+ to: { type: "string", minLength: 1, description: "Counterpart (user id / email) to negotiate a meeting time with" },
6422
+ topic: { type: "string", minLength: 1, description: "Meeting topic shown to the counterpart" },
6423
+ durationMinutes: { type: "integer", minimum: 5, maximum: 480, description: "Meeting length in minutes" },
6424
+ candidates: {
6425
+ type: "array",
6426
+ minItems: 1,
6427
+ maxItems: 10,
6428
+ description: "Candidate slots computed by the agent from the user calendar (LLM-side computation; the server only validates)",
6429
+ items: {
6430
+ type: "object",
6431
+ properties: {
6432
+ start: { type: "string", description: "ISO 8601 start" },
6433
+ end: { type: "string", description: "ISO 8601 end" }
6434
+ },
6435
+ required: ["start", "end"],
6436
+ additionalProperties: false
6437
+ }
6438
+ },
6439
+ message: { type: "string", description: "Optional human-readable message" }
6440
+ },
6441
+ required: ["to", "topic", "durationMinutes", "candidates"],
6442
+ additionalProperties: false
6443
+ },
6444
+ constraints: { rate_bucket: "inbox.write" },
6445
+ effects: ["Create:InboxItem"],
6446
+ risk: "high",
6447
+ target_bindings: {
6448
+ resource_id: { source: "param", param: "to" }
6449
+ },
6450
+ version: "1.0.0"
5667
6451
  }
5668
6452
  ],
5669
6453
  capabilities: [
@@ -5723,19 +6507,149 @@ var ACTION_REGISTRY = {
5723
6507
  },
5724
6508
  {
5725
6509
  capability: "jira.read.basic",
5726
- description: "Read Jira issues, projects, boards, sprints, and issue link types",
5727
- 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"],
6510
+ description: "Read Jira issues, projects, boards, sprints, issue link types, and users",
6511
+ 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"],
5728
6512
  version: "1.0.0"
5729
6513
  },
5730
6514
  {
5731
6515
  capability: "jira.write.basic",
5732
- description: "Create, update, delete Jira issues, and manage issue links",
5733
- includes: ["jira.issue.create", "jira.issue.update", "jira.issue.delete", "jira.comment.create", "jira.issue.transition", "jira.issuelink.create", "jira.issuelink.delete"],
6516
+ description: "Create, update, delete Jira issues, manage issue links, and add/delete comments",
6517
+ 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"],
6518
+ version: "1.0.0"
6519
+ },
6520
+ {
6521
+ capability: "inbox.write",
6522
+ description: "Send and respond to agent inbox tasks",
6523
+ includes: ["inbox.send", "inbox.respond", "inbox.complete", "scheduling.request"],
6524
+ version: "1.0.0"
6525
+ },
6526
+ {
6527
+ capability: "inbox.read",
6528
+ description: "Read agent inbox tasks",
6529
+ includes: ["inbox.check", "inbox.checkByToken"],
5734
6530
  version: "1.0.0"
5735
6531
  }
5736
6532
  ]
5737
6533
  };
5738
6534
 
6535
+ // src/registry/action-input-validator.ts
6536
+ var SCHEMA_INDEX = (() => {
6537
+ const map = /* @__PURE__ */ new Map();
6538
+ for (const a of ACTION_REGISTRY.actions) {
6539
+ if (a && typeof a.action === "string" && a.input_schema) {
6540
+ map.set(a.action, a.input_schema);
6541
+ }
6542
+ }
6543
+ return map;
6544
+ })();
6545
+ function describeExpectedShape(schema) {
6546
+ const props = schema.properties ?? {};
6547
+ const required = Array.isArray(schema.required) ? schema.required : [];
6548
+ const requiredSet = new Set(required);
6549
+ const parts = [];
6550
+ const orderedKeys = [
6551
+ ...required.filter((k) => k in props),
6552
+ ...Object.keys(props).filter((k) => !requiredSet.has(k))
6553
+ ];
6554
+ for (const key of orderedKeys) {
6555
+ const prop = props[key] || {};
6556
+ const optionalMark = requiredSet.has(key) ? "" : "?";
6557
+ const enumVals = Array.isArray(prop.enum) ? prop.enum : void 0;
6558
+ if (enumVals && enumVals.length > 0) {
6559
+ const rendered = enumVals.map((v) => typeof v === "string" ? `'${v}'` : String(v)).join(" | ");
6560
+ parts.push(`${key}${optionalMark}: ${rendered}`);
6561
+ } else {
6562
+ parts.push(`${key}${optionalMark}`);
6563
+ }
6564
+ }
6565
+ return `{ ${parts.join(", ")} }`;
6566
+ }
6567
+ function matchesType(value, type) {
6568
+ if (!type) return true;
6569
+ switch (type) {
6570
+ case "string":
6571
+ return typeof value === "string";
6572
+ case "integer":
6573
+ return typeof value === "number" && Number.isInteger(value);
6574
+ case "number":
6575
+ return typeof value === "number";
6576
+ case "boolean":
6577
+ return typeof value === "boolean";
6578
+ case "array":
6579
+ return Array.isArray(value);
6580
+ case "object":
6581
+ return typeof value === "object" && value !== null && !Array.isArray(value);
6582
+ default:
6583
+ return true;
6584
+ }
6585
+ }
6586
+ function validateActionInput(action, params) {
6587
+ const schema = SCHEMA_INDEX.get(action);
6588
+ if (!schema) {
6589
+ return { valid: true };
6590
+ }
6591
+ const props = schema.properties ?? {};
6592
+ const required = Array.isArray(schema.required) ? schema.required : [];
6593
+ const additionalProps = schema.additionalProperties;
6594
+ const safeParams = params && typeof params === "object" && !Array.isArray(params) ? params : {};
6595
+ const missing = [];
6596
+ const unknown = [];
6597
+ const enumErrors = [];
6598
+ const typeErrors = [];
6599
+ for (const key of required) {
6600
+ if (!(key in safeParams) || safeParams[key] === void 0 || safeParams[key] === null) {
6601
+ missing.push(key);
6602
+ }
6603
+ }
6604
+ if (additionalProps === false) {
6605
+ for (const key of Object.keys(safeParams)) {
6606
+ if (!(key in props)) {
6607
+ unknown.push(key);
6608
+ }
6609
+ }
6610
+ }
6611
+ for (const key of Object.keys(props)) {
6612
+ if (!(key in safeParams)) continue;
6613
+ const value = safeParams[key];
6614
+ if (value === void 0 || value === null) continue;
6615
+ const prop = props[key] || {};
6616
+ const enumVals = Array.isArray(prop.enum) ? prop.enum : void 0;
6617
+ if (enumVals && enumVals.length > 0) {
6618
+ if (!enumVals.includes(value)) {
6619
+ enumErrors.push(key);
6620
+ continue;
6621
+ }
6622
+ }
6623
+ if (!matchesType(value, prop.type)) {
6624
+ typeErrors.push(key);
6625
+ }
6626
+ }
6627
+ if (missing.length === 0 && unknown.length === 0 && enumErrors.length === 0 && typeErrors.length === 0) {
6628
+ return { valid: true };
6629
+ }
6630
+ const segments = [];
6631
+ if (missing.length > 0) {
6632
+ segments.push(`missing required parameter(s) [${missing.join(", ")}]`);
6633
+ }
6634
+ if (unknown.length > 0) {
6635
+ segments.push(`unknown parameter(s) [${unknown.join(", ")}]`);
6636
+ }
6637
+ if (enumErrors.length > 0) {
6638
+ const details = enumErrors.map((key) => {
6639
+ const enumVals = props[key]?.enum || [];
6640
+ const rendered = enumVals.map((v) => typeof v === "string" ? `'${v}'` : String(v)).join(" | ");
6641
+ return `${key} (allowed: ${rendered})`;
6642
+ }).join(", ");
6643
+ segments.push(`invalid value for enum parameter(s) [${details}]`);
6644
+ }
6645
+ if (typeErrors.length > 0) {
6646
+ const details = typeErrors.map((key) => `${key} (expected ${props[key]?.type})`).join(", ");
6647
+ segments.push(`wrong type for parameter(s) [${details}]`);
6648
+ }
6649
+ const message = `${action}: ${segments.join("; ")}. Expected shape: ${describeExpectedShape(schema)}`;
6650
+ return { valid: false, errors: [message] };
6651
+ }
6652
+
5739
6653
  // src/registry/resource-types.ts
5740
6654
  var RESOURCE_TYPES = {
5741
6655
  // Slack
@@ -5757,6 +6671,14 @@ var RESOURCE_TYPES = {
5757
6671
  JIRA_BOARD: "jira:board",
5758
6672
  JIRA_ISSUE: "jira:issue",
5759
6673
  JIRA_SPRINT: "jira:sprint",
6674
+ // HubSpot
6675
+ HUBSPOT_OBJECT: "hubspot:object",
6676
+ HUBSPOT_PROPERTY: "hubspot:property",
6677
+ HUBSPOT_SCHEMA: "hubspot:schema",
6678
+ HUBSPOT_ASSOCIATION: "hubspot:association",
6679
+ HUBSPOT_ENGAGEMENT: "hubspot:engagement",
6680
+ HUBSPOT_WORKFLOW: "hubspot:workflow",
6681
+ HUBSPOT_ACCOUNT: "hubspot:account",
5760
6682
  // OS (local)
5761
6683
  OS_SECRET: "os:secret",
5762
6684
  OS_PROCESS: "os:process",
@@ -5783,6 +6705,13 @@ var LEGACY_RESOURCE_TYPE_MAP = {
5783
6705
  "jira:board": RESOURCE_TYPES.JIRA_BOARD,
5784
6706
  "jira:issue": RESOURCE_TYPES.JIRA_ISSUE,
5785
6707
  "jira:sprint": RESOURCE_TYPES.JIRA_SPRINT,
6708
+ "hubspot:object": RESOURCE_TYPES.HUBSPOT_OBJECT,
6709
+ "hubspot:property": RESOURCE_TYPES.HUBSPOT_PROPERTY,
6710
+ "hubspot:schema": RESOURCE_TYPES.HUBSPOT_SCHEMA,
6711
+ "hubspot:association": RESOURCE_TYPES.HUBSPOT_ASSOCIATION,
6712
+ "hubspot:engagement": RESOURCE_TYPES.HUBSPOT_ENGAGEMENT,
6713
+ "hubspot:workflow": RESOURCE_TYPES.HUBSPOT_WORKFLOW,
6714
+ "hubspot:account": RESOURCE_TYPES.HUBSPOT_ACCOUNT,
5786
6715
  "os:secret": RESOURCE_TYPES.OS_SECRET,
5787
6716
  "os:process": RESOURCE_TYPES.OS_PROCESS,
5788
6717
  // Legacy formats with old provider prefixes
@@ -6006,7 +6935,7 @@ var ACTION_DISPLAY_CONFIGS = {
6006
6935
  summaryTemplate: (p) => {
6007
6936
  const parts = [];
6008
6937
  if (p.summary) parts.push(p.summary);
6009
- if (p.start) parts.push(`(${formatValue(p.start)})`);
6938
+ if (p.start) parts.push(`(${formatCalendarTime(p.start)})`);
6010
6939
  return parts.join(" ");
6011
6940
  },
6012
6941
  displayFields: [
@@ -6020,7 +6949,7 @@ var ACTION_DISPLAY_CONFIGS = {
6020
6949
  summaryTemplate: (p) => {
6021
6950
  const parts = [];
6022
6951
  if (p.summary) parts.push(p.summary);
6023
- if (p.start) parts.push(`(${formatValue(p.start)})`);
6952
+ if (p.start) parts.push(`(${formatCalendarTime(p.start)})`);
6024
6953
  return parts.join(" ");
6025
6954
  },
6026
6955
  displayFields: [
@@ -6110,7 +7039,7 @@ var ACTION_DISPLAY_CONFIGS = {
6110
7039
  ]
6111
7040
  },
6112
7041
  // AIDENTITY-65: comment 本体は string と ADF document の両方を受けるため、
6113
- // formatValue 側の ADF ハンドリング (extractFirstAdfText) に任せて key 指定で OK。
7042
+ // detail 表示の ADF 描画は formatValueFull 側に任せて key 指定で OK。
6114
7043
  "jira.comment.create": {
6115
7044
  summaryTemplate: (p) => {
6116
7045
  const parts = [];
@@ -6123,6 +7052,21 @@ var ACTION_DISPLAY_CONFIGS = {
6123
7052
  { key: "body", label: "Comment" }
6124
7053
  ]
6125
7054
  },
7055
+ // AIDENTITY-66: 破壊的操作なので「どの issue のどの comment を消すか」を明示する
7056
+ // (jira.issue.delete / jira.issuelink.delete と同じ destructive 表現の方針)。
7057
+ "jira.comment.delete": {
7058
+ summaryTemplate: (p) => {
7059
+ const issue = p.issueIdOrKey ?? p.issueKey;
7060
+ const commentId = p.commentId ?? p.id;
7061
+ if (issue && commentId) return `Delete comment ${commentId} on ${issue}`;
7062
+ if (commentId) return `Delete comment ${commentId}`;
7063
+ return "";
7064
+ },
7065
+ displayFields: [
7066
+ { label: "Issue", extract: (p) => p.issueIdOrKey ?? p.issueKey },
7067
+ { label: "Comment", extract: (p) => p.commentId ?? p.id }
7068
+ ]
7069
+ },
6126
7070
  // AIDENTITY-65: API enricher が 'Link' label を upsert で書き換える。
6127
7071
  "jira.issuelink.delete": {
6128
7072
  summaryTemplate: (p) => {
@@ -6133,24 +7077,99 @@ var ACTION_DISPLAY_CONFIGS = {
6133
7077
  displayFields: [
6134
7078
  { key: "linkId", label: "Link" }
6135
7079
  ]
7080
+ },
7081
+ // AIDENTITY-83: email / displayName から accountId を解決する read action。
7082
+ "jira.user.search": {
7083
+ summaryTemplate: (p) => {
7084
+ if (p.query) return `Search users: ${String(p.query)}`;
7085
+ return "";
7086
+ },
7087
+ displayFields: [
7088
+ { key: "query", label: "Query" },
7089
+ { key: "maxResults", label: "Max Results" }
7090
+ ]
7091
+ },
7092
+ // ─── Agent Inbox ───
7093
+ "inbox.send": {
7094
+ summaryTemplate: (p) => {
7095
+ const parts = [];
7096
+ if (p.to) parts.push(`To: ${p.to}`);
7097
+ if (p.taskType) parts.push(`Task: ${p.taskType}`);
7098
+ return parts.join(", ");
7099
+ },
7100
+ displayFields: [
7101
+ { key: "to", label: "To" },
7102
+ { key: "taskType", label: "Task" },
7103
+ { key: "message", label: "Message" }
7104
+ ]
7105
+ },
7106
+ "inbox.respond": {
7107
+ summaryTemplate: (p) => {
7108
+ const parts = [];
7109
+ if (p.action) parts.push(String(p.action));
7110
+ if (p.id) parts.push(`#${p.id}`);
7111
+ return parts.join(" ");
7112
+ },
7113
+ displayFields: [
7114
+ { key: "id", label: "Item" },
7115
+ { key: "action", label: "Action" }
7116
+ ]
7117
+ },
7118
+ "inbox.check": {
7119
+ summaryTemplate: (p) => {
7120
+ const parts = [];
7121
+ if (p.status) parts.push(`Status: ${p.status}`);
7122
+ if (Array.isArray(p.types) && p.types.length > 0) parts.push(`Types: ${p.types.join(", ")}`);
7123
+ return parts.join(", ");
7124
+ },
7125
+ displayFields: [
7126
+ { key: "status", label: "Status" },
7127
+ { key: "types", label: "Types" }
7128
+ ]
7129
+ },
7130
+ "inbox.checkByToken": {
7131
+ summaryTemplate: (p) => p.token ? `Token: ${p.token}` : "",
7132
+ displayFields: [
7133
+ { key: "token", label: "Token" }
7134
+ ]
7135
+ },
7136
+ "inbox.complete": {
7137
+ summaryTemplate: (p) => p.id ? `Complete #${p.id}` : "",
7138
+ displayFields: [
7139
+ { key: "id", label: "Item" }
7140
+ ]
6136
7141
  }
6137
7142
  };
6138
7143
  function truncate(text, maxLength) {
6139
7144
  if (text.length <= maxLength) return text;
6140
7145
  return text.slice(0, maxLength - 3) + "...";
6141
7146
  }
6142
- function formatValue(value) {
7147
+ function formatCalendarTime(value) {
7148
+ if (value && typeof value === "object" && !Array.isArray(value)) {
7149
+ const obj = value;
7150
+ if (obj.dateTime) {
7151
+ return obj.timeZone ? `${obj.dateTime} (${obj.timeZone})` : String(obj.dateTime);
7152
+ }
7153
+ if (obj.date) return String(obj.date);
7154
+ }
7155
+ return String(value);
7156
+ }
7157
+ function formatValueFull(value) {
6143
7158
  if (value === void 0) return "";
6144
7159
  if (value === null) return "(unset)";
6145
7160
  if (Array.isArray(value)) {
6146
- return value.map((item) => {
7161
+ const parts = value.map((item) => {
6147
7162
  if (item && typeof item === "object") {
6148
7163
  const email = item.email;
6149
7164
  if (email) return String(email);
6150
- return JSON.stringify(item);
7165
+ return JSON.stringify(item, null, 2);
6151
7166
  }
6152
7167
  return String(item);
6153
- }).join(", ");
7168
+ });
7169
+ const hasMultiline = parts.some((p) => p.includes("\n"));
7170
+ const joinedShort = parts.join(", ");
7171
+ if (hasMultiline || joinedShort.length > 80) return parts.join("\n");
7172
+ return joinedShort;
6154
7173
  }
6155
7174
  if (typeof value === "object") {
6156
7175
  const obj = value;
@@ -6159,33 +7178,118 @@ function formatValue(value) {
6159
7178
  }
6160
7179
  if (obj.date) return String(obj.date);
6161
7180
  if (obj.type === "doc" && Array.isArray(obj.content)) {
6162
- const firstText = extractFirstAdfText(obj.content);
6163
- if (firstText) {
6164
- const moreCount = obj.content.length - 1;
6165
- const more = moreCount > 0 ? ` \u2026 (+${moreCount} block${moreCount > 1 ? "s" : ""})` : "";
6166
- return `${firstText}${more}`;
6167
- }
6168
- return "(ADF document)";
7181
+ const rendered = renderAdfDocument(obj.content).trim();
7182
+ if (rendered) return rendered;
7183
+ if (obj.content.length > 0) return JSON.stringify(value, null, 2);
7184
+ return "";
6169
7185
  }
6170
- return JSON.stringify(value);
7186
+ return JSON.stringify(value, null, 2);
6171
7187
  }
6172
7188
  return String(value);
6173
7189
  }
6174
- function extractFirstAdfText(nodes) {
7190
+ function renderAdfDocument(nodes, indent = "") {
7191
+ const lines = [];
6175
7192
  for (const node of nodes) {
6176
7193
  if (!node || typeof node !== "object") continue;
6177
7194
  const n = node;
6178
- if (n.type === "paragraph" || n.type === "heading") {
6179
- const inner = n.content ?? [];
6180
- for (const child of inner) {
6181
- if (child && typeof child === "object") {
6182
- const c = child;
6183
- if (c.type === "text" && typeof c.text === "string") return c.text;
7195
+ const type = n.type;
7196
+ const content = n.content ?? [];
7197
+ switch (type) {
7198
+ case "paragraph": {
7199
+ lines.push(indent + renderAdfInline(content));
7200
+ break;
7201
+ }
7202
+ case "heading": {
7203
+ const level = Number(n.attrs?.level) || 1;
7204
+ lines.push(indent + "#".repeat(level) + " " + renderAdfInline(content));
7205
+ break;
7206
+ }
7207
+ case "bulletList":
7208
+ case "orderedList": {
7209
+ const ordered = type === "orderedList";
7210
+ let orderedCounter = 0;
7211
+ content.forEach((item) => {
7212
+ if (!item || typeof item !== "object") return;
7213
+ const li = item;
7214
+ const liContent = li.content ?? [];
7215
+ orderedCounter++;
7216
+ const marker = ordered ? `${orderedCounter}. ` : "- ";
7217
+ const inner = renderAdfDocument(liContent, indent + " ");
7218
+ const innerLines = inner.split("\n");
7219
+ const firstTrimmed = innerLines.length > 0 ? innerLines[0].slice((indent + " ").length) : "";
7220
+ lines.push(indent + marker + firstTrimmed);
7221
+ for (let i = 1; i < innerLines.length; i++) lines.push(innerLines[i]);
7222
+ });
7223
+ break;
7224
+ }
7225
+ case "codeBlock": {
7226
+ lines.push(indent + renderAdfInline(content));
7227
+ break;
7228
+ }
7229
+ case "blockquote": {
7230
+ const inner = renderAdfDocument(content, indent);
7231
+ if (inner) {
7232
+ for (const l of inner.split("\n")) lines.push(indent + "> " + l.slice(indent.length));
6184
7233
  }
7234
+ break;
7235
+ }
7236
+ case "panel": {
7237
+ const panelType = n.attrs?.panelType;
7238
+ if (panelType) lines.push(indent + `[panel:${String(panelType)}]`);
7239
+ const panelInner = renderAdfDocument(content, indent);
7240
+ if (panelInner) lines.push(panelInner);
7241
+ break;
7242
+ }
7243
+ case "rule": {
7244
+ lines.push(indent + "---");
7245
+ break;
7246
+ }
7247
+ default: {
7248
+ if (content.length > 0) {
7249
+ const inner = renderAdfDocument(content, indent);
7250
+ if (inner) lines.push(inner);
7251
+ } else {
7252
+ const inline = renderAdfInline([n]);
7253
+ if (inline) lines.push(indent + inline);
7254
+ }
7255
+ break;
6185
7256
  }
6186
7257
  }
6187
7258
  }
6188
- return "";
7259
+ return lines.join("\n");
7260
+ }
7261
+ function renderAdfInline(nodes) {
7262
+ let out = "";
7263
+ for (const node of nodes) {
7264
+ if (!node || typeof node !== "object") continue;
7265
+ const n = node;
7266
+ const attrs = n.attrs ?? {};
7267
+ switch (n.type) {
7268
+ case "text":
7269
+ if (typeof n.text === "string") out += n.text;
7270
+ break;
7271
+ case "hardBreak":
7272
+ out += "\n";
7273
+ break;
7274
+ case "mention":
7275
+ out += String(attrs.text ?? attrs.id ?? "@mention");
7276
+ break;
7277
+ case "emoji":
7278
+ out += String(attrs.text ?? attrs.shortName ?? "");
7279
+ break;
7280
+ case "inlineCard":
7281
+ out += String(attrs.url ?? "");
7282
+ break;
7283
+ default:
7284
+ if (Array.isArray(n.content)) {
7285
+ out += renderAdfInline(n.content);
7286
+ } else if (typeof attrs.text === "string") {
7287
+ out += attrs.text;
7288
+ }
7289
+ break;
7290
+ }
7291
+ }
7292
+ return out;
6189
7293
  }
6190
7294
  var ACTION_PARAMS_MAX_SIZE = 1e4;
6191
7295
  function generateActionSummary(action, params, maxLength = 50) {
@@ -6209,11 +7313,11 @@ function generateActionParamsDisplay(action, params) {
6209
7313
  return config.displayFields.map((f) => {
6210
7314
  const raw = f.extract ? f.extract(params) : f.key ? params[f.key] : void 0;
6211
7315
  return { label: f.label, raw };
6212
- }).filter((item) => item.raw !== void 0).map((item) => ({ label: item.label, value: formatValue(item.raw) }));
7316
+ }).filter((item) => item.raw !== void 0).map((item) => ({ label: item.label, value: formatValueFull(item.raw) }));
6213
7317
  }
6214
- return Object.entries(params).filter(([, v]) => v !== void 0 && v !== null).slice(0, 3).map(([key, val]) => ({
7318
+ return Object.entries(params).filter(([, v]) => v !== void 0 && v !== null).map(([key, val]) => ({
6215
7319
  label: key,
6216
- value: formatValue(val)
7320
+ value: formatValueFull(val)
6217
7321
  }));
6218
7322
  }
6219
7323
 
@@ -6836,6 +7940,7 @@ var version = "0.0.1";
6836
7940
  sha256Hex,
6837
7941
  signJWT,
6838
7942
  signRequest,
7943
+ validateActionInput,
6839
7944
  validateRegistryObject,
6840
7945
  vcStatusToCredentialStatus,
6841
7946
  verifyJWT,