@vess-id/ai-identity 0.12.0 → 0.14.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/dist/index.d.mts +1230 -8
  2. package/dist/index.d.ts +11 -0
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +571 -27
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.mjs +558 -27
  7. package/dist/index.mjs.map +1 -1
  8. package/dist/policy/__tests__/cedar-engine.spec.d.ts +17 -0
  9. package/dist/policy/__tests__/cedar-engine.spec.d.ts.map +1 -0
  10. package/dist/policy/__tests__/cedar-entities.spec.d.ts +14 -0
  11. package/dist/policy/__tests__/cedar-entities.spec.d.ts.map +1 -0
  12. package/dist/policy/__tests__/decision-enum.spec.d.ts +16 -0
  13. package/dist/policy/__tests__/decision-enum.spec.d.ts.map +1 -0
  14. package/dist/policy/cedar-engine.d.ts +334 -0
  15. package/dist/policy/cedar-engine.d.ts.map +1 -0
  16. package/dist/policy/cedar-entities.d.ts +59 -0
  17. package/dist/policy/cedar-entities.d.ts.map +1 -0
  18. package/dist/policy/decision.d.ts +46 -0
  19. package/dist/policy/decision.d.ts.map +1 -0
  20. package/dist/policy/index.d.ts +15 -0
  21. package/dist/policy/index.d.ts.map +1 -0
  22. package/dist/registry/__tests__/action-registry-validation.spec.d.ts +13 -0
  23. package/dist/registry/__tests__/action-registry-validation.spec.d.ts.map +1 -0
  24. package/dist/registry/__tests__/action-risk-registry-driven.spec.d.ts +15 -0
  25. package/dist/registry/__tests__/action-risk-registry-driven.spec.d.ts.map +1 -0
  26. package/dist/registry/__tests__/action-risk.spec.d.ts +17 -0
  27. package/dist/registry/__tests__/action-risk.spec.d.ts.map +1 -0
  28. package/dist/registry/action-registry-json.d.ts +398 -0
  29. package/dist/registry/action-registry-json.d.ts.map +1 -1
  30. package/dist/registry/action-registry.d.ts +1 -1
  31. package/dist/registry/action-registry.d.ts.map +1 -1
  32. package/dist/registry/action-risk.d.ts +47 -0
  33. package/dist/registry/action-risk.d.ts.map +1 -0
  34. package/dist/registry/action-summary.d.ts.map +1 -1
  35. package/dist/types/__tests__/cedar-policy.spec.d.ts +8 -0
  36. package/dist/types/__tests__/cedar-policy.spec.d.ts.map +1 -0
  37. package/dist/types/__tests__/permission-vc-v3.spec.d.ts +9 -0
  38. package/dist/types/__tests__/permission-vc-v3.spec.d.ts.map +1 -0
  39. package/dist/types/__tests__/phase1-vc-factory.spec.d.ts +9 -0
  40. package/dist/types/__tests__/phase1-vc-factory.spec.d.ts.map +1 -0
  41. package/dist/types/__tests__/policy-ref.spec.d.ts +9 -0
  42. package/dist/types/__tests__/policy-ref.spec.d.ts.map +1 -0
  43. package/dist/types/cedar-policy.d.ts +60 -0
  44. package/dist/types/cedar-policy.d.ts.map +1 -0
  45. package/dist/types/grant.d.ts +69 -0
  46. package/dist/types/grant.d.ts.map +1 -1
  47. package/dist/types/index.d.ts +1 -0
  48. package/dist/types/index.d.ts.map +1 -1
  49. package/dist/types/jira.d.ts +57 -0
  50. package/dist/types/jira.d.ts.map +1 -1
  51. package/dist/types/permission-vc.d.ts +236 -6
  52. package/dist/types/permission-vc.d.ts.map +1 -1
  53. package/dist/types/tier.d.ts.map +1 -1
  54. package/package.json +2 -1
