avorelo 0.1.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 (258) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +56 -0
  3. package/bin/avorelo +9 -0
  4. package/package.json +135 -0
  5. package/scripts/README.md +40 -0
  6. package/scripts/cco-dashboard.js +252 -0
  7. package/scripts/cco-status.js +430 -0
  8. package/scripts/lib/activation/account-state.js +37 -0
  9. package/scripts/lib/activation/activation-runner.js +546 -0
  10. package/scripts/lib/activation/activation-self-healing.js +480 -0
  11. package/scripts/lib/activation/activation-state.js +83 -0
  12. package/scripts/lib/activation/activation-summary.js +191 -0
  13. package/scripts/lib/activation/adapters/claude-code.js +77 -0
  14. package/scripts/lib/activation/adapters/codex-cli.js +52 -0
  15. package/scripts/lib/activation/adapters/cursor.js +37 -0
  16. package/scripts/lib/activation/adapters/github-agent.js +39 -0
  17. package/scripts/lib/activation/adapters/terminal.js +42 -0
  18. package/scripts/lib/activation/adapters/vscode.js +39 -0
  19. package/scripts/lib/activation/adapters/windsurf.js +37 -0
  20. package/scripts/lib/activation/ai-surface-detector.js +151 -0
  21. package/scripts/lib/activation/connect-account.js +145 -0
  22. package/scripts/lib/activation/detect-environment.js +75 -0
  23. package/scripts/lib/activation/detect-hosts.js +62 -0
  24. package/scripts/lib/activation/format-activation-output.js +109 -0
  25. package/scripts/lib/activation/next-action.js +43 -0
  26. package/scripts/lib/activation/repair-engine.js +219 -0
  27. package/scripts/lib/activation-distribution-readiness.js +507 -0
  28. package/scripts/lib/adapter-conformance.js +176 -0
  29. package/scripts/lib/adapter-readiness.js +417 -0
  30. package/scripts/lib/adapter-safety-boundaries.js +335 -0
  31. package/scripts/lib/adapter-technical-readiness-gate.js +205 -0
  32. package/scripts/lib/agent-access-governance.js +455 -0
  33. package/scripts/lib/agent-enforcement.js +765 -0
  34. package/scripts/lib/agent-policy-profile.js +210 -0
  35. package/scripts/lib/agent-security/action-evaluator.js +507 -0
  36. package/scripts/lib/agent-security/adapter-registry.js +98 -0
  37. package/scripts/lib/agent-security/auto-policy.js +139 -0
  38. package/scripts/lib/agent-security/bounded-scan.js +93 -0
  39. package/scripts/lib/agent-security/enforcement-adapter.js +174 -0
  40. package/scripts/lib/agent-security/enforcement-engine.js +1129 -0
  41. package/scripts/lib/agent-security/file-write-adapter.js +183 -0
  42. package/scripts/lib/agent-security/file-write-rules.js +178 -0
  43. package/scripts/lib/agent-security/index.js +3342 -0
  44. package/scripts/lib/agent-security/instruction-risk.js +181 -0
  45. package/scripts/lib/agent-security/mcp-action-adapter.js +185 -0
  46. package/scripts/lib/agent-security/mcp-action-rules.js +184 -0
  47. package/scripts/lib/agent-security/package-action-adapter.js +175 -0
  48. package/scripts/lib/agent-security/package-action-rules.js +233 -0
  49. package/scripts/lib/agent-security/performance.js +148 -0
  50. package/scripts/lib/agent-security/permission-minimizer.js +403 -0
  51. package/scripts/lib/agent-security/scan-cache.js +74 -0
  52. package/scripts/lib/agent-security/source-trust.js +146 -0
  53. package/scripts/lib/ai-install-prompt.js +288 -0
  54. package/scripts/lib/ai-workspace-hygiene.js +1499 -0
  55. package/scripts/lib/alpha-activation.js +520 -0
  56. package/scripts/lib/alpha-feedback.js +263 -0
  57. package/scripts/lib/alpha-readiness-gate.js +332 -0
  58. package/scripts/lib/anti-gaming.js +169 -0
  59. package/scripts/lib/artifact-health.js +431 -0
  60. package/scripts/lib/attribution.js +180 -0
  61. package/scripts/lib/audit.js +289 -0
  62. package/scripts/lib/avorelo-skill-registry.js +810 -0
  63. package/scripts/lib/batch-jobs.js +71 -0
  64. package/scripts/lib/brain-pack.js +578 -0
  65. package/scripts/lib/brand-boundary.js +424 -0
  66. package/scripts/lib/brand.js +74 -0
  67. package/scripts/lib/browser-capability.js +1048 -0
  68. package/scripts/lib/browser-proof-preflight.js +321 -0
  69. package/scripts/lib/cache-readiness.js +187 -0
  70. package/scripts/lib/canonical-reentry.js +162 -0
  71. package/scripts/lib/capability-packs.js +314 -0
  72. package/scripts/lib/capability-recommender.js +512 -0
  73. package/scripts/lib/capability-registry.js +1059 -0
  74. package/scripts/lib/carry-forward-surfacing.js +194 -0
  75. package/scripts/lib/ccusage-adapter.js +188 -0
  76. package/scripts/lib/company-loop.js +1149 -0
  77. package/scripts/lib/config.js +637 -0
  78. package/scripts/lib/context-acquisition-plan.js +287 -0
  79. package/scripts/lib/context-budget-guard.js +170 -0
  80. package/scripts/lib/context-budget-scanner.js +257 -0
  81. package/scripts/lib/context-optimizer.js +715 -0
  82. package/scripts/lib/context-reduction-plan.js +178 -0
  83. package/scripts/lib/context-safety.js +88 -0
  84. package/scripts/lib/context-savings-engine.js +158 -0
  85. package/scripts/lib/cost-evidence.js +254 -0
  86. package/scripts/lib/cross-host-install-plan.js +308 -0
  87. package/scripts/lib/cross-host-install-readiness.js +237 -0
  88. package/scripts/lib/cross-host-value-flow.js +268 -0
  89. package/scripts/lib/dashboard.js +900 -0
  90. package/scripts/lib/design-partner-feedback.js +346 -0
  91. package/scripts/lib/entitlements.js +100 -0
  92. package/scripts/lib/execution-packet.js +559 -0
  93. package/scripts/lib/experimentation-events.js +547 -0
  94. package/scripts/lib/external-capability-compliance.js +107 -0
  95. package/scripts/lib/external-user-simulation.js +166 -0
  96. package/scripts/lib/failure-recovery-readiness.js +81 -0
  97. package/scripts/lib/failure-recovery.js +419 -0
  98. package/scripts/lib/feedback-intelligence.js +537 -0
  99. package/scripts/lib/feedback-signals.js +205 -0
  100. package/scripts/lib/file-integrity.js +68 -0
  101. package/scripts/lib/fsx.js +127 -0
  102. package/scripts/lib/full-readiness-gate.js +451 -0
  103. package/scripts/lib/guidance-builder.js +174 -0
  104. package/scripts/lib/hook-apply.js +1019 -0
  105. package/scripts/lib/hook-baseline.js +310 -0
  106. package/scripts/lib/hook-config-preview.js +275 -0
  107. package/scripts/lib/hook-contracts.js +290 -0
  108. package/scripts/lib/hook-safety-boundary-readiness.js +80 -0
  109. package/scripts/lib/host-capability-matrix.js +351 -0
  110. package/scripts/lib/host-support-context.js +254 -0
  111. package/scripts/lib/http-hook-action.js +538 -0
  112. package/scripts/lib/install-ai-readiness.js +84 -0
  113. package/scripts/lib/install-intake-risk.js +1037 -0
  114. package/scripts/lib/install-journey-intelligence.js +329 -0
  115. package/scripts/lib/intervention-guidance.js +57 -0
  116. package/scripts/lib/known-limitations.js +115 -0
  117. package/scripts/lib/l8-path-truth.js +146 -0
  118. package/scripts/lib/launch-hardening-gate.js +436 -0
  119. package/scripts/lib/launch-readiness.js +628 -0
  120. package/scripts/lib/learning-memory.js +686 -0
  121. package/scripts/lib/lifecycle-hooks.js +802 -0
  122. package/scripts/lib/local-package-smoke.js +423 -0
  123. package/scripts/lib/local-pricing.js +299 -0
  124. package/scripts/lib/mcp-enforcement.js +311 -0
  125. package/scripts/lib/mcp-least-privilege-policy.js +303 -0
  126. package/scripts/lib/mcp-tool-inventory.js +388 -0
  127. package/scripts/lib/mcp-tool-risk.js +0 -0
  128. package/scripts/lib/memory.js +335 -0
  129. package/scripts/lib/metrics.js +699 -0
  130. package/scripts/lib/micro-proof.js +133 -0
  131. package/scripts/lib/next-run-context.js +436 -0
  132. package/scripts/lib/operating-value.js +1648 -0
  133. package/scripts/lib/optimization-v3.js +122 -0
  134. package/scripts/lib/orchestration/adapters/_shared.js +49 -0
  135. package/scripts/lib/orchestration/adapters/aider.js +18 -0
  136. package/scripts/lib/orchestration/adapters/claude-code.js +35 -0
  137. package/scripts/lib/orchestration/adapters/codex.js +35 -0
  138. package/scripts/lib/orchestration/adapters/gemini-cli.js +18 -0
  139. package/scripts/lib/orchestration/adapters/git.js +25 -0
  140. package/scripts/lib/orchestration/adapters/index.js +31 -0
  141. package/scripts/lib/orchestration/adapters/lm-studio.js +18 -0
  142. package/scripts/lib/orchestration/adapters/ollama.js +18 -0
  143. package/scripts/lib/orchestration/adapters/opencode.js +18 -0
  144. package/scripts/lib/orchestration/adapters/openrouter.js +18 -0
  145. package/scripts/lib/orchestration/adapters/test-runner.js +25 -0
  146. package/scripts/lib/orchestration/cli.js +438 -0
  147. package/scripts/lib/orchestration/execution-manager.js +279 -0
  148. package/scripts/lib/orchestration/handoff.js +314 -0
  149. package/scripts/lib/orchestration/index.js +456 -0
  150. package/scripts/lib/orchestration/inventory.js +47 -0
  151. package/scripts/lib/orchestration/model-discovery.js +498 -0
  152. package/scripts/lib/orchestration/model-profiler.js +170 -0
  153. package/scripts/lib/orchestration/model-profiles.js +252 -0
  154. package/scripts/lib/orchestration/model-refresh-policy.js +72 -0
  155. package/scripts/lib/orchestration/proof-writer.js +349 -0
  156. package/scripts/lib/orchestration/provider-discovery/aider.js +49 -0
  157. package/scripts/lib/orchestration/provider-discovery/claude-code.js +56 -0
  158. package/scripts/lib/orchestration/provider-discovery/codex.js +49 -0
  159. package/scripts/lib/orchestration/provider-discovery/common.js +186 -0
  160. package/scripts/lib/orchestration/provider-discovery/gemini.js +106 -0
  161. package/scripts/lib/orchestration/provider-discovery/lm-studio.js +118 -0
  162. package/scripts/lib/orchestration/provider-discovery/models-dev.js +12 -0
  163. package/scripts/lib/orchestration/provider-discovery/ollama.js +100 -0
  164. package/scripts/lib/orchestration/provider-discovery/opencode.js +47 -0
  165. package/scripts/lib/orchestration/provider-discovery/openrouter.js +44 -0
  166. package/scripts/lib/orchestration/risk-classifier.js +130 -0
  167. package/scripts/lib/orchestration/routing-policy.js +486 -0
  168. package/scripts/lib/orchestration/settings.js +112 -0
  169. package/scripts/lib/orchestration/state.js +165 -0
  170. package/scripts/lib/orchestration/verification-manager.js +138 -0
  171. package/scripts/lib/output-profiles.js +146 -0
  172. package/scripts/lib/package-content-audit.js +368 -0
  173. package/scripts/lib/package-runtime.js +278 -0
  174. package/scripts/lib/plan-surface.js +53 -0
  175. package/scripts/lib/plans.js +2318 -0
  176. package/scripts/lib/policy-provider.js +27 -0
  177. package/scripts/lib/prelaunch-activation-readiness.js +409 -0
  178. package/scripts/lib/prelaunch-evidence-store.js +816 -0
  179. package/scripts/lib/prelaunch-intelligence.js +869 -0
  180. package/scripts/lib/pricing-experiment.js +118 -0
  181. package/scripts/lib/pro-moment-events.js +77 -0
  182. package/scripts/lib/pro-moment-state.js +227 -0
  183. package/scripts/lib/pro-moments.js +1216 -0
  184. package/scripts/lib/product-learning-events.js +629 -0
  185. package/scripts/lib/project-profile.js +555 -0
  186. package/scripts/lib/prompt-compiler.js +280 -0
  187. package/scripts/lib/prompt-lint.js +32 -0
  188. package/scripts/lib/prompt-suggestions.js +52 -0
  189. package/scripts/lib/proof-canonical.js +398 -0
  190. package/scripts/lib/proof-drilldown.js +383 -0
  191. package/scripts/lib/proof-events.js +342 -0
  192. package/scripts/lib/proof-history.js +243 -0
  193. package/scripts/lib/proof-metrics.js +296 -0
  194. package/scripts/lib/proof-outcome-evidence.js +134 -0
  195. package/scripts/lib/proof-receipt.js +335 -0
  196. package/scripts/lib/proof-record.js +461 -0
  197. package/scripts/lib/public-activation-distribution-gate.js +258 -0
  198. package/scripts/lib/public-cli.js +3891 -0
  199. package/scripts/lib/public-distribution-truth.js +211 -0
  200. package/scripts/lib/public-install-claim-checker.js +294 -0
  201. package/scripts/lib/publish-provenance-readiness.js +283 -0
  202. package/scripts/lib/readiness-delta.js +218 -0
  203. package/scripts/lib/readiness-evidence-closure.js +196 -0
  204. package/scripts/lib/reentry-memory-capture.js +241 -0
  205. package/scripts/lib/reentry-memory-retrieval.js +302 -0
  206. package/scripts/lib/reentry-memory-status.js +146 -0
  207. package/scripts/lib/reentry-memory-store.js +178 -0
  208. package/scripts/lib/reentry-state.js +66 -0
  209. package/scripts/lib/release-candidate-bundle.js +166 -0
  210. package/scripts/lib/remediation.js +81 -0
  211. package/scripts/lib/repo-map.js +391 -0
  212. package/scripts/lib/run-improvements-lifecycle.js +330 -0
  213. package/scripts/lib/run-improvements.js +789 -0
  214. package/scripts/lib/runtime-decision-policy.js +387 -0
  215. package/scripts/lib/safe-path-engine.js +705 -0
  216. package/scripts/lib/safe-run-controller.js +887 -0
  217. package/scripts/lib/score.js +262 -0
  218. package/scripts/lib/seamless-enforcement.js +329 -0
  219. package/scripts/lib/seamless-outcome.js +689 -0
  220. package/scripts/lib/seamless-reality-gate.js +5043 -0
  221. package/scripts/lib/security-risk-classifier.js +511 -0
  222. package/scripts/lib/security-scan.js +384 -0
  223. package/scripts/lib/session-context-optimizer.js +1211 -0
  224. package/scripts/lib/session-timing.js +315 -0
  225. package/scripts/lib/skill-hygiene.js +805 -0
  226. package/scripts/lib/skill-packs.js +161 -0
  227. package/scripts/lib/skills-operating-layer.js +580 -0
  228. package/scripts/lib/smart-work-routing.js +768 -0
  229. package/scripts/lib/source-catalog.js +700 -0
  230. package/scripts/lib/status-value-summary.js +32 -0
  231. package/scripts/lib/support-bundle.js +578 -0
  232. package/scripts/lib/task-continuation.js +440 -0
  233. package/scripts/lib/test-helpers.js +15 -0
  234. package/scripts/lib/tier.js +38 -0
  235. package/scripts/lib/token-context-quality-gate.js +370 -0
  236. package/scripts/lib/token-cost-capture.js +187 -0
  237. package/scripts/lib/token-cost-intelligence.js +358 -0
  238. package/scripts/lib/token-efficiency-evidence.js +213 -0
  239. package/scripts/lib/token-evidence.js +699 -0
  240. package/scripts/lib/tokenish.js +17 -0
  241. package/scripts/lib/tool-output-sandbox.js +304 -0
  242. package/scripts/lib/trust-audit.js +136 -0
  243. package/scripts/lib/unified-events.js +396 -0
  244. package/scripts/lib/upgrade-interruption-recovery.js +407 -0
  245. package/scripts/lib/usage-ledger.js +201 -0
  246. package/scripts/lib/value-ledger.js +130 -0
  247. package/scripts/lib/value-proof-calibration.js +531 -0
  248. package/scripts/lib/visual-qa.js +231 -0
  249. package/scripts/lib/voice-alpha.js +29 -0
  250. package/scripts/lib/work-aware-orchestration.js +976 -0
  251. package/scripts/lib/work-control-receipts.js +577 -0
  252. package/scripts/lib/work-ledger.js +1123 -0
  253. package/scripts/lib/work-panel-preview.js +352 -0
  254. package/scripts/lib/workflow-discipline.js +280 -0
  255. package/scripts/lib/workflow-signals.js +419 -0
  256. package/scripts/lib/workspace-map.js +281 -0
  257. package/scripts/lib/workspace-registry.js +1367 -0
  258. package/scripts/lib/workspace-resolver.js +480 -0
