@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.mjs CHANGED
@@ -2753,6 +2753,13 @@ var GrantResourceType = /* @__PURE__ */ ((GrantResourceType2) => {
2753
2753
  GrantResourceType2["JIRA_PROJECT"] = "jira:project";
2754
2754
  GrantResourceType2["JIRA_BOARD"] = "jira:board";
2755
2755
  GrantResourceType2["JIRA_ISSUE"] = "jira:issue";
2756
+ GrantResourceType2["HUBSPOT_OBJECT"] = "hubspot:object";
2757
+ GrantResourceType2["HUBSPOT_PROPERTY"] = "hubspot:property";
2758
+ GrantResourceType2["HUBSPOT_SCHEMA"] = "hubspot:schema";
2759
+ GrantResourceType2["HUBSPOT_ASSOCIATION"] = "hubspot:association";
2760
+ GrantResourceType2["HUBSPOT_ENGAGEMENT"] = "hubspot:engagement";
2761
+ GrantResourceType2["HUBSPOT_WORKFLOW"] = "hubspot:workflow";
2762
+ GrantResourceType2["HUBSPOT_ACCOUNT"] = "hubspot:account";
2756
2763
  GrantResourceType2["OS_SECRET"] = "os:secret";
2757
2764
  GrantResourceType2["ANY"] = "*";
2758
2765
  return GrantResourceType2;
@@ -4086,6 +4093,7 @@ var CANONICAL_PROVIDERS = [
4086
4093
  "gmail",
4087
4094
  "calendar",
4088
4095
  "jira",
4096
+ "hubspot",
4089
4097
  "os"
4090
4098
  ];
4091
4099
  var PROVIDER_ALIASES = {};
@@ -4329,6 +4337,15 @@ var DummyVpVerifier = class {
4329
4337
  var ACTION_REGISTRY = {
4330
4338
  registry_version: "2025-09-28",
4331
4339
  actions: [
4340
+ // ─── Resource binding principle (high-risk CREATE actions) ───
4341
+ // A high-risk CREATE action's target_bindings.resource_id MUST bind to the
4342
+ // container/parent that already exists at approval + invoke time — never to
4343
+ // the not-yet-created resource's id (which does not exist until after the
4344
+ // call and is absent from input_schema). Cedar must resolve the resource at
4345
+ // evaluation time, and the server enforces a specific non-wildcard target,
4346
+ // so an unresolvable binding makes the action impossible to approve.
4347
+ // Examples: slack.message.post → channel, jira.issue.create → projectKey,
4348
+ // hubspot objects.batchCreate → objectType, engagements.create → type.
4332
4349
  // ─── Slack Actions ───
4333
4350
  {
4334
4351
  action: "slack.message.post",
@@ -4528,15 +4545,21 @@ var ACTION_REGISTRY = {
4528
4545
  required_relations: ["editor", "act_as"],
4529
4546
  required_scopes: ["repo", "write:issues"],
4530
4547
  capability: "github.issues.triage",
4548
+ // Schema mirrors the server contract (GitHubConnectorAdapter
4549
+ // getSupportedActions inputSchema — packages/api/src/tool/adapters/
4550
+ // github.adapter.ts): owner/repo are required params.
4531
4551
  input_schema: {
4532
4552
  type: "object",
4533
4553
  properties: {
4554
+ owner: { type: "string", minLength: 1, description: "Repository owner (username or organization)" },
4555
+ repo: { type: "string", minLength: 1, description: "Repository name" },
4534
4556
  title: { type: "string", minLength: 1 },
4535
4557
  body: { type: "string" },
4536
4558
  labels: { type: "array", items: { type: "string" } },
4537
- assignees: { type: "array", items: { type: "string" } }
4559
+ assignees: { type: "array", items: { type: "string" } },
4560
+ milestone: { type: "integer", minimum: 1, description: "Milestone number to associate with the issue" }
4538
4561
  },
4539
- required: ["title"],
4562
+ required: ["owner", "repo", "title"],
4540
4563
  additionalProperties: false
4541
4564
  },
4542
4565
  constraints: { rate_bucket: "github.write" },
@@ -4553,9 +4576,13 @@ var ACTION_REGISTRY = {
4553
4576
  required_relations: ["viewer", "editor", "admin", "owner"],
4554
4577
  required_scopes: ["repo", "read:issues"],
4555
4578
  capability: "github.read.basic",
4579
+ // Schema mirrors the server contract (GitHubConnectorAdapter):
4580
+ // owner/repo are required params.
4556
4581
  input_schema: {
4557
4582
  type: "object",
4558
4583
  properties: {
4584
+ owner: { type: "string", minLength: 1, description: "Repository owner (username or organization)" },
4585
+ repo: { type: "string", minLength: 1, description: "Repository name" },
4559
4586
  state: { type: "string", enum: ["open", "closed", "all"] },
4560
4587
  labels: { type: "string" },
4561
4588
  sort: { type: "string", enum: ["created", "updated", "comments"] },
@@ -4563,6 +4590,7 @@ var ACTION_REGISTRY = {
4563
4590
  per_page: { type: "integer", minimum: 1, maximum: 100 },
4564
4591
  page: { type: "integer", minimum: 1 }
4565
4592
  },
4593
+ required: ["owner", "repo"],
4566
4594
  additionalProperties: false
4567
4595
  },
4568
4596
  constraints: { rate_bucket: "github.read" },
@@ -4579,12 +4607,17 @@ var ACTION_REGISTRY = {
4579
4607
  required_relations: ["viewer", "editor", "admin", "owner"],
4580
4608
  required_scopes: ["repo", "read:issues"],
4581
4609
  capability: "github.read.basic",
4610
+ // Schema mirrors the server contract (GitHubConnectorAdapter):
4611
+ // owner/repo required, camelCase issueNumber (the adapter reads
4612
+ // params.issueNumber — snake_case issue_number was a drift).
4582
4613
  input_schema: {
4583
4614
  type: "object",
4584
4615
  properties: {
4585
- issue_number: { type: "integer", minimum: 1 }
4616
+ owner: { type: "string", minLength: 1, description: "Repository owner (username or organization)" },
4617
+ repo: { type: "string", minLength: 1, description: "Repository name" },
4618
+ issueNumber: { type: "integer", minimum: 1, description: "Issue number" }
4586
4619
  },
4587
- required: ["issue_number"],
4620
+ required: ["owner", "repo", "issueNumber"],
4588
4621
  additionalProperties: false
4589
4622
  },
4590
4623
  constraints: { rate_bucket: "github.read" },
@@ -4601,17 +4634,22 @@ var ACTION_REGISTRY = {
4601
4634
  required_relations: ["editor", "act_as"],
4602
4635
  required_scopes: ["repo", "write:issues"],
4603
4636
  capability: "github.issues.triage",
4637
+ // Schema mirrors the server contract (GitHubConnectorAdapter):
4638
+ // owner/repo required, camelCase issueNumber (the adapter reads
4639
+ // params.issueNumber — snake_case issue_number was a drift).
4604
4640
  input_schema: {
4605
4641
  type: "object",
4606
4642
  properties: {
4607
- issue_number: { type: "integer", minimum: 1 },
4643
+ owner: { type: "string", minLength: 1, description: "Repository owner (username or organization)" },
4644
+ repo: { type: "string", minLength: 1, description: "Repository name" },
4645
+ issueNumber: { type: "integer", minimum: 1, description: "Issue number to update" },
4608
4646
  title: { type: "string" },
4609
4647
  body: { type: "string" },
4610
4648
  state: { type: "string", enum: ["open", "closed"] },
4611
4649
  labels: { type: "array", items: { type: "string" } },
4612
4650
  assignees: { type: "array", items: { type: "string" } }
4613
4651
  },
4614
- required: ["issue_number"],
4652
+ required: ["owner", "repo", "issueNumber"],
4615
4653
  additionalProperties: false
4616
4654
  },
4617
4655
  constraints: { rate_bucket: "github.write" },
@@ -4903,7 +4941,9 @@ var ACTION_REGISTRY = {
4903
4941
  }
4904
4942
  },
4905
4943
  attendees: { type: "array", description: "List of attendee objects with email field", items: { type: "object", properties: { email: { type: "string" } } } },
4906
- location: { type: "string", description: "Event location" }
4944
+ location: { type: "string", description: "Event location" },
4945
+ addMeet: { type: "boolean", description: "Opt-in: attach a Google Meet link (default: false)" },
4946
+ meetRequestId: { type: "string", description: "Stable idempotency key for the Meet request (used only when addMeet is true)" }
4907
4947
  },
4908
4948
  required: ["summary", "start", "end"],
4909
4949
  additionalProperties: false
@@ -4951,7 +4991,9 @@ var ACTION_REGISTRY = {
4951
4991
  }
4952
4992
  },
4953
4993
  attendees: { type: "array", description: "List of attendee objects with email field", items: { type: "object", properties: { email: { type: "string" } } } },
4954
- location: { type: "string", description: "Event location" }
4994
+ location: { type: "string", description: "Event location" },
4995
+ addMeet: { type: "boolean", description: "Opt-in: attach a Google Meet link (default: false)" },
4996
+ meetRequestId: { type: "string", description: "Stable idempotency key for the Meet request (used only when addMeet is true)" }
4955
4997
  },
4956
4998
  required: ["eventId"],
4957
4999
  additionalProperties: false
@@ -5159,7 +5201,13 @@ var ACTION_REGISTRY = {
5159
5201
  properties: {
5160
5202
  projectKey: { type: "string", minLength: 1 },
5161
5203
  summary: { type: "string", minLength: 1 },
5162
- description: { type: "string" },
5204
+ description: {
5205
+ oneOf: [
5206
+ { type: "string", description: "Plain text description." },
5207
+ { type: "object", description: 'ADF document object for rich formatting: {type:"doc", version:1, content:[...]}.' }
5208
+ ],
5209
+ description: 'Issue description. Pass a plain string, OR an ADF document object ({type:"doc",version:1,content:[...]}) for rich formatting (headings, lists, code, links).'
5210
+ },
5163
5211
  issueTypeName: { type: "string", minLength: 1, description: "Issue type name (default: Task)" },
5164
5212
  priority: { type: "string" },
5165
5213
  assigneeAccountId: { type: "string" },
@@ -5187,7 +5235,13 @@ var ACTION_REGISTRY = {
5187
5235
  properties: {
5188
5236
  issueIdOrKey: { type: "string", minLength: 1 },
5189
5237
  summary: { type: "string" },
5190
- description: { type: "string" },
5238
+ description: {
5239
+ oneOf: [
5240
+ { type: "string", description: "Plain text description." },
5241
+ { type: "object", description: 'ADF document object for rich formatting: {type:"doc", version:1, content:[...]}.' }
5242
+ ],
5243
+ description: 'Issue description. Pass a plain string, OR an ADF document object ({type:"doc",version:1,content:[...]}) for rich formatting (headings, lists, code, links).'
5244
+ },
5191
5245
  priority: { type: "string" },
5192
5246
  assigneeAccountId: { type: "string" },
5193
5247
  labels: { type: "array", items: { type: "string" } }
@@ -5235,7 +5289,13 @@ var ACTION_REGISTRY = {
5235
5289
  type: "object",
5236
5290
  properties: {
5237
5291
  issueIdOrKey: { type: "string", minLength: 1 },
5238
- body: { type: "string", minLength: 1 }
5292
+ body: {
5293
+ oneOf: [
5294
+ { type: "string", minLength: 1, description: "Plain text comment body." },
5295
+ { type: "object", description: 'ADF document object for rich formatting: {type:"doc", version:1, content:[...]}.' }
5296
+ ],
5297
+ description: 'Comment body. Pass a plain string, OR an ADF document object ({type:"doc",version:1,content:[...]}) for rich formatting (headings, lists, code, links).'
5298
+ }
5239
5299
  },
5240
5300
  required: ["issueIdOrKey", "body"],
5241
5301
  additionalProperties: false
@@ -5249,6 +5309,34 @@ var ACTION_REGISTRY = {
5249
5309
  },
5250
5310
  version: "1.0.0"
5251
5311
  },
5312
+ {
5313
+ // AIDENTITY-66: delete a comment from a Jira issue. high-risk destructive
5314
+ // write — mirrors jira.issue.delete (admin/owner/act_as) but resource_type
5315
+ // は jira.comment.create と同じ jira:project (issue から project を derive)。
5316
+ action: "jira.comment.delete",
5317
+ resource_type: "jira:project",
5318
+ required_relations: ["admin", "owner", "act_as"],
5319
+ required_scopes: ["write:jira-work"],
5320
+ capability: "jira.write.basic",
5321
+ input_schema: {
5322
+ type: "object",
5323
+ properties: {
5324
+ issueIdOrKey: { type: "string", minLength: 1 },
5325
+ commentId: { type: "string", minLength: 1, description: "Comment id (from jira.comment.read)" }
5326
+ },
5327
+ required: ["issueIdOrKey", "commentId"],
5328
+ additionalProperties: false
5329
+ },
5330
+ constraints: { rate_bucket: "jira.write" },
5331
+ effects: ["Delete:Comment"],
5332
+ // high: deleting a comment is irreversible and visible to all project members,
5333
+ // consistent with jira.issue.delete / jira.comment.create.
5334
+ risk: "high",
5335
+ target_bindings: {
5336
+ resource_id: { source: "param", param: "issueIdOrKey", fallback_param: "issueKey", derive: "project_key" }
5337
+ },
5338
+ version: "1.0.0"
5339
+ },
5252
5340
  {
5253
5341
  action: "jira.comment.read",
5254
5342
  resource_type: "jira:project",
@@ -5414,6 +5502,42 @@ var ACTION_REGISTRY = {
5414
5502
  },
5415
5503
  version: "1.0.0"
5416
5504
  },
5505
+ {
5506
+ // AIDENTITY-83: email / displayName から accountId を解決する read action。
5507
+ // query は resource id ではなく検索語なので target_bindings は付けず
5508
+ // (jira.project.read 等の unscoped read と同様)、type-only match で評価する。
5509
+ action: "jira.user.search",
5510
+ resource_type: "jira:user",
5511
+ required_relations: ["viewer", "editor", "admin", "owner"],
5512
+ required_scopes: ["read:jira-user"],
5513
+ capability: "jira.read.basic",
5514
+ input_schema: {
5515
+ type: "object",
5516
+ properties: {
5517
+ query: {
5518
+ type: "string",
5519
+ minLength: 1,
5520
+ description: "Matched against displayName and emailAddress (prefix match). Pass an email address to resolve its accountId."
5521
+ },
5522
+ maxResults: {
5523
+ type: "integer",
5524
+ minimum: 1,
5525
+ maximum: 50,
5526
+ description: "Max users to return (default 10)"
5527
+ }
5528
+ },
5529
+ required: ["query"],
5530
+ additionalProperties: false
5531
+ },
5532
+ constraints: { rate_bucket: "jira.read" },
5533
+ effects: ["Read:User"],
5534
+ risk: "low",
5535
+ // query は resource id ではないので unscoped。required: false で type-only match。
5536
+ target_bindings: {
5537
+ resource_id: { source: "param", param: "query", required: false }
5538
+ },
5539
+ version: "1.0.0"
5540
+ },
5417
5541
  // ─── OS Actions (Local) ───
5418
5542
  {
5419
5543
  action: "os.secret.read",
@@ -5491,6 +5615,665 @@ var ACTION_REGISTRY = {
5491
5615
  resource_id: { source: "param", param: "command" }
5492
5616
  },
5493
5617
  version: "1.0.0"
5618
+ },
5619
+ // ─── HubSpot CRM Objects (objectType 汎用) ───
5620
+ // 公式 MCP (@hubspot/mcp-server) のツール集合を写像。object 系は objectType
5621
+ // パラメータ化された汎用エンドポイント。scope は objectType ごとに HubSpot 側で
5622
+ // 実行時強制されるため、required_scopes には代表 scope を宣言する (実際の許可範囲は
5623
+ // DEFAULT_SCOPES の固定 union)。
5624
+ {
5625
+ action: "hubspot.crm.objects.list",
5626
+ resource_type: "hubspot:object",
5627
+ required_relations: ["viewer", "editor", "admin", "owner"],
5628
+ required_scopes: ["crm.objects.contacts.read"],
5629
+ capability: "hubspot.crm.read",
5630
+ input_schema: {
5631
+ type: "object",
5632
+ properties: {
5633
+ objectType: { type: "string", description: "CRM object type (e.g. contacts, companies, deals) or custom object type ID" },
5634
+ limit: { type: "integer", minimum: 1, maximum: 100 },
5635
+ after: { type: "string" },
5636
+ properties: { type: "array", items: { type: "string" } },
5637
+ archived: { type: "boolean" }
5638
+ },
5639
+ required: ["objectType"],
5640
+ additionalProperties: false
5641
+ },
5642
+ constraints: { rate_bucket: "hubspot.read" },
5643
+ effects: ["Read:CrmObject"],
5644
+ risk: "low",
5645
+ target_bindings: {
5646
+ resource_id: { source: "param", param: "objectType" }
5647
+ },
5648
+ version: "1.0.0"
5649
+ },
5650
+ {
5651
+ action: "hubspot.crm.objects.search",
5652
+ resource_type: "hubspot:object",
5653
+ required_relations: ["viewer", "editor", "admin", "owner"],
5654
+ required_scopes: ["crm.objects.contacts.read"],
5655
+ capability: "hubspot.crm.read",
5656
+ input_schema: {
5657
+ type: "object",
5658
+ properties: {
5659
+ objectType: { type: "string", description: "CRM object type or custom object type ID" },
5660
+ query: { type: "string", maxLength: 3e3 },
5661
+ filterGroups: { type: "array" },
5662
+ properties: { type: "array", items: { type: "string" } },
5663
+ sorts: { type: "array", items: { type: "string" } },
5664
+ limit: { type: "integer", minimum: 1, maximum: 100 },
5665
+ after: { type: "string" }
5666
+ },
5667
+ required: ["objectType"],
5668
+ additionalProperties: false
5669
+ },
5670
+ constraints: { rate_bucket: "hubspot.read" },
5671
+ effects: ["Read:CrmObject"],
5672
+ risk: "low",
5673
+ target_bindings: {
5674
+ resource_id: { source: "param", param: "objectType" }
5675
+ },
5676
+ version: "1.0.0"
5677
+ },
5678
+ {
5679
+ action: "hubspot.crm.objects.batchRead",
5680
+ resource_type: "hubspot:object",
5681
+ required_relations: ["viewer", "editor", "admin", "owner"],
5682
+ required_scopes: ["crm.objects.contacts.read"],
5683
+ capability: "hubspot.crm.read",
5684
+ input_schema: {
5685
+ type: "object",
5686
+ properties: {
5687
+ objectType: { type: "string", description: "CRM object type or custom object type ID" },
5688
+ inputs: {
5689
+ type: "array",
5690
+ minItems: 1,
5691
+ items: { type: "object", properties: { id: { type: "string" } }, required: ["id"], additionalProperties: false }
5692
+ },
5693
+ properties: { type: "array", items: { type: "string" } },
5694
+ idProperty: { type: "string" }
5695
+ },
5696
+ required: ["objectType", "inputs"],
5697
+ additionalProperties: false
5698
+ },
5699
+ constraints: { rate_bucket: "hubspot.read" },
5700
+ effects: ["Read:CrmObject"],
5701
+ risk: "low",
5702
+ target_bindings: {
5703
+ resource_id: { source: "param", param: "objectType" }
5704
+ },
5705
+ version: "1.0.0"
5706
+ },
5707
+ {
5708
+ action: "hubspot.crm.objects.batchCreate",
5709
+ resource_type: "hubspot:object",
5710
+ required_relations: ["editor", "act_as"],
5711
+ required_scopes: ["crm.objects.contacts.write"],
5712
+ capability: "hubspot.crm.write",
5713
+ input_schema: {
5714
+ type: "object",
5715
+ properties: {
5716
+ objectType: { type: "string", description: "CRM object type or custom object type ID" },
5717
+ inputs: {
5718
+ type: "array",
5719
+ minItems: 1,
5720
+ items: {
5721
+ type: "object",
5722
+ properties: { properties: { type: "object" }, associations: { type: "array" } },
5723
+ required: ["properties"],
5724
+ additionalProperties: false
5725
+ }
5726
+ }
5727
+ },
5728
+ required: ["objectType", "inputs"],
5729
+ additionalProperties: false
5730
+ },
5731
+ constraints: { rate_bucket: "hubspot.write" },
5732
+ effects: ["Create:CrmObject"],
5733
+ risk: "high",
5734
+ target_bindings: {
5735
+ resource_id: { source: "param", param: "objectType" }
5736
+ },
5737
+ version: "1.0.0"
5738
+ },
5739
+ {
5740
+ action: "hubspot.crm.objects.batchUpdate",
5741
+ resource_type: "hubspot:object",
5742
+ required_relations: ["editor", "act_as"],
5743
+ required_scopes: ["crm.objects.contacts.write"],
5744
+ capability: "hubspot.crm.write",
5745
+ input_schema: {
5746
+ type: "object",
5747
+ properties: {
5748
+ objectType: { type: "string", description: "CRM object type or custom object type ID" },
5749
+ inputs: {
5750
+ type: "array",
5751
+ minItems: 1,
5752
+ items: {
5753
+ type: "object",
5754
+ properties: { id: { type: "string" }, properties: { type: "object" } },
5755
+ required: ["id", "properties"],
5756
+ additionalProperties: false
5757
+ }
5758
+ }
5759
+ },
5760
+ required: ["objectType", "inputs"],
5761
+ additionalProperties: false
5762
+ },
5763
+ constraints: { rate_bucket: "hubspot.write" },
5764
+ effects: ["Update:CrmObject"],
5765
+ risk: "high",
5766
+ target_bindings: {
5767
+ resource_id: { source: "param", param: "objectType" }
5768
+ },
5769
+ version: "1.0.0"
5770
+ },
5771
+ {
5772
+ action: "hubspot.crm.schemas.get",
5773
+ resource_type: "hubspot:schema",
5774
+ required_relations: ["viewer", "editor", "admin", "owner"],
5775
+ required_scopes: ["crm.schemas.custom.read"],
5776
+ capability: "hubspot.crm.read",
5777
+ input_schema: {
5778
+ type: "object",
5779
+ properties: {},
5780
+ additionalProperties: false
5781
+ },
5782
+ constraints: { rate_bucket: "hubspot.read" },
5783
+ effects: ["Read:CrmSchema"],
5784
+ risk: "low",
5785
+ target_bindings: {
5786
+ resource_id: { source: "param", param: "objectType", required: false }
5787
+ },
5788
+ version: "1.0.0"
5789
+ },
5790
+ // ─── HubSpot Properties ───
5791
+ {
5792
+ action: "hubspot.crm.properties.list",
5793
+ resource_type: "hubspot:property",
5794
+ required_relations: ["viewer", "editor", "admin", "owner"],
5795
+ required_scopes: ["crm.schemas.contacts.read"],
5796
+ capability: "hubspot.crm.read",
5797
+ input_schema: {
5798
+ type: "object",
5799
+ properties: {
5800
+ objectType: { type: "string", description: "CRM object type or custom object type ID" },
5801
+ archived: { type: "boolean" }
5802
+ },
5803
+ required: ["objectType"],
5804
+ additionalProperties: false
5805
+ },
5806
+ constraints: { rate_bucket: "hubspot.read" },
5807
+ effects: ["Read:CrmProperty"],
5808
+ risk: "low",
5809
+ target_bindings: { resource_id: { source: "param", param: "objectType" } },
5810
+ version: "1.0.0"
5811
+ },
5812
+ {
5813
+ action: "hubspot.crm.properties.get",
5814
+ resource_type: "hubspot:property",
5815
+ required_relations: ["viewer", "editor", "admin", "owner"],
5816
+ required_scopes: ["crm.schemas.contacts.read"],
5817
+ capability: "hubspot.crm.read",
5818
+ input_schema: {
5819
+ type: "object",
5820
+ properties: {
5821
+ objectType: { type: "string", description: "CRM object type or custom object type ID" },
5822
+ propertyName: { type: "string", description: "Internal property name" }
5823
+ },
5824
+ required: ["objectType", "propertyName"],
5825
+ additionalProperties: false
5826
+ },
5827
+ constraints: { rate_bucket: "hubspot.read" },
5828
+ effects: ["Read:CrmProperty"],
5829
+ risk: "low",
5830
+ target_bindings: { resource_id: { source: "param", param: "objectType" } },
5831
+ version: "1.0.0"
5832
+ },
5833
+ {
5834
+ action: "hubspot.crm.properties.create",
5835
+ resource_type: "hubspot:property",
5836
+ required_relations: ["editor", "act_as"],
5837
+ required_scopes: ["crm.schemas.contacts.write"],
5838
+ capability: "hubspot.crm.write",
5839
+ input_schema: {
5840
+ type: "object",
5841
+ properties: {
5842
+ objectType: { type: "string", description: "CRM object type or custom object type ID" },
5843
+ name: { type: "string" },
5844
+ label: { type: "string" },
5845
+ type: { type: "string" },
5846
+ fieldType: { type: "string" },
5847
+ groupName: { type: "string" },
5848
+ description: { type: "string" },
5849
+ options: { type: "array" }
5850
+ },
5851
+ required: ["objectType", "name", "label", "type", "fieldType", "groupName"],
5852
+ additionalProperties: false
5853
+ },
5854
+ constraints: { rate_bucket: "hubspot.write" },
5855
+ effects: ["Create:CrmProperty"],
5856
+ risk: "high",
5857
+ target_bindings: { resource_id: { source: "param", param: "objectType" } },
5858
+ version: "1.0.0"
5859
+ },
5860
+ {
5861
+ action: "hubspot.crm.properties.update",
5862
+ resource_type: "hubspot:property",
5863
+ required_relations: ["editor", "act_as"],
5864
+ required_scopes: ["crm.schemas.contacts.write"],
5865
+ capability: "hubspot.crm.write",
5866
+ input_schema: {
5867
+ type: "object",
5868
+ properties: {
5869
+ objectType: { type: "string", description: "CRM object type or custom object type ID" },
5870
+ propertyName: { type: "string" },
5871
+ label: { type: "string" },
5872
+ type: { type: "string" },
5873
+ fieldType: { type: "string" },
5874
+ groupName: { type: "string" },
5875
+ description: { type: "string" },
5876
+ options: { type: "array" }
5877
+ },
5878
+ required: ["objectType", "propertyName"],
5879
+ additionalProperties: false
5880
+ },
5881
+ constraints: { rate_bucket: "hubspot.write" },
5882
+ effects: ["Update:CrmProperty"],
5883
+ risk: "high",
5884
+ target_bindings: { resource_id: { source: "param", param: "objectType" } },
5885
+ version: "1.0.0"
5886
+ },
5887
+ // ─── HubSpot Associations (v4) ───
5888
+ {
5889
+ action: "hubspot.crm.associations.list",
5890
+ resource_type: "hubspot:association",
5891
+ required_relations: ["viewer", "editor", "admin", "owner"],
5892
+ required_scopes: ["crm.objects.contacts.read"],
5893
+ capability: "hubspot.crm.read",
5894
+ input_schema: {
5895
+ type: "object",
5896
+ properties: {
5897
+ objectType: { type: "string" },
5898
+ objectId: { type: "string" },
5899
+ toObjectType: { type: "string" },
5900
+ after: { type: "string" },
5901
+ limit: { type: "integer", minimum: 1, maximum: 100 }
5902
+ },
5903
+ required: ["objectType", "objectId", "toObjectType"],
5904
+ additionalProperties: false
5905
+ },
5906
+ constraints: { rate_bucket: "hubspot.read" },
5907
+ effects: ["Read:CrmAssociation"],
5908
+ risk: "low",
5909
+ target_bindings: { resource_id: { source: "param", param: "objectType" } },
5910
+ version: "1.0.0"
5911
+ },
5912
+ {
5913
+ action: "hubspot.crm.associations.getDefinitions",
5914
+ resource_type: "hubspot:association",
5915
+ required_relations: ["viewer", "editor", "admin", "owner"],
5916
+ required_scopes: ["crm.objects.contacts.read"],
5917
+ capability: "hubspot.crm.read",
5918
+ input_schema: {
5919
+ type: "object",
5920
+ properties: {
5921
+ fromObjectType: { type: "string" },
5922
+ toObjectType: { type: "string" }
5923
+ },
5924
+ required: ["fromObjectType", "toObjectType"],
5925
+ additionalProperties: false
5926
+ },
5927
+ constraints: { rate_bucket: "hubspot.read" },
5928
+ effects: ["Read:CrmAssociation"],
5929
+ risk: "low",
5930
+ target_bindings: { resource_id: { source: "param", param: "fromObjectType" } },
5931
+ version: "1.0.0"
5932
+ },
5933
+ {
5934
+ action: "hubspot.crm.associations.batchCreate",
5935
+ resource_type: "hubspot:association",
5936
+ required_relations: ["editor", "act_as"],
5937
+ required_scopes: ["crm.objects.contacts.write"],
5938
+ capability: "hubspot.crm.write",
5939
+ input_schema: {
5940
+ type: "object",
5941
+ properties: {
5942
+ fromObjectType: { type: "string" },
5943
+ toObjectType: { type: "string" },
5944
+ inputs: { type: "array", minItems: 1 }
5945
+ },
5946
+ required: ["fromObjectType", "toObjectType", "inputs"],
5947
+ additionalProperties: false
5948
+ },
5949
+ constraints: { rate_bucket: "hubspot.write" },
5950
+ effects: ["Create:CrmAssociation"],
5951
+ risk: "high",
5952
+ target_bindings: { resource_id: { source: "param", param: "fromObjectType" } },
5953
+ version: "1.0.0"
5954
+ },
5955
+ // ─── HubSpot Engagements (legacy v1: NOTE / TASK) ───
5956
+ {
5957
+ action: "hubspot.crm.engagements.get",
5958
+ resource_type: "hubspot:engagement",
5959
+ required_relations: ["viewer", "editor", "admin", "owner"],
5960
+ required_scopes: ["crm.objects.contacts.read"],
5961
+ capability: "hubspot.crm.read",
5962
+ input_schema: {
5963
+ type: "object",
5964
+ properties: { engagementId: { type: "string" } },
5965
+ required: ["engagementId"],
5966
+ additionalProperties: false
5967
+ },
5968
+ constraints: { rate_bucket: "hubspot.read" },
5969
+ effects: ["Read:CrmEngagement"],
5970
+ risk: "low",
5971
+ target_bindings: { resource_id: { source: "param", param: "engagementId" } },
5972
+ version: "1.0.0"
5973
+ },
5974
+ {
5975
+ action: "hubspot.crm.engagements.create",
5976
+ resource_type: "hubspot:engagement",
5977
+ required_relations: ["editor", "act_as"],
5978
+ required_scopes: ["crm.objects.contacts.write"],
5979
+ capability: "hubspot.crm.write",
5980
+ input_schema: {
5981
+ type: "object",
5982
+ properties: {
5983
+ type: { type: "string", enum: ["NOTE", "TASK"] },
5984
+ ownerId: { type: "number" },
5985
+ timestamp: { type: "number" },
5986
+ associations: { type: "object" },
5987
+ metadata: { type: "object" }
5988
+ },
5989
+ required: ["type", "ownerId", "metadata"],
5990
+ additionalProperties: false
5991
+ },
5992
+ constraints: { rate_bucket: "hubspot.write" },
5993
+ effects: ["Create:CrmEngagement"],
5994
+ risk: "high",
5995
+ // Bind to the engagement type (NOTE/TASK) as the container that exists at
5996
+ // call time, consistent with other create actions (see CREATE-binding note above).
5997
+ target_bindings: { resource_id: { source: "param", param: "type" } },
5998
+ version: "1.0.0"
5999
+ },
6000
+ {
6001
+ action: "hubspot.crm.engagements.update",
6002
+ resource_type: "hubspot:engagement",
6003
+ required_relations: ["editor", "act_as"],
6004
+ required_scopes: ["crm.objects.contacts.write"],
6005
+ capability: "hubspot.crm.write",
6006
+ input_schema: {
6007
+ type: "object",
6008
+ properties: {
6009
+ engagementId: { type: "string" },
6010
+ ownerId: { type: "number" },
6011
+ timestamp: { type: "number" },
6012
+ associations: { type: "object" },
6013
+ metadata: { type: "object" }
6014
+ },
6015
+ required: ["engagementId"],
6016
+ additionalProperties: false
6017
+ },
6018
+ constraints: { rate_bucket: "hubspot.write" },
6019
+ effects: ["Update:CrmEngagement"],
6020
+ risk: "high",
6021
+ target_bindings: { resource_id: { source: "param", param: "engagementId" } },
6022
+ version: "1.0.0"
6023
+ },
6024
+ // ─── HubSpot Workflows (automation v4 flows, read-only) ───
6025
+ {
6026
+ action: "hubspot.automation.workflows.list",
6027
+ resource_type: "hubspot:workflow",
6028
+ required_relations: ["viewer", "editor", "admin", "owner"],
6029
+ required_scopes: ["automation"],
6030
+ capability: "hubspot.automation.read",
6031
+ input_schema: {
6032
+ type: "object",
6033
+ properties: {
6034
+ after: { type: "string" },
6035
+ limit: { type: "integer", minimum: 1, maximum: 100 }
6036
+ },
6037
+ additionalProperties: false
6038
+ },
6039
+ constraints: { rate_bucket: "hubspot.read" },
6040
+ effects: ["Read:Workflow"],
6041
+ risk: "low",
6042
+ target_bindings: { resource_id: { source: "param", param: "flowId", required: false } },
6043
+ version: "1.0.0"
6044
+ },
6045
+ {
6046
+ action: "hubspot.automation.workflows.get",
6047
+ resource_type: "hubspot:workflow",
6048
+ required_relations: ["viewer", "editor", "admin", "owner"],
6049
+ required_scopes: ["automation"],
6050
+ capability: "hubspot.automation.read",
6051
+ input_schema: {
6052
+ type: "object",
6053
+ properties: { flowId: { type: "string" } },
6054
+ required: ["flowId"],
6055
+ additionalProperties: false
6056
+ },
6057
+ constraints: { rate_bucket: "hubspot.read" },
6058
+ effects: ["Read:Workflow"],
6059
+ risk: "low",
6060
+ target_bindings: { resource_id: { source: "param", param: "flowId" } },
6061
+ version: "1.0.0"
6062
+ },
6063
+ // ─── HubSpot Account / utility ───
6064
+ {
6065
+ action: "hubspot.account.userDetails.get",
6066
+ resource_type: "hubspot:account",
6067
+ required_relations: ["viewer", "editor", "admin", "owner"],
6068
+ required_scopes: ["oauth"],
6069
+ capability: "hubspot.account.read",
6070
+ input_schema: {
6071
+ type: "object",
6072
+ properties: {},
6073
+ additionalProperties: false
6074
+ },
6075
+ constraints: { rate_bucket: "hubspot.read" },
6076
+ effects: ["Read:Account"],
6077
+ risk: "low",
6078
+ target_bindings: { resource_id: { source: "param", param: "hubId", required: false } },
6079
+ version: "1.0.0"
6080
+ },
6081
+ {
6082
+ action: "hubspot.account.link.get",
6083
+ resource_type: "hubspot:account",
6084
+ required_relations: ["viewer", "editor", "admin", "owner"],
6085
+ // Pure URL builder; nominal base scope (always granted) keeps it
6086
+ // grantable and satisfies the registry's minItems:1 contract.
6087
+ required_scopes: ["oauth"],
6088
+ capability: "hubspot.account.read",
6089
+ input_schema: {
6090
+ type: "object",
6091
+ properties: {
6092
+ portalId: { type: "string" },
6093
+ uiDomain: { type: "string" },
6094
+ pageRequests: { type: "array", minItems: 1 }
6095
+ },
6096
+ required: ["portalId", "uiDomain", "pageRequests"],
6097
+ additionalProperties: false
6098
+ },
6099
+ constraints: { rate_bucket: "hubspot.read" },
6100
+ effects: ["Read:Account"],
6101
+ risk: "low",
6102
+ target_bindings: { resource_id: { source: "param", param: "portalId" } },
6103
+ version: "1.0.0"
6104
+ },
6105
+ // ─── Agent Inbox Actions (internal) ───
6106
+ // Inbox actions back the Agent Inbox MCP tools (task delegation between
6107
+ // agents/people). They are internal (no external OAuth provider), so they
6108
+ // carry a single nominal base scope `inbox` to satisfy the registry
6109
+ // meta-schema's `minItems: 1` (same pattern as hubspot.account.link.get).
6110
+ {
6111
+ action: "inbox.send",
6112
+ resource_type: "inbox:item",
6113
+ required_relations: ["editor", "act_as"],
6114
+ required_scopes: ["inbox"],
6115
+ capability: "inbox.write",
6116
+ input_schema: {
6117
+ type: "object",
6118
+ properties: {
6119
+ to: { type: "string", minLength: 1, description: "Recipient (user id / handle) the task request is sent to" },
6120
+ taskType: { type: "string", minLength: 1, description: "Type of task being requested" },
6121
+ payload: { type: "object", description: "Task-specific payload data" },
6122
+ message: { type: "string", description: "Optional human-readable message" }
6123
+ },
6124
+ required: ["to", "taskType", "payload"],
6125
+ additionalProperties: false
6126
+ },
6127
+ constraints: { rate_bucket: "inbox.write" },
6128
+ effects: ["Create:InboxItem"],
6129
+ risk: "high",
6130
+ target_bindings: {
6131
+ resource_id: { source: "param", param: "to" }
6132
+ },
6133
+ version: "1.0.0"
6134
+ },
6135
+ {
6136
+ action: "inbox.respond",
6137
+ resource_type: "inbox:item",
6138
+ required_relations: ["editor", "act_as"],
6139
+ required_scopes: ["inbox"],
6140
+ capability: "inbox.write",
6141
+ input_schema: {
6142
+ type: "object",
6143
+ properties: {
6144
+ id: { type: "string", minLength: 1, description: "Inbox item id being responded to" },
6145
+ action: { type: "string", enum: ["accept", "decline", "counter"], description: "Response action" },
6146
+ data: { type: "object", description: "Optional response data (e.g. counter-proposal)" }
6147
+ },
6148
+ required: ["id", "action"],
6149
+ additionalProperties: false
6150
+ },
6151
+ constraints: { rate_bucket: "inbox.write" },
6152
+ effects: ["Update:InboxItem"],
6153
+ // high (not medium): an agent-mediated response (MCP invoke) must always
6154
+ // go through human approval — the Phase 1 "always confirm" guarantee made
6155
+ // enforceable. target_bindings below binds the concrete inbox item id so
6156
+ // the high-risk approval has a specific resource constraint (the public
6157
+ // /scheduling/:token link flow does NOT go through this gate — it calls
6158
+ // InboxService.respond directly, system-key-signed).
6159
+ risk: "high",
6160
+ target_bindings: {
6161
+ resource_id: { source: "param", param: "id" }
6162
+ },
6163
+ version: "1.0.0"
6164
+ },
6165
+ {
6166
+ action: "inbox.check",
6167
+ resource_type: "inbox:item",
6168
+ required_relations: ["viewer", "editor", "admin", "owner"],
6169
+ required_scopes: ["inbox"],
6170
+ capability: "inbox.read",
6171
+ input_schema: {
6172
+ type: "object",
6173
+ properties: {
6174
+ types: { type: "array", items: { type: "string" }, description: "Filter by task types" },
6175
+ status: { type: "string", description: "Filter by item status" }
6176
+ },
6177
+ additionalProperties: false
6178
+ },
6179
+ constraints: { rate_bucket: "inbox.read" },
6180
+ effects: ["Read:InboxItem"],
6181
+ risk: "low",
6182
+ target_bindings: {
6183
+ resource_id: { source: "param", param: "id", required: false }
6184
+ },
6185
+ version: "1.0.0"
6186
+ },
6187
+ {
6188
+ action: "inbox.checkByToken",
6189
+ resource_type: "inbox:item",
6190
+ required_relations: ["viewer", "editor", "admin", "owner"],
6191
+ required_scopes: ["inbox"],
6192
+ capability: "inbox.read",
6193
+ input_schema: {
6194
+ type: "object",
6195
+ properties: {
6196
+ token: { type: "string", minLength: 1, description: "Opaque access token for a single inbox item" }
6197
+ },
6198
+ required: ["token"],
6199
+ additionalProperties: false
6200
+ },
6201
+ constraints: { rate_bucket: "inbox.read" },
6202
+ effects: ["Read:InboxItem"],
6203
+ risk: "low",
6204
+ target_bindings: {
6205
+ resource_id: { source: "param", param: "token" }
6206
+ },
6207
+ version: "1.0.0"
6208
+ },
6209
+ {
6210
+ action: "inbox.complete",
6211
+ resource_type: "inbox:item",
6212
+ required_relations: ["editor", "act_as"],
6213
+ required_scopes: ["inbox"],
6214
+ capability: "inbox.write",
6215
+ input_schema: {
6216
+ type: "object",
6217
+ properties: {
6218
+ id: { type: "string", minLength: 1, description: "Inbox item id being completed" },
6219
+ result: { type: "object", description: "Result payload for the completed task" }
6220
+ },
6221
+ required: ["id", "result"],
6222
+ additionalProperties: false
6223
+ },
6224
+ constraints: { rate_bucket: "inbox.write" },
6225
+ effects: ["Update:InboxItem"],
6226
+ risk: "low",
6227
+ target_bindings: {
6228
+ resource_id: { source: "param", param: "id" }
6229
+ },
6230
+ version: "1.0.0"
6231
+ },
6232
+ // ─── Scheduling Actions (internal) ───
6233
+ // scheduling.request is a meeting-time negotiation façade over inbox.send.
6234
+ // Candidate slots are computed LLM-side from the user calendar; the server
6235
+ // only validates them. Like the inbox actions it is internal (no external
6236
+ // OAuth provider), so it carries the single nominal base scope `inbox`.
6237
+ // Spec: docs/specs/2026-06-10-inbox-intent-routing-design.md §2.1
6238
+ {
6239
+ action: "scheduling.request",
6240
+ resource_type: "inbox:item",
6241
+ required_relations: ["editor", "act_as"],
6242
+ required_scopes: ["inbox"],
6243
+ capability: "inbox.write",
6244
+ input_schema: {
6245
+ type: "object",
6246
+ properties: {
6247
+ to: { type: "string", minLength: 1, description: "Counterpart (user id / email) to negotiate a meeting time with" },
6248
+ topic: { type: "string", minLength: 1, description: "Meeting topic shown to the counterpart" },
6249
+ durationMinutes: { type: "integer", minimum: 5, maximum: 480, description: "Meeting length in minutes" },
6250
+ candidates: {
6251
+ type: "array",
6252
+ minItems: 1,
6253
+ maxItems: 10,
6254
+ description: "Candidate slots computed by the agent from the user calendar (LLM-side computation; the server only validates)",
6255
+ items: {
6256
+ type: "object",
6257
+ properties: {
6258
+ start: { type: "string", description: "ISO 8601 start" },
6259
+ end: { type: "string", description: "ISO 8601 end" }
6260
+ },
6261
+ required: ["start", "end"],
6262
+ additionalProperties: false
6263
+ }
6264
+ },
6265
+ message: { type: "string", description: "Optional human-readable message" }
6266
+ },
6267
+ required: ["to", "topic", "durationMinutes", "candidates"],
6268
+ additionalProperties: false
6269
+ },
6270
+ constraints: { rate_bucket: "inbox.write" },
6271
+ effects: ["Create:InboxItem"],
6272
+ risk: "high",
6273
+ target_bindings: {
6274
+ resource_id: { source: "param", param: "to" }
6275
+ },
6276
+ version: "1.0.0"
5494
6277
  }
5495
6278
  ],
5496
6279
  capabilities: [
@@ -5550,19 +6333,149 @@ var ACTION_REGISTRY = {
5550
6333
  },
5551
6334
  {
5552
6335
  capability: "jira.read.basic",
5553
- description: "Read Jira issues, projects, boards, sprints, and issue link types",
5554
- 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"],
6336
+ description: "Read Jira issues, projects, boards, sprints, issue link types, and users",
6337
+ 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"],
5555
6338
  version: "1.0.0"
5556
6339
  },
5557
6340
  {
5558
6341
  capability: "jira.write.basic",
5559
- description: "Create, update, delete Jira issues, and manage issue links",
5560
- includes: ["jira.issue.create", "jira.issue.update", "jira.issue.delete", "jira.comment.create", "jira.issue.transition", "jira.issuelink.create", "jira.issuelink.delete"],
6342
+ description: "Create, update, delete Jira issues, manage issue links, and add/delete comments",
6343
+ 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"],
6344
+ version: "1.0.0"
6345
+ },
6346
+ {
6347
+ capability: "inbox.write",
6348
+ description: "Send and respond to agent inbox tasks",
6349
+ includes: ["inbox.send", "inbox.respond", "inbox.complete", "scheduling.request"],
6350
+ version: "1.0.0"
6351
+ },
6352
+ {
6353
+ capability: "inbox.read",
6354
+ description: "Read agent inbox tasks",
6355
+ includes: ["inbox.check", "inbox.checkByToken"],
5561
6356
  version: "1.0.0"
5562
6357
  }
5563
6358
  ]
5564
6359
  };
5565
6360
 
6361
+ // src/registry/action-input-validator.ts
6362
+ var SCHEMA_INDEX = (() => {
6363
+ const map = /* @__PURE__ */ new Map();
6364
+ for (const a of ACTION_REGISTRY.actions) {
6365
+ if (a && typeof a.action === "string" && a.input_schema) {
6366
+ map.set(a.action, a.input_schema);
6367
+ }
6368
+ }
6369
+ return map;
6370
+ })();
6371
+ function describeExpectedShape(schema) {
6372
+ const props = schema.properties ?? {};
6373
+ const required = Array.isArray(schema.required) ? schema.required : [];
6374
+ const requiredSet = new Set(required);
6375
+ const parts = [];
6376
+ const orderedKeys = [
6377
+ ...required.filter((k) => k in props),
6378
+ ...Object.keys(props).filter((k) => !requiredSet.has(k))
6379
+ ];
6380
+ for (const key of orderedKeys) {
6381
+ const prop = props[key] || {};
6382
+ const optionalMark = requiredSet.has(key) ? "" : "?";
6383
+ const enumVals = Array.isArray(prop.enum) ? prop.enum : void 0;
6384
+ if (enumVals && enumVals.length > 0) {
6385
+ const rendered = enumVals.map((v) => typeof v === "string" ? `'${v}'` : String(v)).join(" | ");
6386
+ parts.push(`${key}${optionalMark}: ${rendered}`);
6387
+ } else {
6388
+ parts.push(`${key}${optionalMark}`);
6389
+ }
6390
+ }
6391
+ return `{ ${parts.join(", ")} }`;
6392
+ }
6393
+ function matchesType(value, type) {
6394
+ if (!type) return true;
6395
+ switch (type) {
6396
+ case "string":
6397
+ return typeof value === "string";
6398
+ case "integer":
6399
+ return typeof value === "number" && Number.isInteger(value);
6400
+ case "number":
6401
+ return typeof value === "number";
6402
+ case "boolean":
6403
+ return typeof value === "boolean";
6404
+ case "array":
6405
+ return Array.isArray(value);
6406
+ case "object":
6407
+ return typeof value === "object" && value !== null && !Array.isArray(value);
6408
+ default:
6409
+ return true;
6410
+ }
6411
+ }
6412
+ function validateActionInput(action, params) {
6413
+ const schema = SCHEMA_INDEX.get(action);
6414
+ if (!schema) {
6415
+ return { valid: true };
6416
+ }
6417
+ const props = schema.properties ?? {};
6418
+ const required = Array.isArray(schema.required) ? schema.required : [];
6419
+ const additionalProps = schema.additionalProperties;
6420
+ const safeParams = params && typeof params === "object" && !Array.isArray(params) ? params : {};
6421
+ const missing = [];
6422
+ const unknown = [];
6423
+ const enumErrors = [];
6424
+ const typeErrors = [];
6425
+ for (const key of required) {
6426
+ if (!(key in safeParams) || safeParams[key] === void 0 || safeParams[key] === null) {
6427
+ missing.push(key);
6428
+ }
6429
+ }
6430
+ if (additionalProps === false) {
6431
+ for (const key of Object.keys(safeParams)) {
6432
+ if (!(key in props)) {
6433
+ unknown.push(key);
6434
+ }
6435
+ }
6436
+ }
6437
+ for (const key of Object.keys(props)) {
6438
+ if (!(key in safeParams)) continue;
6439
+ const value = safeParams[key];
6440
+ if (value === void 0 || value === null) continue;
6441
+ const prop = props[key] || {};
6442
+ const enumVals = Array.isArray(prop.enum) ? prop.enum : void 0;
6443
+ if (enumVals && enumVals.length > 0) {
6444
+ if (!enumVals.includes(value)) {
6445
+ enumErrors.push(key);
6446
+ continue;
6447
+ }
6448
+ }
6449
+ if (!matchesType(value, prop.type)) {
6450
+ typeErrors.push(key);
6451
+ }
6452
+ }
6453
+ if (missing.length === 0 && unknown.length === 0 && enumErrors.length === 0 && typeErrors.length === 0) {
6454
+ return { valid: true };
6455
+ }
6456
+ const segments = [];
6457
+ if (missing.length > 0) {
6458
+ segments.push(`missing required parameter(s) [${missing.join(", ")}]`);
6459
+ }
6460
+ if (unknown.length > 0) {
6461
+ segments.push(`unknown parameter(s) [${unknown.join(", ")}]`);
6462
+ }
6463
+ if (enumErrors.length > 0) {
6464
+ const details = enumErrors.map((key) => {
6465
+ const enumVals = props[key]?.enum || [];
6466
+ const rendered = enumVals.map((v) => typeof v === "string" ? `'${v}'` : String(v)).join(" | ");
6467
+ return `${key} (allowed: ${rendered})`;
6468
+ }).join(", ");
6469
+ segments.push(`invalid value for enum parameter(s) [${details}]`);
6470
+ }
6471
+ if (typeErrors.length > 0) {
6472
+ const details = typeErrors.map((key) => `${key} (expected ${props[key]?.type})`).join(", ");
6473
+ segments.push(`wrong type for parameter(s) [${details}]`);
6474
+ }
6475
+ const message = `${action}: ${segments.join("; ")}. Expected shape: ${describeExpectedShape(schema)}`;
6476
+ return { valid: false, errors: [message] };
6477
+ }
6478
+
5566
6479
  // src/registry/resource-types.ts
5567
6480
  var RESOURCE_TYPES = {
5568
6481
  // Slack
@@ -5584,6 +6497,14 @@ var RESOURCE_TYPES = {
5584
6497
  JIRA_BOARD: "jira:board",
5585
6498
  JIRA_ISSUE: "jira:issue",
5586
6499
  JIRA_SPRINT: "jira:sprint",
6500
+ // HubSpot
6501
+ HUBSPOT_OBJECT: "hubspot:object",
6502
+ HUBSPOT_PROPERTY: "hubspot:property",
6503
+ HUBSPOT_SCHEMA: "hubspot:schema",
6504
+ HUBSPOT_ASSOCIATION: "hubspot:association",
6505
+ HUBSPOT_ENGAGEMENT: "hubspot:engagement",
6506
+ HUBSPOT_WORKFLOW: "hubspot:workflow",
6507
+ HUBSPOT_ACCOUNT: "hubspot:account",
5587
6508
  // OS (local)
5588
6509
  OS_SECRET: "os:secret",
5589
6510
  OS_PROCESS: "os:process",
@@ -5610,6 +6531,13 @@ var LEGACY_RESOURCE_TYPE_MAP = {
5610
6531
  "jira:board": RESOURCE_TYPES.JIRA_BOARD,
5611
6532
  "jira:issue": RESOURCE_TYPES.JIRA_ISSUE,
5612
6533
  "jira:sprint": RESOURCE_TYPES.JIRA_SPRINT,
6534
+ "hubspot:object": RESOURCE_TYPES.HUBSPOT_OBJECT,
6535
+ "hubspot:property": RESOURCE_TYPES.HUBSPOT_PROPERTY,
6536
+ "hubspot:schema": RESOURCE_TYPES.HUBSPOT_SCHEMA,
6537
+ "hubspot:association": RESOURCE_TYPES.HUBSPOT_ASSOCIATION,
6538
+ "hubspot:engagement": RESOURCE_TYPES.HUBSPOT_ENGAGEMENT,
6539
+ "hubspot:workflow": RESOURCE_TYPES.HUBSPOT_WORKFLOW,
6540
+ "hubspot:account": RESOURCE_TYPES.HUBSPOT_ACCOUNT,
5613
6541
  "os:secret": RESOURCE_TYPES.OS_SECRET,
5614
6542
  "os:process": RESOURCE_TYPES.OS_PROCESS,
5615
6543
  // Legacy formats with old provider prefixes
@@ -5833,7 +6761,7 @@ var ACTION_DISPLAY_CONFIGS = {
5833
6761
  summaryTemplate: (p) => {
5834
6762
  const parts = [];
5835
6763
  if (p.summary) parts.push(p.summary);
5836
- if (p.start) parts.push(`(${formatValue(p.start)})`);
6764
+ if (p.start) parts.push(`(${formatCalendarTime(p.start)})`);
5837
6765
  return parts.join(" ");
5838
6766
  },
5839
6767
  displayFields: [
@@ -5847,7 +6775,7 @@ var ACTION_DISPLAY_CONFIGS = {
5847
6775
  summaryTemplate: (p) => {
5848
6776
  const parts = [];
5849
6777
  if (p.summary) parts.push(p.summary);
5850
- if (p.start) parts.push(`(${formatValue(p.start)})`);
6778
+ if (p.start) parts.push(`(${formatCalendarTime(p.start)})`);
5851
6779
  return parts.join(" ");
5852
6780
  },
5853
6781
  displayFields: [
@@ -5937,7 +6865,7 @@ var ACTION_DISPLAY_CONFIGS = {
5937
6865
  ]
5938
6866
  },
5939
6867
  // AIDENTITY-65: comment 本体は string と ADF document の両方を受けるため、
5940
- // formatValue 側の ADF ハンドリング (extractFirstAdfText) に任せて key 指定で OK。
6868
+ // detail 表示の ADF 描画は formatValueFull 側に任せて key 指定で OK。
5941
6869
  "jira.comment.create": {
5942
6870
  summaryTemplate: (p) => {
5943
6871
  const parts = [];
@@ -5950,6 +6878,21 @@ var ACTION_DISPLAY_CONFIGS = {
5950
6878
  { key: "body", label: "Comment" }
5951
6879
  ]
5952
6880
  },
6881
+ // AIDENTITY-66: 破壊的操作なので「どの issue のどの comment を消すか」を明示する
6882
+ // (jira.issue.delete / jira.issuelink.delete と同じ destructive 表現の方針)。
6883
+ "jira.comment.delete": {
6884
+ summaryTemplate: (p) => {
6885
+ const issue = p.issueIdOrKey ?? p.issueKey;
6886
+ const commentId = p.commentId ?? p.id;
6887
+ if (issue && commentId) return `Delete comment ${commentId} on ${issue}`;
6888
+ if (commentId) return `Delete comment ${commentId}`;
6889
+ return "";
6890
+ },
6891
+ displayFields: [
6892
+ { label: "Issue", extract: (p) => p.issueIdOrKey ?? p.issueKey },
6893
+ { label: "Comment", extract: (p) => p.commentId ?? p.id }
6894
+ ]
6895
+ },
5953
6896
  // AIDENTITY-65: API enricher が 'Link' label を upsert で書き換える。
5954
6897
  "jira.issuelink.delete": {
5955
6898
  summaryTemplate: (p) => {
@@ -5960,24 +6903,99 @@ var ACTION_DISPLAY_CONFIGS = {
5960
6903
  displayFields: [
5961
6904
  { key: "linkId", label: "Link" }
5962
6905
  ]
6906
+ },
6907
+ // AIDENTITY-83: email / displayName から accountId を解決する read action。
6908
+ "jira.user.search": {
6909
+ summaryTemplate: (p) => {
6910
+ if (p.query) return `Search users: ${String(p.query)}`;
6911
+ return "";
6912
+ },
6913
+ displayFields: [
6914
+ { key: "query", label: "Query" },
6915
+ { key: "maxResults", label: "Max Results" }
6916
+ ]
6917
+ },
6918
+ // ─── Agent Inbox ───
6919
+ "inbox.send": {
6920
+ summaryTemplate: (p) => {
6921
+ const parts = [];
6922
+ if (p.to) parts.push(`To: ${p.to}`);
6923
+ if (p.taskType) parts.push(`Task: ${p.taskType}`);
6924
+ return parts.join(", ");
6925
+ },
6926
+ displayFields: [
6927
+ { key: "to", label: "To" },
6928
+ { key: "taskType", label: "Task" },
6929
+ { key: "message", label: "Message" }
6930
+ ]
6931
+ },
6932
+ "inbox.respond": {
6933
+ summaryTemplate: (p) => {
6934
+ const parts = [];
6935
+ if (p.action) parts.push(String(p.action));
6936
+ if (p.id) parts.push(`#${p.id}`);
6937
+ return parts.join(" ");
6938
+ },
6939
+ displayFields: [
6940
+ { key: "id", label: "Item" },
6941
+ { key: "action", label: "Action" }
6942
+ ]
6943
+ },
6944
+ "inbox.check": {
6945
+ summaryTemplate: (p) => {
6946
+ const parts = [];
6947
+ if (p.status) parts.push(`Status: ${p.status}`);
6948
+ if (Array.isArray(p.types) && p.types.length > 0) parts.push(`Types: ${p.types.join(", ")}`);
6949
+ return parts.join(", ");
6950
+ },
6951
+ displayFields: [
6952
+ { key: "status", label: "Status" },
6953
+ { key: "types", label: "Types" }
6954
+ ]
6955
+ },
6956
+ "inbox.checkByToken": {
6957
+ summaryTemplate: (p) => p.token ? `Token: ${p.token}` : "",
6958
+ displayFields: [
6959
+ { key: "token", label: "Token" }
6960
+ ]
6961
+ },
6962
+ "inbox.complete": {
6963
+ summaryTemplate: (p) => p.id ? `Complete #${p.id}` : "",
6964
+ displayFields: [
6965
+ { key: "id", label: "Item" }
6966
+ ]
5963
6967
  }
5964
6968
  };
5965
6969
  function truncate(text, maxLength) {
5966
6970
  if (text.length <= maxLength) return text;
5967
6971
  return text.slice(0, maxLength - 3) + "...";
5968
6972
  }
5969
- function formatValue(value) {
6973
+ function formatCalendarTime(value) {
6974
+ if (value && typeof value === "object" && !Array.isArray(value)) {
6975
+ const obj = value;
6976
+ if (obj.dateTime) {
6977
+ return obj.timeZone ? `${obj.dateTime} (${obj.timeZone})` : String(obj.dateTime);
6978
+ }
6979
+ if (obj.date) return String(obj.date);
6980
+ }
6981
+ return String(value);
6982
+ }
6983
+ function formatValueFull(value) {
5970
6984
  if (value === void 0) return "";
5971
6985
  if (value === null) return "(unset)";
5972
6986
  if (Array.isArray(value)) {
5973
- return value.map((item) => {
6987
+ const parts = value.map((item) => {
5974
6988
  if (item && typeof item === "object") {
5975
6989
  const email = item.email;
5976
6990
  if (email) return String(email);
5977
- return JSON.stringify(item);
6991
+ return JSON.stringify(item, null, 2);
5978
6992
  }
5979
6993
  return String(item);
5980
- }).join(", ");
6994
+ });
6995
+ const hasMultiline = parts.some((p) => p.includes("\n"));
6996
+ const joinedShort = parts.join(", ");
6997
+ if (hasMultiline || joinedShort.length > 80) return parts.join("\n");
6998
+ return joinedShort;
5981
6999
  }
5982
7000
  if (typeof value === "object") {
5983
7001
  const obj = value;
@@ -5986,33 +7004,118 @@ function formatValue(value) {
5986
7004
  }
5987
7005
  if (obj.date) return String(obj.date);
5988
7006
  if (obj.type === "doc" && Array.isArray(obj.content)) {
5989
- const firstText = extractFirstAdfText(obj.content);
5990
- if (firstText) {
5991
- const moreCount = obj.content.length - 1;
5992
- const more = moreCount > 0 ? ` \u2026 (+${moreCount} block${moreCount > 1 ? "s" : ""})` : "";
5993
- return `${firstText}${more}`;
5994
- }
5995
- return "(ADF document)";
7007
+ const rendered = renderAdfDocument(obj.content).trim();
7008
+ if (rendered) return rendered;
7009
+ if (obj.content.length > 0) return JSON.stringify(value, null, 2);
7010
+ return "";
5996
7011
  }
5997
- return JSON.stringify(value);
7012
+ return JSON.stringify(value, null, 2);
5998
7013
  }
5999
7014
  return String(value);
6000
7015
  }
6001
- function extractFirstAdfText(nodes) {
7016
+ function renderAdfDocument(nodes, indent = "") {
7017
+ const lines = [];
6002
7018
  for (const node of nodes) {
6003
7019
  if (!node || typeof node !== "object") continue;
6004
7020
  const n = node;
6005
- if (n.type === "paragraph" || n.type === "heading") {
6006
- const inner = n.content ?? [];
6007
- for (const child of inner) {
6008
- if (child && typeof child === "object") {
6009
- const c = child;
6010
- if (c.type === "text" && typeof c.text === "string") return c.text;
7021
+ const type = n.type;
7022
+ const content = n.content ?? [];
7023
+ switch (type) {
7024
+ case "paragraph": {
7025
+ lines.push(indent + renderAdfInline(content));
7026
+ break;
7027
+ }
7028
+ case "heading": {
7029
+ const level = Number(n.attrs?.level) || 1;
7030
+ lines.push(indent + "#".repeat(level) + " " + renderAdfInline(content));
7031
+ break;
7032
+ }
7033
+ case "bulletList":
7034
+ case "orderedList": {
7035
+ const ordered = type === "orderedList";
7036
+ let orderedCounter = 0;
7037
+ content.forEach((item) => {
7038
+ if (!item || typeof item !== "object") return;
7039
+ const li = item;
7040
+ const liContent = li.content ?? [];
7041
+ orderedCounter++;
7042
+ const marker = ordered ? `${orderedCounter}. ` : "- ";
7043
+ const inner = renderAdfDocument(liContent, indent + " ");
7044
+ const innerLines = inner.split("\n");
7045
+ const firstTrimmed = innerLines.length > 0 ? innerLines[0].slice((indent + " ").length) : "";
7046
+ lines.push(indent + marker + firstTrimmed);
7047
+ for (let i = 1; i < innerLines.length; i++) lines.push(innerLines[i]);
7048
+ });
7049
+ break;
7050
+ }
7051
+ case "codeBlock": {
7052
+ lines.push(indent + renderAdfInline(content));
7053
+ break;
7054
+ }
7055
+ case "blockquote": {
7056
+ const inner = renderAdfDocument(content, indent);
7057
+ if (inner) {
7058
+ for (const l of inner.split("\n")) lines.push(indent + "> " + l.slice(indent.length));
6011
7059
  }
7060
+ break;
7061
+ }
7062
+ case "panel": {
7063
+ const panelType = n.attrs?.panelType;
7064
+ if (panelType) lines.push(indent + `[panel:${String(panelType)}]`);
7065
+ const panelInner = renderAdfDocument(content, indent);
7066
+ if (panelInner) lines.push(panelInner);
7067
+ break;
7068
+ }
7069
+ case "rule": {
7070
+ lines.push(indent + "---");
7071
+ break;
7072
+ }
7073
+ default: {
7074
+ if (content.length > 0) {
7075
+ const inner = renderAdfDocument(content, indent);
7076
+ if (inner) lines.push(inner);
7077
+ } else {
7078
+ const inline = renderAdfInline([n]);
7079
+ if (inline) lines.push(indent + inline);
7080
+ }
7081
+ break;
6012
7082
  }
6013
7083
  }
6014
7084
  }
6015
- return "";
7085
+ return lines.join("\n");
7086
+ }
7087
+ function renderAdfInline(nodes) {
7088
+ let out = "";
7089
+ for (const node of nodes) {
7090
+ if (!node || typeof node !== "object") continue;
7091
+ const n = node;
7092
+ const attrs = n.attrs ?? {};
7093
+ switch (n.type) {
7094
+ case "text":
7095
+ if (typeof n.text === "string") out += n.text;
7096
+ break;
7097
+ case "hardBreak":
7098
+ out += "\n";
7099
+ break;
7100
+ case "mention":
7101
+ out += String(attrs.text ?? attrs.id ?? "@mention");
7102
+ break;
7103
+ case "emoji":
7104
+ out += String(attrs.text ?? attrs.shortName ?? "");
7105
+ break;
7106
+ case "inlineCard":
7107
+ out += String(attrs.url ?? "");
7108
+ break;
7109
+ default:
7110
+ if (Array.isArray(n.content)) {
7111
+ out += renderAdfInline(n.content);
7112
+ } else if (typeof attrs.text === "string") {
7113
+ out += attrs.text;
7114
+ }
7115
+ break;
7116
+ }
7117
+ }
7118
+ return out;
6016
7119
  }
6017
7120
  var ACTION_PARAMS_MAX_SIZE = 1e4;
6018
7121
  function generateActionSummary(action, params, maxLength = 50) {
@@ -6036,11 +7139,11 @@ function generateActionParamsDisplay(action, params) {
6036
7139
  return config.displayFields.map((f) => {
6037
7140
  const raw = f.extract ? f.extract(params) : f.key ? params[f.key] : void 0;
6038
7141
  return { label: f.label, raw };
6039
- }).filter((item) => item.raw !== void 0).map((item) => ({ label: item.label, value: formatValue(item.raw) }));
7142
+ }).filter((item) => item.raw !== void 0).map((item) => ({ label: item.label, value: formatValueFull(item.raw) }));
6040
7143
  }
6041
- return Object.entries(params).filter(([, v]) => v !== void 0 && v !== null).slice(0, 3).map(([key, val]) => ({
7144
+ return Object.entries(params).filter(([, v]) => v !== void 0 && v !== null).map(([key, val]) => ({
6042
7145
  label: key,
6043
- value: formatValue(val)
7146
+ value: formatValueFull(val)
6044
7147
  }));
6045
7148
  }
6046
7149
 
@@ -6662,6 +7765,7 @@ export {
6662
7765
  sha256Hex,
6663
7766
  signJWT,
6664
7767
  signRequest,
7768
+ validateActionInput,
6665
7769
  validateRegistryObject,
6666
7770
  vcStatusToCredentialStatus,
6667
7771
  verifyJWT,