package/dist/index.js CHANGED
@@ -44,9 +44,12 @@ __export(index_exports, {
44
44
  AuthProvider: () => AuthProvider,
45
45
  AuthenticationError: () => AuthenticationError,
46
46
  CANONICAL_PROVIDERS: () => CANONICAL_PROVIDERS,
47
+ CedarEngineUnavailableError: () => CedarEngineUnavailableError,
48
+ CedarParseError: () => CedarParseError,
47
49
  ConstraintEvaluator: () => ConstraintEvaluator,
48
50
  CredentialStatus: () => CredentialStatus,
49
51
  CredentialType: () => CredentialType,
52
+ DECISION_VALUES: () => DECISION_VALUES,
50
53
  DEFAULT_CONSTRAINTS_BY_RISK: () => DEFAULT_CONSTRAINTS_BY_RISK,
51
54
  DeviceEnrollManager: () => DeviceEnrollManager,
52
55
  DummyCreds: () => DummyCreds,
@@ -68,6 +71,7 @@ __export(index_exports, {
68
71
  MemoryKeyStorage: () => MemoryKeyStorage,
69
72
  NetworkError: () => NetworkError,
70
73
  OAuthProvider: () => OAuthProvider,
74
+ PHASE_1_VC_LAYER: () => PHASE_1_VC_LAYER,
71
75
  PROVIDER_ALIASES: () => PROVIDER_ALIASES,
72
76
  REAUTH_REQUIRED_ACTION: () => REAUTH_REQUIRED_ACTION,
73
77
  RESOURCE_TYPES: () => RESOURCE_TYPES,
@@ -93,12 +97,17 @@ __export(index_exports, {
93
97
  VPManager: () => VPManager,
94
98
  WRITE_ACTION_NAMES: () => WRITE_ACTION_NAMES,
95
99
  buildCanonicalString: () => buildCanonicalString,
100
+ buildCedarEntities: () => buildCedarEntities,
96
101
  buildGrantIdFields: () => buildGrantIdFields,
97
102
  buildKbJwtPayload: () => buildKbJwtPayload,
103
+ buildPhase1VcClaims: () => buildPhase1VcClaims,
104
+ buildValidationErrors: () => buildValidationErrors,
98
105
  canonicalizeAction: () => canonicalizeAction,
99
106
  checkPermissionWithVP: () => checkPermissionWithVP,
107
+ classifyCedarErrorMessage: () => classifyCedarErrorMessage,
100
108
  configure: () => configure,
101
109
  createAjv: () => createAjv,
110
+ createCedarEngine: () => createCedarEngine,
102
111
  createDidJwk: () => createDidJwk,
103
112
  credentialStatusToVCStatus: () => credentialStatusToVCStatus,
104
113
  defaultConstraintEvaluator: () => defaultConstraintEvaluator,
@@ -127,6 +136,9 @@ __export(index_exports, {
127
136
  indexCapabilities: () => indexCapabilities,
128
137
  isActionEquivalent: () => isActionEquivalent,
129
138
  isCanonicalProvider: () => isCanonicalProvider,
139
+ isDecision: () => isDecision,
140
+ isPolicyRefInline: () => isPolicyRefInline,
141
+ isPolicyRefReference: () => isPolicyRefReference,
130
142
  isUnlimited: () => isUnlimited,
131
143
  isValidDidJwk: () => isValidDidJwk,
132
144
  isValidProvider: () => isValidProvider,
@@ -141,6 +153,7 @@ __export(index_exports, {
141
153
  planDelegationForVC: () => planDelegationForVC,
142
154
  publicKeysMatch: () => publicKeysMatch,
143
155
  readVcExpSeconds: () => readVcExpSeconds,
156
+ resolveActionRisk: () => resolveActionRisk,
144
157
  resolveActionsFromSelection: () => resolveActionsFromSelection,
145
158
  resolveProvider: () => resolveProvider,
146
159
  resolveResourceType: () => resolveResourceType,
@@ -2831,6 +2844,12 @@ var NetworkError = class extends AIdentityError {
2831
2844
  };
2832
2845
 
2833
2846
  // src/types/permission-vc.ts
2847
+ function isPolicyRefInline(ref) {
2848
+ return ref.mode === "inline";
2849
+ }
2850
+ function isPolicyRefReference(ref) {
2851
+ return ref.mode === "reference";
2852
+ }
2834
2853
  function buildGrantIdFields(grantIds) {
2835
2854
  if (grantIds.length === 0) {
2836
2855
  throw new Error("grantIds must contain at least one element");
@@ -2870,6 +2889,10 @@ function parseGrantAction(grantAction) {
2870
2889
  }
2871
2890
  return { provider: "*", action: grantAction };
2872
2891
  }
2892
+ var PHASE_1_VC_LAYER = "agent_permission";
2893
+ function buildPhase1VcClaims(base) {
2894
+ return { ...base, layer: PHASE_1_VC_LAYER };
2895
+ }
2873
2896
 
2874
2897
  // src/types/grant.ts
2875
2898
  var GrantStatus = /* @__PURE__ */ ((GrantStatus2) => {
@@ -3085,7 +3108,9 @@ var DEFAULT_CONSTRAINTS_BY_RISK = {
3085
3108
  var TIER_LIMITS = {
3086
3109
  free: {
3087
3110
  maxProjects: 1,
3088
- maxWritesPerMonth: 50,
3111
+ // GTM doc §3 Tier 構成: Free = 100 writes/月. Raised from 50 to 100
3112
+ // (2026-05-14 tier drift fix) so Aha 到達前にユーザーを枯渇させない。
3113
+ maxWritesPerMonth: 100,
3089
3114
  maxWriteVcTtlMinutes: 5,
3090
3115
  readAutoApproveMaxRiskLevel: "low",
3091
3116
  readAutoApproveTtlMinutes: 30,
@@ -3095,7 +3120,10 @@ var TIER_LIMITS = {
3095
3120
  },
3096
3121
  pro: {
3097
3122
  maxProjects: 3,
3098
- maxWritesPerMonth: 300,
3123
+ // GTM doc §3 Tier 構成: Pro = 2,000 writes/月. Raised from 300 to 2,000
3124
+ // (2026-05-14 tier drift fix) — backend was 6.7x below the published GTM
3125
+ // commitment. Overage billing ($0.07 / action) kicks in beyond 2,000.
3126
+ maxWritesPerMonth: 2e3,
3099
3127
  maxWriteVcTtlMinutes: 1440,
3100
3128
  // 24h
3101
3129
  readAutoApproveMaxRiskLevel: "medium",
@@ -3109,14 +3137,21 @@ var TIER_LIMITS = {
3109
3137
  team: {
3110
3138
  maxProjects: -1,
3111
3139
  // unlimited
3140
+ // GTM doc §3 Tier 構成: Team = 10,000 writes/月 (team 合計). Per-user
3141
+ // enforcement is intentionally unlimited (-1) in M1 Closed Beta; the
3142
+ // team-aggregate 10K cap is deferred to M2 (requires team-scoped quota
3143
+ // ledger). Documented in GTM doc §3 annotation.
3112
3144
  maxWritesPerMonth: -1,
3113
- // unlimited (fair use)
3145
+ // unlimited (M1 fair use; M2 enforces 10K team total)
3114
3146
  maxWriteVcTtlMinutes: 10080,
3115
3147
  // 168h
3116
3148
  readAutoApproveMaxRiskLevel: "medium",
3117
3149
  readAutoApproveTtlMinutes: 10080,
3118
3150
  // 168h
3119
3151
  writeAutoApproveEnabled: true,
3152
+ // GTM doc §3 commits to 90-day audit retention for Team; implementation
3153
+ // exceeds this with 365 days as a customer-favorable bonus (documented
3154
+ // in GTM doc §3 annotation).
3120
3155
  auditRetentionDays: 365,
3121
3156
  auditExportEnabled: true
3122
3157
  }
@@ -4036,7 +4071,7 @@ var actionMetaSchema = {
4036
4071
  $id: "https://vess.ai/schemas/action-meta.json",
4037
4072
  type: "object",
4038
4073
  additionalProperties: false,
4039
- required: ["action", "resource_type", "required_relations", "required_scopes", "version"],
4074
+ required: ["action", "resource_type", "required_relations", "required_scopes", "risk", "version"],
4040
4075
  properties: {
4041
4076
  action: { type: "string", minLength: 1 },
4042
4077
  resource_type: {
@@ -4676,7 +4711,7 @@ var ACTION_REGISTRY = {
4676
4711
  },
4677
4712
  constraints: { rate_bucket: "github.write" },
4678
4713
  effects: ["Create:Issue"],
4679
- risk: "medium",
4714
+ risk: "high",
4680
4715
  target_bindings: {
4681
4716
  resource_id: { source: "context", key: "resource_id" }
4682
4717
  },
@@ -4751,7 +4786,7 @@ var ACTION_REGISTRY = {
4751
4786
  },
4752
4787
  constraints: { rate_bucket: "github.write" },
4753
4788
  effects: ["Update:Issue"],
4754
- risk: "medium",
4789
+ risk: "high",
4755
4790
  target_bindings: {
4756
4791
  resource_id: { source: "context", key: "resource_id" }
4757
4792
  },
@@ -5093,7 +5128,7 @@ var ACTION_REGISTRY = {
5093
5128
  },
5094
5129
  constraints: { rate_bucket: "calendar.write" },
5095
5130
  effects: ["Update:Event"],
5096
- risk: "medium",
5131
+ risk: "high",
5097
5132
  target_bindings: {
5098
5133
  resource_id: { source: "param", param: "calendarId", default: "primary" },
5099
5134
  secondary: [
@@ -5475,6 +5510,80 @@ var ACTION_REGISTRY = {
5475
5510
  },
5476
5511
  version: "1.0.0"
5477
5512
  },
5513
+ {
5514
+ action: "jira.issuelink.create",
5515
+ resource_type: "jira:project",
5516
+ required_relations: ["editor", "act_as"],
5517
+ required_scopes: ["write:jira-work"],
5518
+ capability: "jira.write.basic",
5519
+ input_schema: {
5520
+ type: "object",
5521
+ properties: {
5522
+ typeName: { type: "string", minLength: 1, description: "Link type name (e.g. Blocks, Relates)" },
5523
+ inwardIssueKey: { type: "string", minLength: 1 },
5524
+ outwardIssueKey: { type: "string", minLength: 1 },
5525
+ commentBody: { type: "string" }
5526
+ },
5527
+ required: ["typeName", "inwardIssueKey", "outwardIssueKey"],
5528
+ additionalProperties: false
5529
+ },
5530
+ constraints: { rate_bucket: "jira.write" },
5531
+ effects: ["Create:IssueLink"],
5532
+ risk: "high",
5533
+ target_bindings: {
5534
+ // 両 issue が touch されるが target_bindings は 1 つしか指定できないので
5535
+ // outwardIssueKey を主 binding として project_key を導出する。
5536
+ // 完全な制御をしたい場合は別途 inwardIssueKey 側も grant チェックする運用を要する。
5537
+ resource_id: { source: "param", param: "outwardIssueKey", derive: "project_key" }
5538
+ },
5539
+ version: "1.0.0"
5540
+ },
5541
+ {
5542
+ action: "jira.issuelink.delete",
5543
+ resource_type: "jira:issuelink",
5544
+ required_relations: ["editor", "act_as"],
5545
+ required_scopes: ["write:jira-work"],
5546
+ capability: "jira.write.basic",
5547
+ input_schema: {
5548
+ type: "object",
5549
+ properties: {
5550
+ linkId: { type: "string", minLength: 1, description: "Internal id of the issue link (from jira.issue.read fields.issuelinks[].id)" }
5551
+ },
5552
+ required: ["linkId"],
5553
+ additionalProperties: false
5554
+ },
5555
+ constraints: { rate_bucket: "jira.write" },
5556
+ effects: ["Delete:IssueLink"],
5557
+ risk: "high",
5558
+ target_bindings: {
5559
+ resource_id: { source: "param", param: "linkId" }
5560
+ },
5561
+ version: "1.0.0"
5562
+ },
5563
+ {
5564
+ action: "jira.issuelinktype.list",
5565
+ // workspace 全体のメタデータ取得なので、jira.project.read と同様 jira:project
5566
+ // resource として扱い、特定 project を要求しないことで全 viewer に許可する。
5567
+ resource_type: "jira:project",
5568
+ required_relations: ["viewer", "editor", "admin", "owner"],
5569
+ required_scopes: ["read:jira-work"],
5570
+ capability: "jira.read.basic",
5571
+ input_schema: {
5572
+ type: "object",
5573
+ properties: {},
5574
+ additionalProperties: false
5575
+ },
5576
+ constraints: { rate_bucket: "jira.read" },
5577
+ effects: ["Read:IssueLinkTypes"],
5578
+ risk: "low",
5579
+ // workspace 全体のメタデータなので resource_id は常に未解決のまま
5580
+ // type-only match で評価する (required: false がその挙動)。input_schema には
5581
+ // 該当 param が無いため param 値は実行時に必ず undefined になる。
5582
+ target_bindings: {
5583
+ resource_id: { source: "param", param: "projectKeyOrId", required: false }
5584
+ },
5585
+ version: "1.0.0"
5586
+ },
5478
5587
  // ─── OS Actions (Local) ───
5479
5588
  {
5480
5589
  action: "os.secret.read",
@@ -5611,14 +5720,14 @@ var ACTION_REGISTRY = {
5611
5720
  },
5612
5721
  {
5613
5722
  capability: "jira.read.basic",
5614
- description: "Read Jira issues, projects, boards, and sprints",
5615
- 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"],
5723
+ description: "Read Jira issues, projects, boards, sprints, and issue link types",
5724
+ 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"],
5616
5725
  version: "1.0.0"
5617
5726
  },
5618
5727
  {
5619
5728
  capability: "jira.write.basic",
5620
- description: "Create, update, and delete Jira issues",
5621
- includes: ["jira.issue.create", "jira.issue.update", "jira.issue.delete", "jira.comment.create", "jira.issue.transition"],
5729
+ description: "Create, update, delete Jira issues, and manage issue links",
5730
+ includes: ["jira.issue.create", "jira.issue.update", "jira.issue.delete", "jira.comment.create", "jira.issue.transition", "jira.issuelink.create", "jira.issuelink.delete"],
5622
5731
  version: "1.0.0"
5623
5732
  }
5624
5733
  ]
@@ -5795,6 +5904,46 @@ var GATEWAY_ERROR_CODE = {
5795
5904
  };
5796
5905
 
5797
5906
  // src/registry/action-summary.ts
5907
+ function extractJiraAssigneeDisplay(params) {
5908
+ const pickFromShape = (value) => {
5909
+ if (value === null) return null;
5910
+ if (typeof value === "string") return value.length > 0 ? value : void 0;
5911
+ if (value && typeof value === "object" && !Array.isArray(value)) {
5912
+ const id = value.accountId;
5913
+ if (id === null) return null;
5914
+ if (typeof id === "string" && id.length > 0) return id;
5915
+ }
5916
+ return void 0;
5917
+ };
5918
+ if ("assigneeAccountId" in params) {
5919
+ const v = params.assigneeAccountId;
5920
+ if (v === null) return null;
5921
+ if (typeof v === "string" && v.length > 0) return v;
5922
+ }
5923
+ if ("assignee" in params) {
5924
+ const picked = pickFromShape(params.assignee);
5925
+ if (picked !== void 0) return picked;
5926
+ }
5927
+ const fields = params.fields;
5928
+ if (fields && typeof fields === "object" && "assignee" in fields) {
5929
+ const picked = pickFromShape(fields.assignee);
5930
+ if (picked !== void 0) return picked;
5931
+ }
5932
+ return void 0;
5933
+ }
5934
+ function jiraField(params, topLevelKeys, nestedKey, nestedExtractor) {
5935
+ for (const k of topLevelKeys) {
5936
+ if (params[k] !== void 0 && params[k] !== null) return params[k];
5937
+ }
5938
+ const fields = params.fields;
5939
+ if (fields && typeof fields === "object") {
5940
+ const v = fields[nestedKey];
5941
+ if (v !== void 0 && v !== null) {
5942
+ return nestedExtractor ? nestedExtractor(v) : v;
5943
+ }
5944
+ }
5945
+ return void 0;
5946
+ }
5798
5947
  var ACTION_DISPLAY_CONFIGS = {
5799
5948
  "slack.message.post": {
5800
5949
  summaryTemplate: (p) => {
@@ -5865,28 +6014,105 @@ var ACTION_DISPLAY_CONFIGS = {
5865
6014
  "jira.issue.create": {
5866
6015
  summaryTemplate: (p) => {
5867
6016
  const parts = [];
5868
- if (p.project) parts.push(`${p.project}:`);
5869
- if (p.summary) parts.push(p.summary);
6017
+ const projectKey = jiraField(
6018
+ p,
6019
+ ["projectKey", "project"],
6020
+ "project",
6021
+ (v) => typeof v === "string" ? v : v?.key
6022
+ );
6023
+ const summary = jiraField(p, ["summary"], "summary");
6024
+ if (projectKey) parts.push(`${projectKey}:`);
6025
+ if (summary) parts.push(summary);
5870
6026
  return parts.join(" ");
5871
6027
  },
6028
+ // AIDENTITY-54: nested `fields.X` 形式と top-level canonical の両方を
6029
+ // 拾えるよう extract を使う。assignee は null (unassign) も表示。
6030
+ // legacy alias (project / issuetype 等) も top-level 候補に含めて後方互換を保つ。
5872
6031
  displayFields: [
5873
- { key: "project", label: "Project" },
5874
- { key: "issuetype", label: "Type" },
5875
- { key: "summary", label: "Summary" },
5876
- { key: "description", label: "Description" }
6032
+ {
6033
+ label: "Project",
6034
+ extract: (p) => jiraField(
6035
+ p,
6036
+ ["projectKey", "project"],
6037
+ "project",
6038
+ (v) => typeof v === "string" ? v : v?.key
6039
+ )
6040
+ },
6041
+ {
6042
+ label: "Type",
6043
+ extract: (p) => jiraField(
6044
+ p,
6045
+ ["issueTypeName", "issueType", "issuetype"],
6046
+ "issuetype",
6047
+ (v) => typeof v === "string" ? v : v?.name
6048
+ )
6049
+ },
6050
+ { label: "Summary", extract: (p) => jiraField(p, ["summary"], "summary") },
6051
+ { label: "Description", extract: (p) => jiraField(p, ["description"], "description") },
6052
+ {
6053
+ label: "Priority",
6054
+ extract: (p) => jiraField(
6055
+ p,
6056
+ ["priority"],
6057
+ "priority",
6058
+ (v) => typeof v === "string" ? v : v?.name
6059
+ )
6060
+ },
6061
+ { label: "Assignee", extract: extractJiraAssigneeDisplay },
6062
+ { label: "Labels", extract: (p) => jiraField(p, ["labels"], "labels") }
5877
6063
  ]
5878
6064
  },
5879
6065
  "jira.issue.update": {
5880
6066
  summaryTemplate: (p) => {
5881
6067
  const parts = [];
5882
- if (p.issueKey) parts.push(`${p.issueKey}:`);
5883
- if (p.summary) parts.push(p.summary);
6068
+ const key = p.issueIdOrKey ?? p.issueKey;
6069
+ const summary = jiraField(p, ["summary"], "summary");
6070
+ if (key) parts.push(`${key}:`);
6071
+ if (summary) parts.push(summary);
5884
6072
  return parts.join(" ");
5885
6073
  },
5886
6074
  displayFields: [
5887
- { key: "issueKey", label: "Issue" },
5888
- { key: "summary", label: "Summary" },
5889
- { key: "description", label: "Description" }
6075
+ // canonical issueIdOrKey、agent issueKey で送ってくる旧仕様も拾う。
6076
+ { label: "Issue", extract: (p) => p.issueIdOrKey ?? p.issueKey },
6077
+ { label: "Summary", extract: (p) => jiraField(p, ["summary"], "summary") },
6078
+ { label: "Description", extract: (p) => jiraField(p, ["description"], "description") },
6079
+ {
6080
+ label: "Priority",
6081
+ extract: (p) => jiraField(
6082
+ p,
6083
+ ["priority"],
6084
+ "priority",
6085
+ (v) => typeof v === "string" ? v : v?.name
6086
+ )
6087
+ },
6088
+ // AIDENTITY-54: top-level alias (string / object) と null (unassign) も解決。
6089
+ { label: "Assignee", extract: extractJiraAssigneeDisplay },
6090
+ { label: "Labels", extract: (p) => jiraField(p, ["labels"], "labels") }
6091
+ ]
6092
+ },
6093
+ // AIDENTITY-65: comment 本体は string と ADF document の両方を受けるため、
6094
+ // formatValue 側の ADF ハンドリング (extractFirstAdfText) に任せて key 指定で OK。
6095
+ "jira.comment.create": {
6096
+ summaryTemplate: (p) => {
6097
+ const parts = [];
6098
+ if (p.issueIdOrKey) parts.push(`${p.issueIdOrKey}:`);
6099
+ if (p.body) parts.push(typeof p.body === "string" ? p.body : "[ADF]");
6100
+ return parts.join(" ");
6101
+ },
6102
+ displayFields: [
6103
+ { key: "issueIdOrKey", label: "Issue" },
6104
+ { key: "body", label: "Comment" }
6105
+ ]
6106
+ },
6107
+ // AIDENTITY-65: API enricher が 'Link' label を upsert で書き換える。
6108
+ "jira.issuelink.delete": {
6109
+ summaryTemplate: (p) => {
6110
+ const parts = [];
6111
+ if (p.linkId) parts.push(`Delete link ${p.linkId}`);
6112
+ return parts.join(" ");
6113
+ },
6114
+ displayFields: [
6115
+ { key: "linkId", label: "Link" }
5890
6116
  ]
5891
6117
  }
5892
6118
  };
@@ -5895,7 +6121,8 @@ function truncate(text, maxLength) {
5895
6121
  return text.slice(0, maxLength - 3) + "...";
5896
6122
  }
5897
6123
  function formatValue(value) {
5898
- if (value === null || value === void 0) return "";
6124
+ if (value === void 0) return "";
6125
+ if (value === null) return "(unset)";
5899
6126
  if (Array.isArray(value)) {
5900
6127
  return value.map((item) => {
5901
6128
  if (item && typeof item === "object") {
@@ -5912,10 +6139,35 @@ function formatValue(value) {
5912
6139
  return obj.timeZone ? `${obj.dateTime} (${obj.timeZone})` : String(obj.dateTime);
5913
6140
  }
5914
6141
  if (obj.date) return String(obj.date);
6142
+ if (obj.type === "doc" && Array.isArray(obj.content)) {
6143
+ const firstText = extractFirstAdfText(obj.content);
6144
+ if (firstText) {
6145
+ const moreCount = obj.content.length - 1;
6146
+ const more = moreCount > 0 ? ` \u2026 (+${moreCount} block${moreCount > 1 ? "s" : ""})` : "";
6147
+ return `${firstText}${more}`;
6148
+ }
6149
+ return "(ADF document)";
6150
+ }
5915
6151
  return JSON.stringify(value);
5916
6152
  }
5917
6153
  return String(value);
5918
6154
  }
6155
+ function extractFirstAdfText(nodes) {
6156
+ for (const node of nodes) {
6157
+ if (!node || typeof node !== "object") continue;
6158
+ const n = node;
6159
+ if (n.type === "paragraph" || n.type === "heading") {
6160
+ const inner = n.content ?? [];
6161
+ for (const child of inner) {
6162
+ if (child && typeof child === "object") {
6163
+ const c = child;
6164
+ if (c.type === "text" && typeof c.text === "string") return c.text;
6165
+ }
6166
+ }
6167
+ }
6168
+ }
6169
+ return "";
6170
+ }
5919
6171
  var ACTION_PARAMS_MAX_SIZE = 1e4;
5920
6172
  function generateActionSummary(action, params, maxLength = 50) {
5921
6173
  if (!params || Object.keys(params).length === 0) return "";
@@ -5935,10 +6187,10 @@ function generateActionParamsDisplay(action, params) {
5935
6187
  if (!params || Object.keys(params).length === 0) return [];
5936
6188
  const config = ACTION_DISPLAY_CONFIGS[action];
5937
6189
  if (config) {
5938
- return config.displayFields.filter((f) => params[f.key] !== void 0 && params[f.key] !== null).map((f) => ({
5939
- label: f.label,
5940
- value: formatValue(params[f.key])
5941
- }));
6190
+ return config.displayFields.map((f) => {
6191
+ const raw = f.extract ? f.extract(params) : f.key ? params[f.key] : void 0;
6192
+ return { label: f.label, raw };
6193
+ }).filter((item) => item.raw !== void 0).map((item) => ({ label: item.label, value: formatValue(item.raw) }));
5942
6194
  }
5943
6195
  return Object.entries(params).filter(([, v]) => v !== void 0 && v !== null).slice(0, 3).map(([key, val]) => ({
5944
6196
  label: key,
@@ -6112,6 +6364,285 @@ function assertKeyMaterial(k) {
6112
6364
  }
6113
6365
  }
6114
6366
 
6367
+ // src/policy/cedar-engine.ts
6368
+ var CedarEngineUnavailableError = class extends Error {
6369
+ name = "CedarEngineUnavailableError";
6370
+ constructor(cause) {
6371
+ super(
6372
+ "Cedar wasm engine could not be loaded. This typically happens in non-Node environments (browser) or when the @cedar-policy/cedar-wasm/nodejs module fails to instantiate.",
6373
+ { cause }
6374
+ );
6375
+ }
6376
+ };
6377
+ var CedarParseError = class extends Error {
6378
+ name = "CedarParseError";
6379
+ errors;
6380
+ /**
6381
+ * Structured diagnostics with `{ code, message, line, column, context,
6382
+ * offset }`. Always non-empty when the throw is from cedar-wasm; may
6383
+ * be empty when constructed from a non-cedar-wasm path (e.g. when an
6384
+ * upstream caller wraps an unexpected throw).
6385
+ */
6386
+ validationErrors;
6387
+ constructor(message, errors, validationErrors = []) {
6388
+ super(message);
6389
+ this.errors = errors;
6390
+ this.validationErrors = validationErrors;
6391
+ }
6392
+ };
6393
+ var defaultLoader = async () => (
6394
+ // Dynamic import keeps browser bundlers from inlining the Node-only subpath.
6395
+ // The cast widens the upstream module to our minimal surface above; we don't
6396
+ // re-export the upstream types.
6397
+ await import("@cedar-policy/cedar-wasm/nodejs")
6398
+ );
6399
+ var activeLoader = defaultLoader;
6400
+ var enginePromise = null;
6401
+ async function createCedarEngine() {
6402
+ if (enginePromise) return enginePromise;
6403
+ const inFlight = doCreateCedarEngine(activeLoader).catch((err) => {
6404
+ if (enginePromise === inFlight) {
6405
+ enginePromise = null;
6406
+ }
6407
+ throw err;
6408
+ });
6409
+ enginePromise = inFlight;
6410
+ return enginePromise;
6411
+ }
6412
+ async function doCreateCedarEngine(loader) {
6413
+ let mod;
6414
+ try {
6415
+ mod = await loader();
6416
+ } catch (err) {
6417
+ throw new CedarEngineUnavailableError(err);
6418
+ }
6419
+ let handleCounter = 0;
6420
+ const nextId = (kind) => `${kind}-${++handleCounter}-${Date.now().toString(36)}`;
6421
+ const adapter = {
6422
+ preparseSchema(schemaText) {
6423
+ const name = nextId("schema");
6424
+ const ans = mod.preparseSchema(name, schemaText);
6425
+ if (ans.type === "failure") {
6426
+ throw new CedarParseError(
6427
+ `Failed to parse Cedar schema: ${ans.errors[0]?.message ?? "unknown error"}`,
6428
+ ans.errors.map(toCedarError),
6429
+ buildValidationErrors(ans.errors, schemaText)
6430
+ );
6431
+ }
6432
+ return { __cedar: "schema", name };
6433
+ },
6434
+ preparsePolicySet(cedarText) {
6435
+ const id = nextId("pset");
6436
+ const ans = mod.preparsePolicySet(id, { staticPolicies: cedarText });
6437
+ if (ans.type === "failure") {
6438
+ throw new CedarParseError(
6439
+ `Failed to parse Cedar PolicySet: ${ans.errors[0]?.message ?? "unknown error"}`,
6440
+ ans.errors.map(toCedarError),
6441
+ buildValidationErrors(ans.errors, cedarText)
6442
+ );
6443
+ }
6444
+ return { __cedar: "policySet", id };
6445
+ },
6446
+ evaluate(input) {
6447
+ const call = {
6448
+ principal: parseEntityUid(input.request.principal),
6449
+ action: parseEntityUid(input.request.action),
6450
+ resource: parseEntityUid(input.request.resource),
6451
+ context: input.request.context ?? {},
6452
+ preparsedPolicySetId: input.policySetHandle.id,
6453
+ entities: input.entities
6454
+ };
6455
+ if (input.schemaHandle) {
6456
+ call.preparsedSchemaName = input.schemaHandle.name;
6457
+ call.validateRequest = true;
6458
+ }
6459
+ const ans = mod.statefulIsAuthorized(call);
6460
+ if (ans.type === "failure") {
6461
+ return {
6462
+ decision: "Deny",
6463
+ reasons: [],
6464
+ errors: ans.errors.map(toCedarError)
6465
+ };
6466
+ }
6467
+ return {
6468
+ decision: ans.response.decision === "allow" ? "Allow" : "Deny",
6469
+ reasons: ans.response.diagnostics.reason ?? [],
6470
+ errors: (ans.response.diagnostics.errors ?? []).map((e) => ({
6471
+ policyId: e.policyId,
6472
+ message: e.error.message,
6473
+ code: e.error.code ?? void 0
6474
+ }))
6475
+ };
6476
+ }
6477
+ };
6478
+ return adapter;
6479
+ }
6480
+ function toCedarError(e) {
6481
+ return {
6482
+ message: e.message,
6483
+ code: e.code ?? void 0
6484
+ };
6485
+ }
6486
+ function buildValidationErrors(errors, sourceText) {
6487
+ const out = [];
6488
+ const MAX_DEPTH = 10;
6489
+ const visit = (e, depth) => {
6490
+ if (depth >= MAX_DEPTH) return;
6491
+ const code = classifyCedarErrorMessage(e.message, e.code ?? void 0);
6492
+ const loc = (e.sourceLocations ?? []).find(
6493
+ (l) => typeof l?.start === "number"
6494
+ );
6495
+ const offset = typeof loc?.start === "number" ? loc.start : void 0;
6496
+ const end = typeof loc?.end === "number" ? loc.end : void 0;
6497
+ const lc = offset !== void 0 ? offsetToLineColumn(sourceText, offset) : null;
6498
+ const context = offset !== void 0 && end !== void 0 && end > offset ? truncateContext(sourceText.slice(offset, end)) : void 0;
6499
+ out.push({
6500
+ code,
6501
+ message: e.message,
6502
+ ...lc ? { line: lc.line, column: lc.column } : {},
6503
+ ...context !== void 0 ? { context } : {},
6504
+ ...offset !== void 0 ? { offset } : {}
6505
+ });
6506
+ if (e.related && Array.isArray(e.related)) {
6507
+ for (const child of e.related) visit(child, depth + 1);
6508
+ }
6509
+ };
6510
+ for (const e of errors) visit(e, 0);
6511
+ return out;
6512
+ }
6513
+ function classifyCedarErrorMessage(message, cedarCode) {
6514
+ if (cedarCode && cedarCode.length > 0) return cedarCode;
6515
+ const m = message.toLowerCase();
6516
+ if (m.includes("unexpected end of input")) return "unexpected_end_of_input";
6517
+ if (m.includes("unexpected token")) return "unexpected_token";
6518
+ if (m.includes("unknown extension")) return "unknown_extension";
6519
+ if (m.includes("failed to parse")) return "parse_error";
6520
+ return "unknown";
6521
+ }
6522
+ function offsetToLineColumn(text, offset) {
6523
+ const safe = Math.max(0, Math.min(offset, text.length));
6524
+ let line = 1;
6525
+ let lineStart = 0;
6526
+ for (let i = 0; i < safe; i++) {
6527
+ if (text.charCodeAt(i) === 10) {
6528
+ line += 1;
6529
+ lineStart = i + 1;
6530
+ }
6531
+ }
6532
+ return { line, column: safe - lineStart + 1 };
6533
+ }
6534
+ function truncateContext(slice) {
6535
+ const max = 200;
6536
+ if (slice.length <= max) return slice;
6537
+ return slice.slice(0, max - 1) + "\u2026";
6538
+ }
6539
+ var ENTITY_UID_PATTERN = /^([A-Za-z_]\w*(?:::[A-Za-z_]\w*)*)::"((?:[^"\\]|\\.)*)"$/;
6540
+ function parseEntityUid(uid) {
6541
+ const m = uid.match(ENTITY_UID_PATTERN);
6542
+ if (!m) {
6543
+ throw new Error(
6544
+ `Invalid Cedar entity uid expression: ${JSON.stringify(uid)}. Expected form: Type::"id" (e.g. Agent::"agent-1").`
6545
+ );
6546
+ }
6547
+ return {
6548
+ type: m[1],
6549
+ // Unescape standard Cedar string escapes (\" → ").
6550
+ id: m[2].replace(/\\(.)/g, "$1")
6551
+ };
6552
+ }
6553
+
6554
+ // src/registry/action-risk.ts
6555
+ var HIGH_RISK_SUFFIXES = /* @__PURE__ */ new Set([
6556
+ "send",
6557
+ "post",
6558
+ "create",
6559
+ "update",
6560
+ "delete",
6561
+ "remove",
6562
+ "write",
6563
+ "modify",
6564
+ "upload",
6565
+ "invite",
6566
+ "archive",
6567
+ "unarchive",
6568
+ "kick",
6569
+ "rename",
6570
+ "patch",
6571
+ "put"
6572
+ ]);
6573
+ var LOW_RISK_SUFFIXES = /* @__PURE__ */ new Set([
6574
+ "read",
6575
+ "list",
6576
+ "get",
6577
+ "search",
6578
+ "find",
6579
+ "lookup",
6580
+ "show",
6581
+ "view",
6582
+ "fetch",
6583
+ "history",
6584
+ "info"
6585
+ ]);
6586
+ var REGISTRY_RISK_BY_ACTION = (() => {
6587
+ const map = /* @__PURE__ */ new Map();
6588
+ for (const entry of ACTION_REGISTRY.actions) {
6589
+ if (typeof entry.action === "string" && typeof entry.risk === "string") {
6590
+ map.set(entry.action.toLowerCase(), entry.risk);
6591
+ }
6592
+ }
6593
+ return map;
6594
+ })();
6595
+ function resolveActionRiskBySuffix(lowerAction) {
6596
+ const segments = lowerAction.split(".");
6597
+ const last = segments[segments.length - 1] ?? "";
6598
+ if (!last) return "medium";
6599
+ if (HIGH_RISK_SUFFIXES.has(last)) return "high";
6600
+ if (LOW_RISK_SUFFIXES.has(last)) return "low";
6601
+ return "medium";
6602
+ }
6603
+ function resolveActionRisk(action) {
6604
+ if (!action || typeof action !== "string") return "medium";
6605
+ const lower = action.toLowerCase();
6606
+ const registryRisk = REGISTRY_RISK_BY_ACTION.get(lower);
6607
+ if (registryRisk) return registryRisk;
6608
+ return resolveActionRiskBySuffix(lower);
6609
+ }
6610
+
6611
+ // src/policy/cedar-entities.ts
6612
+ function buildCedarEntities(input) {
6613
+ const { principal, action, resource } = input;
6614
+ const principalEntity = {
6615
+ uid: { type: principal.type, id: principal.id },
6616
+ attrs: principal.attrs ?? {},
6617
+ parents: []
6618
+ };
6619
+ const actionEntity = {
6620
+ uid: { type: "Action", id: action },
6621
+ attrs: { risk_level: resolveActionRisk(action) },
6622
+ parents: []
6623
+ };
6624
+ const resourceEntity = {
6625
+ uid: { type: resource.type, id: resource.id },
6626
+ attrs: resource.attrs ?? {},
6627
+ parents: []
6628
+ };
6629
+ return [principalEntity, actionEntity, resourceEntity];
6630
+ }
6631
+
6632
+ // src/policy/decision.ts
6633
+ var DECISION_VALUES = [
6634
+ "permit",
6635
+ "auth_required",
6636
+ "input_required",
6637
+ "denied",
6638
+ "denied_default",
6639
+ "denied_by_user",
6640
+ "indeterminate"
6641
+ ];
6642
+ function isDecision(value) {
6643
+ return typeof value === "string" && DECISION_VALUES.includes(value);
6644
+ }
6645
+
6115
6646
  // src/index.ts
6116
6647
  var version = "0.0.1";
6117
6648
  // Annotate the CommonJS export names for ESM import in node:
@@ -6130,9 +6661,12 @@ var version = "0.0.1";
6130
6661
  AuthProvider,
6131
6662
  AuthenticationError,
6132
6663
  CANONICAL_PROVIDERS,
6664
+ CedarEngineUnavailableError,
6665
+ CedarParseError,
6133
6666
  ConstraintEvaluator,
6134
6667
  CredentialStatus,
6135
6668
  CredentialType,
6669
+ DECISION_VALUES,
6136
6670
  DEFAULT_CONSTRAINTS_BY_RISK,
6137
6671
  DeviceEnrollManager,
6138
6672
  DummyCreds,
@@ -6154,6 +6688,7 @@ var version = "0.0.1";
6154
6688
  MemoryKeyStorage,
6155
6689
  NetworkError,
6156
6690
  OAuthProvider,
6691
+ PHASE_1_VC_LAYER,
6157
6692
  PROVIDER_ALIASES,
6158
6693
  REAUTH_REQUIRED_ACTION,
6159
6694
  RESOURCE_TYPES,
@@ -6179,12 +6714,17 @@ var version = "0.0.1";
6179
6714
  VPManager,
6180
6715
  WRITE_ACTION_NAMES,
6181
6716
  buildCanonicalString,
6717
+ buildCedarEntities,
6182
6718
  buildGrantIdFields,
6183
6719
  buildKbJwtPayload,
6720
+ buildPhase1VcClaims,
6721
+ buildValidationErrors,
6184
6722
  canonicalizeAction,
6185
6723
  checkPermissionWithVP,
6724
+ classifyCedarErrorMessage,
6186
6725
  configure,
6187
6726
  createAjv,
6727
+ createCedarEngine,
6188
6728
  createDidJwk,
6189
6729
  credentialStatusToVCStatus,
6190
6730
  defaultConstraintEvaluator,
@@ -6213,6 +6753,9 @@ var version = "0.0.1";
6213
6753
  indexCapabilities,
6214
6754
  isActionEquivalent,
6215
6755
  isCanonicalProvider,
6756
+ isDecision,
6757
+ isPolicyRefInline,
6758
+ isPolicyRefReference,
6216
6759
  isUnlimited,
6217
6760
  isValidDidJwk,
6218
6761
  isValidProvider,
@@ -6227,6 +6770,7 @@ var version = "0.0.1";
6227
6770
  planDelegationForVC,
6228
6771
  publicKeysMatch,
6229
6772
  readVcExpSeconds,
6773
+ resolveActionRisk,
6230
6774
  resolveActionsFromSelection,
6231
6775
  resolveProvider,
6232
6776
  resolveResourceType,