@@ -0,0 +1,455 @@
1
+ "use strict";
2
+
3
+ const crypto = require("crypto");
4
+ const path = require("path");
5
+ const { canExportReports } = require("./entitlements");
6
+ const { ensureCcoDirs, nowIso, safeReadJson, safeWriteJson } = require("./fsx");
7
+
8
+ const GOVERNANCE_CONTRACT = "avorelo.agentAccessGovernance.v1";
9
+ const GOVERNANCE_SCHEMA_VERSION = 1;
10
+ const SUBJECT_TYPES = Object.freeze([
11
+ "agent_surface",
12
+ "tool",
13
+ "mcp_server",
14
+ "browser_integration",
15
+ "package",
16
+ "extension",
17
+ "connector",
18
+ "skill",
19
+ "command",
20
+ "unknown",
21
+ ]);
22
+ const TRUST_STATUSES = Object.freeze(["known", "reviewed", "unknown", "blocked"]);
23
+ const REQUESTED_ACTION_TYPES = Object.freeze([
24
+ "command_run",
25
+ "tool_call",
26
+ "mcp_call",
27
+ "browser_action",
28
+ "network_request",
29
+ "file_read",
30
+ "file_write",
31
+ "deploy_publish",
32
+ "auth_billing_ci_prod_change",
33
+ "unknown",
34
+ ]);
35
+ const ACCESS_MODES = Object.freeze(["read_only", "write", "execute", "network", "browser", "unknown"]);
36
+ const DECISIONS = Object.freeze(["allow", "warn", "approval_required", "block"]);
37
+
38
+ const LATEST_RECEIPT_REL_PATH = ".claude/cco/security/agent-access-governance/latest-receipt.json";
39
+ const HISTORY_DIR_REL_PATH = ".claude/cco/security/agent-access-governance/history";
40
+ const EVENT_LOG_REL_PATH = ".claude/cco/events/agent-access-governance.jsonl";
41
+
42
+ function sha256(value) {
43
+ return crypto.createHash("sha256").update(String(value || "")).digest("hex");
44
+ }
45
+
46
+ function unique(values) {
47
+ return [...new Set((values || []).filter(Boolean))];
48
+ }
49
+
50
+ function normalizeEnum(value, allowed, fallback) {
51
+ const normalized = String(value || "").trim().toLowerCase();
52
+ return allowed.includes(normalized) ? normalized : fallback;
53
+ }
54
+
55
+ function normalizeSubjectType(value) {
56
+ return normalizeEnum(value, SUBJECT_TYPES, "unknown");
57
+ }
58
+
59
+ function normalizeTrustStatus(value) {
60
+ return normalizeEnum(value, TRUST_STATUSES, "unknown");
61
+ }
62
+
63
+ function normalizeRequestedActionType(value) {
64
+ return normalizeEnum(value, REQUESTED_ACTION_TYPES, "unknown");
65
+ }
66
+
67
+ function normalizeAccessMode(value) {
68
+ return normalizeEnum(value, ACCESS_MODES, "unknown");
69
+ }
70
+
71
+ function normalizePathList(value) {
72
+ const list = Array.isArray(value) ? value : value ? [value] : [];
73
+ return list
74
+ .map((item) => String(item || "").replace(/\\/g, "/").trim())
75
+ .filter(Boolean);
76
+ }
77
+
78
+ function normalizeDomainList(value) {
79
+ const list = Array.isArray(value) ? value : value ? [value] : [];
80
+ return list
81
+ .map((item) => String(item || "").trim().toLowerCase())
82
+ .filter(Boolean);
83
+ }
84
+
85
+ function normalizeOptionalString(value) {
86
+ const text = String(value || "").trim();
87
+ return text || null;
88
+ }
89
+
90
+ function normalizeOwnerSponsor(value, fallback) {
91
+ const text = normalizeOptionalString(value);
92
+ return text || fallback;
93
+ }
94
+
95
+ function requestedActionTypeFromInput(input = {}, classification = null) {
96
+ const raw = String(input.actionType || "").trim().toLowerCase();
97
+ if (raw === "command_run" || raw === "git_operation") return "command_run";
98
+ if (raw === "tool_call") return "tool_call";
99
+ if (raw === "mcp_tool_call" || raw === "mcp_call") return "mcp_call";
100
+ if (raw === "browser_action" || raw === "visual_qa_run") return "browser_action";
101
+ if (raw === "network_request") return "network_request";
102
+ if (raw === "file_read") return "file_read";
103
+ if (raw === "file_write" || raw === "config_change") return "file_write";
104
+ if (raw === "deploy_operation" || raw === "deploy_publish") return "deploy_publish";
105
+ const reasonCodes = new Set(classification?.combined?.reasonCodes || []);
106
+ if (reasonCodes.has("AUTH_OR_BILLING_SCOPE") || reasonCodes.has("DEPLOYMENT_CONFIG") || reasonCodes.has("CI_CONFIG")) {
107
+ return "auth_billing_ci_prod_change";
108
+ }
109
+ return "unknown";
110
+ }
111
+
112
+ function inferSubjectType(input = {}, requestedActionType = "unknown") {
113
+ const raw = String(input.actionType || "").trim().toLowerCase();
114
+ if (input.subject && typeof input.subject === "object" && input.subject.type) {
115
+ return normalizeSubjectType(input.subject.type);
116
+ }
117
+ if (raw === "tool_call") return "tool";
118
+ if (raw === "mcp_tool_call" || raw === "mcp_call") return "mcp_server";
119
+ if (raw === "browser_action" || raw === "visual_qa_run") return "browser_integration";
120
+ if (raw === "command_run" || raw === "git_operation" || raw === "deploy_operation") return "command";
121
+ if (raw === "package_install" || raw === "package_script") return "package";
122
+ if (raw === "file_read" || raw === "file_write" || raw === "config_change") return "agent_surface";
123
+ if (requestedActionType === "auth_billing_ci_prod_change") return "agent_surface";
124
+ return "unknown";
125
+ }
126
+
127
+ function inferSubjectTrustStatus(input = {}, requestedActionType = "unknown") {
128
+ const subject = input.subject && typeof input.subject === "object" ? input.subject : {};
129
+ const metadata = input.toolMetadata && typeof input.toolMetadata === "object" ? input.toolMetadata : {};
130
+ if (subject.blocked === true || metadata.blocked === true) return "blocked";
131
+ if (subject.trustStatus) return normalizeTrustStatus(subject.trustStatus);
132
+ if (metadata.reviewed === true || metadata.trusted === true) return "reviewed";
133
+ if (subject.reviewed === true || subject.known === true) return "reviewed";
134
+ if (["command_run", "file_read", "file_write", "deploy_publish", "auth_billing_ci_prod_change"].includes(requestedActionType)) {
135
+ return "known";
136
+ }
137
+ if (requestedActionType === "browser_action" && /^https?:\/\/(localhost|127\.0\.0\.1|\[::1\]|::1)/i.test(String(input.url || input.target || ""))) {
138
+ return "known";
139
+ }
140
+ return "unknown";
141
+ }
142
+
143
+ function buildSubjectIdentity(input = {}, classification = null) {
144
+ const requestedActionType = requestedActionTypeFromInput(input, classification);
145
+ const explicitSubject = input.subject && typeof input.subject === "object" ? input.subject : {};
146
+ const metadata = input.toolMetadata && typeof input.toolMetadata === "object" ? input.toolMetadata : {};
147
+ const type = inferSubjectType(input, requestedActionType);
148
+ const trustStatus = inferSubjectTrustStatus(input, requestedActionType);
149
+ const name = normalizeOptionalString(
150
+ explicitSubject.name
151
+ || input.toolName
152
+ || (input.mcpServer && input.toolName ? `${input.mcpServer}:${input.toolName}` : null)
153
+ || input.mcpServer
154
+ || input.domain
155
+ || input.target
156
+ || input.command
157
+ || type
158
+ ) || type;
159
+ const source = normalizeOptionalString(explicitSubject.source || metadata.source || input.source || input.requestedBy || "local");
160
+ const configPath = normalizeOptionalString(explicitSubject.configPath || metadata.configPath);
161
+ const owner = normalizeOwnerSponsor(explicitSubject.owner || metadata.owner, "workspace operator");
162
+ const sponsor = normalizeOwnerSponsor(explicitSubject.sponsor || metadata.sponsor, "Avorelo local policy");
163
+ const idSeed = [
164
+ explicitSubject.id,
165
+ type,
166
+ name,
167
+ source,
168
+ configPath,
169
+ owner,
170
+ sponsor,
171
+ ].filter(Boolean).join("|");
172
+
173
+ return {
174
+ id: normalizeOptionalString(explicitSubject.id) || `${type}-${sha256(idSeed).slice(0, 12)}`,
175
+ type,
176
+ name,
177
+ source,
178
+ configPath,
179
+ owner,
180
+ sponsor,
181
+ trustStatus,
182
+ };
183
+ }
184
+
185
+ function normalizeRequestedAction(input = {}, classification = null) {
186
+ const type = requestedActionTypeFromInput(input, classification);
187
+ return {
188
+ type,
189
+ target: sanitizeSummaryText(normalizeOptionalString(input.target || input.command || input.url || input.toolName || input.mcpServer)),
190
+ task: sanitizeSummaryText(normalizeOptionalString(input.userIntent || input.taskType || input.task)),
191
+ source: sanitizeSummaryText(normalizeOptionalString(input.requestedBy || input.source || "local")),
192
+ };
193
+ }
194
+
195
+ function inferAccessMode(requestedActionType) {
196
+ if (requestedActionType === "file_read") return "read_only";
197
+ if (requestedActionType === "file_write" || requestedActionType === "auth_billing_ci_prod_change") return "write";
198
+ if (requestedActionType === "browser_action") return "browser";
199
+ if (requestedActionType === "network_request") return "network";
200
+ if (requestedActionType === "command_run" || requestedActionType === "tool_call" || requestedActionType === "mcp_call" || requestedActionType === "deploy_publish") {
201
+ return "execute";
202
+ }
203
+ return "unknown";
204
+ }
205
+
206
+ function normalizeScope(input = {}, decision = {}, classification = null) {
207
+ const requestedAction = normalizeRequestedAction(input, classification);
208
+ const normalizedPaths = ["file_read", "file_write", "auth_billing_ci_prod_change"].includes(requestedAction.type)
209
+ ? normalizePathList(input.targetPaths || input.target || [])
210
+ : [];
211
+ const normalizedDomains = normalizeDomainList(input.domain || input.url || []);
212
+ const toolScope = unique([normalizeOptionalString(input.toolName)].filter(Boolean));
213
+ const mcpScope = unique([normalizeOptionalString(input.mcpServer)].filter(Boolean));
214
+ const ttlSeconds = Number.isFinite(Number(input.ttlSeconds))
215
+ ? Math.max(0, Number(input.ttlSeconds))
216
+ : (Number.isFinite(Number(decision.ttlSeconds)) ? Math.max(0, Number(decision.ttlSeconds)) : null);
217
+
218
+ return {
219
+ accessMode: normalizeAccessMode(inferAccessMode(requestedAction.type)),
220
+ pathScope: normalizedPaths,
221
+ domainScope: normalizedDomains,
222
+ toolScope,
223
+ mcpScope,
224
+ allowNetwork: requestedAction.type === "network_request" || requestedAction.type === "browser_action",
225
+ allowSecrets: input.secretAccess === true,
226
+ dryRun: input.dryRun === true,
227
+ testOnly: input.testOnly === true,
228
+ ttlSeconds,
229
+ expiresAt: ttlSeconds ? new Date(Date.now() + ttlSeconds * 1000).toISOString() : null,
230
+ };
231
+ }
232
+
233
+ function summarizeScope(scope) {
234
+ return {
235
+ accessMode: scope.accessMode,
236
+ pathScope: scope.pathScope,
237
+ domainScope: scope.domainScope,
238
+ toolScope: scope.toolScope,
239
+ mcpScope: scope.mcpScope,
240
+ allowNetwork: scope.allowNetwork,
241
+ allowSecrets: scope.allowSecrets,
242
+ dryRun: scope.dryRun,
243
+ testOnly: scope.testOnly,
244
+ };
245
+ }
246
+
247
+ function buildApprovalBoundary(requestedAction, scope, decision, subject) {
248
+ const required = decision.decision === "approval_required" || decision.decision === "block";
249
+ const targetSummary = scope.pathScope[0]
250
+ || scope.domainScope[0]
251
+ || scope.toolScope[0]
252
+ || scope.mcpScope[0]
253
+ || requestedAction.target
254
+ || subject.name;
255
+ return {
256
+ required,
257
+ summary: required
258
+ ? `Review required before ${requestedAction.type} reaches ${targetSummary}.`
259
+ : "No explicit approval boundary is required for the current scoped action.",
260
+ };
261
+ }
262
+
263
+ function buildTtlSummary(scope) {
264
+ return {
265
+ ttlSeconds: Number.isFinite(Number(scope.ttlSeconds)) ? Number(scope.ttlSeconds) : null,
266
+ expiresAt: scope.expiresAt || null,
267
+ summary: Number.isFinite(Number(scope.ttlSeconds)) && Number(scope.ttlSeconds) > 0
268
+ ? `Scoped review window: ${Number(scope.ttlSeconds)} seconds.`
269
+ : "No temporary grant window was recorded.",
270
+ };
271
+ }
272
+
273
+ function sanitizeSummaryText(value) {
274
+ return String(value || "")
275
+ .replace(/sk-[A-Za-z0-9]{16,}/g, "[redacted-openai-key]")
276
+ .replace(/ghp_[A-Za-z0-9]{20,}/g, "[redacted-github-token]")
277
+ .replace(/AKIA[0-9A-Z]{16}/g, "[redacted-aws-key]")
278
+ .replace(/(bearer\s+)[A-Za-z0-9._-]{8,}/ig, "$1[redacted]");
279
+ }
280
+
281
+ function buildGovernanceReceipt(input = {}, decision = {}, classification = null) {
282
+ const subject = buildSubjectIdentity(input, classification);
283
+ const requestedAction = normalizeRequestedAction(input, classification);
284
+ const scope = normalizeScope(input, decision, classification);
285
+ const approvalBoundary = buildApprovalBoundary(requestedAction, scope, decision, subject);
286
+ const ttlSummary = buildTtlSummary(scope);
287
+ const reasonCodes = unique(decision.reasonCodes || []);
288
+
289
+ return {
290
+ schemaVersion: GOVERNANCE_SCHEMA_VERSION,
291
+ contract: GOVERNANCE_CONTRACT,
292
+ decisionId: decision.decisionId,
293
+ decision: normalizeEnum(decision.decision, DECISIONS, "warn"),
294
+ severity: normalizeOptionalString(decision.riskLevel) || "unknown",
295
+ reasonCodes,
296
+ subjectSummary: {
297
+ ...subject,
298
+ name: sanitizeSummaryText(subject.name),
299
+ source: sanitizeSummaryText(subject.source),
300
+ configPath: sanitizeSummaryText(subject.configPath),
301
+ owner: sanitizeSummaryText(subject.owner),
302
+ sponsor: sanitizeSummaryText(subject.sponsor),
303
+ },
304
+ ownerSponsorSummary: {
305
+ owner: subject.owner,
306
+ sponsor: subject.sponsor,
307
+ trustStatus: subject.trustStatus,
308
+ },
309
+ requestedActionSummary: requestedAction,
310
+ scopeSummary: summarizeScope(scope),
311
+ approvalBoundary,
312
+ ttlSummary,
313
+ saferBoundaryHint: sanitizeSummaryText(decision.saferAlternative || "Keep the action inside the smallest reviewed scope."),
314
+ evidencePath: null,
315
+ redacted: true,
316
+ createdAt: decision.createdAt || nowIso(),
317
+ };
318
+ }
319
+
320
+ function writeJsonl(cwd, relPathValue, entry) {
321
+ const fs = require("fs");
322
+ const absPath = path.join(cwd, relPathValue);
323
+ fs.mkdirSync(path.dirname(absPath), { recursive: true });
324
+ fs.appendFileSync(absPath, `${JSON.stringify(entry)}\n`, "utf8");
325
+ }
326
+
327
+ function writeGovernanceReceipt(cwd, receipt, options = {}) {
328
+ ensureCcoDirs(cwd);
329
+ const payload = {
330
+ ...receipt,
331
+ evidencePath: LATEST_RECEIPT_REL_PATH,
332
+ };
333
+ safeWriteJson(cwd, LATEST_RECEIPT_REL_PATH, payload);
334
+ writeJsonl(cwd, EVENT_LOG_REL_PATH, payload);
335
+
336
+ if (canExportReports(options.plan || "free")) {
337
+ safeWriteJson(cwd, `${HISTORY_DIR_REL_PATH}/${payload.decisionId}.json`, payload);
338
+ }
339
+
340
+ return LATEST_RECEIPT_REL_PATH;
341
+ }
342
+
343
+ function readLatestGovernanceReceipt(cwd) {
344
+ return safeReadJson(cwd, LATEST_RECEIPT_REL_PATH, null);
345
+ }
346
+
347
+ function readGovernanceEvents(cwd) {
348
+ const fs = require("fs");
349
+ const absPath = path.join(cwd, EVENT_LOG_REL_PATH);
350
+ if (!fs.existsSync(absPath)) return [];
351
+ return fs.readFileSync(absPath, "utf8")
352
+ .split(/\r?\n/)
353
+ .map((line) => line.trim())
354
+ .filter(Boolean)
355
+ .map((line) => {
356
+ try {
357
+ return JSON.parse(line);
358
+ } catch {
359
+ return null;
360
+ }
361
+ })
362
+ .filter(Boolean);
363
+ }
364
+
365
+ function buildAgentAccessGovernanceSurface(cwd) {
366
+ const latestReceipt = readLatestGovernanceReceipt(cwd);
367
+ const events = readGovernanceEvents(cwd).slice(-50);
368
+ const trustStatuses = events.map((event) => event?.subjectSummary?.trustStatus).filter(Boolean);
369
+ const unknownSubjects = trustStatuses.filter((status) => status === "unknown").length;
370
+ const reviewedSubjects = trustStatuses.filter((status) => status === "known" || status === "reviewed").length;
371
+ const topReasonCounts = {};
372
+
373
+ events.forEach((event) => {
374
+ (event.reasonCodes || []).forEach((code) => {
375
+ topReasonCounts[code] = (topReasonCounts[code] || 0) + 1;
376
+ });
377
+ });
378
+
379
+ const topReasonCodes = Object.entries(topReasonCounts)
380
+ .sort((left, right) => right[1] - left[1])
381
+ .slice(0, 3)
382
+ .map(([code]) => code);
383
+
384
+ const status = latestReceipt ? "foundation" : "partial";
385
+ const nextAction = unknownSubjects > 0
386
+ ? "Review unknown subjects before relying on write-capable or external actions."
387
+ : latestReceipt
388
+ ? "Use governance receipts to keep approval boundaries visible in future risky actions."
389
+ : "Run `avorelo guard` on a risky action to generate the first governance receipt.";
390
+
391
+ return {
392
+ status,
393
+ showInStatus: true,
394
+ showInDashboard: true,
395
+ subjectsReviewed: reviewedSubjects,
396
+ unknownSubjects,
397
+ approvalBoundariesAvailable: Boolean(latestReceipt?.approvalBoundary),
398
+ latestReceiptPath: latestReceipt ? LATEST_RECEIPT_REL_PATH : null,
399
+ latestReceipt,
400
+ topReasonCodes,
401
+ nextAction,
402
+ statusLine: `Agent Access Governance: ${status.toUpperCase()} · reviewed=${reviewedSubjects} · unknown=${unknownSubjects} · approval boundaries ${latestReceipt?.approvalBoundary ? "available" : "missing"} · latest receipt ${latestReceipt ? "available" : "missing"}`,
403
+ dashboardCard: {
404
+ headline: `Agent Access Governance: ${status.toUpperCase()}`,
405
+ summary: `Reviewed=${reviewedSubjects}, unknown=${unknownSubjects}, approval boundaries ${latestReceipt?.approvalBoundary ? "available" : "missing"}.`,
406
+ latestReceiptPath: latestReceipt ? LATEST_RECEIPT_REL_PATH : null,
407
+ topReasonCodes,
408
+ nextAction,
409
+ },
410
+ };
411
+ }
412
+
413
+ function applyGovernanceDecisionFloor(decision, receipt) {
414
+ const next = { ...decision };
415
+ const subjectTrustStatus = receipt?.subjectSummary?.trustStatus || "unknown";
416
+ const reasonCodes = new Set(next.reasonCodes || []);
417
+
418
+ if (subjectTrustStatus === "blocked") {
419
+ next.decision = "block";
420
+ next.blocked = true;
421
+ next.requiresApproval = false;
422
+ next.riskLevel = next.riskLevel === "critical" ? next.riskLevel : "high";
423
+ reasonCodes.add("SUBJECT_BLOCKED");
424
+ next.explanation = `${next.explanation} The subject is explicitly blocked.`;
425
+ } else if (subjectTrustStatus === "unknown" && next.decision === "allow" && ["tool_call", "mcp_call", "network_request", "browser_action"].includes(receipt?.requestedActionSummary?.type)) {
426
+ next.decision = "warn";
427
+ next.blocked = false;
428
+ next.requiresApproval = false;
429
+ reasonCodes.add("SUBJECT_UNKNOWN");
430
+ next.explanation = `${next.explanation} Subject identity is incomplete, so Avorelo is keeping the action visible.`;
431
+ }
432
+
433
+ next.reasonCodes = Array.from(reasonCodes);
434
+ return next;
435
+ }
436
+
437
+ module.exports = {
438
+ GOVERNANCE_CONTRACT,
439
+ GOVERNANCE_SCHEMA_VERSION,
440
+ SUBJECT_TYPES,
441
+ TRUST_STATUSES,
442
+ REQUESTED_ACTION_TYPES,
443
+ ACCESS_MODES,
444
+ LATEST_RECEIPT_REL_PATH,
445
+ EVENT_LOG_REL_PATH,
446
+ buildSubjectIdentity,
447
+ normalizeRequestedAction,
448
+ normalizeScope,
449
+ buildGovernanceReceipt,
450
+ writeGovernanceReceipt,
451
+ readLatestGovernanceReceipt,
452
+ readGovernanceEvents,
453
+ buildAgentAccessGovernanceSurface,
454
+ applyGovernanceDecisionFloor,
455
+ };