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,175 @@
1
+ "use strict";
2
+
3
+ const { spawnSync } = require("child_process");
4
+ const { classifyPackageAction } = require("./package-action-rules");
5
+
6
+ const PACKAGE_ACTION_ADAPTER_ID = "package-action-v1";
7
+ const PREVIEW_LIMIT = 400;
8
+
9
+ function truncatePreview(value) {
10
+ const text = String(value || "");
11
+ if (text.length <= PREVIEW_LIMIT) return text;
12
+ return `${text.slice(0, PREVIEW_LIMIT)}...`;
13
+ }
14
+
15
+ function redactPreview(value) {
16
+ return truncatePreview(String(value || "").replace(
17
+ /((?:secret|token|password|api[_-]?key)[^=\n]{0,20}=)[^\s\n]+/ig,
18
+ "$1[redacted]",
19
+ ));
20
+ }
21
+
22
+ function buildPackageAdapterResult(base, overrides = {}) {
23
+ return {
24
+ actionId: base.actionId,
25
+ componentId: base.componentId || null,
26
+ componentType: base.componentType || null,
27
+ actionType: base.actionType,
28
+ decision: base.decision || null,
29
+ adapterId: PACKAGE_ACTION_ADAPTER_ID,
30
+ enforcementAvailable: true,
31
+ effectiveBehavior: "recommended_only",
32
+ executed: false,
33
+ exitCode: null,
34
+ stdoutPreview: "",
35
+ stderrPreview: "",
36
+ reason: "",
37
+ timestamp: base.timestamp,
38
+ ...overrides,
39
+ };
40
+ }
41
+
42
+ function enforcePackageAction(action, context = {}) {
43
+ const decisionRecord = context.decisionRecord || null;
44
+ const limitPlan = context.limitPlan || null;
45
+ const execute = context.execute === true;
46
+ const cwd = context.cwd;
47
+ const command = String(action?.command || "");
48
+ const executor = typeof context.executor === "function" ? context.executor : null;
49
+ const profile = classifyPackageAction(action);
50
+ const base = {
51
+ actionId: action.actionId,
52
+ componentId: action.componentId,
53
+ componentType: action.componentType,
54
+ actionType: action.actionType,
55
+ decision: decisionRecord?.decision || null,
56
+ timestamp: context.timestamp,
57
+ };
58
+
59
+ if (
60
+ profile.remoteScript ||
61
+ profile.destructiveChain ||
62
+ profile.globalInstall ||
63
+ profile.unsafeFlags ||
64
+ profile.installFromUrlOrPath ||
65
+ profile.sensitiveTarget ||
66
+ profile.workflowTarget
67
+ ) {
68
+ return buildPackageAdapterResult(base, {
69
+ effectiveBehavior: "blocked",
70
+ reason: profile.reasons[0] || "This package action is not allowed.",
71
+ });
72
+ }
73
+
74
+ if (profile.lifecycleRisk && decisionRecord?.decision !== "approve_once") {
75
+ return buildPackageAdapterResult(base, {
76
+ effectiveBehavior: "blocked",
77
+ reason: profile.reasons[0] || "Lifecycle scripts require explicit approval.",
78
+ });
79
+ }
80
+
81
+ if (decisionRecord?.decision === "deny") {
82
+ return buildPackageAdapterResult(base, {
83
+ effectiveBehavior: "blocked",
84
+ reason: "User denied this package action.",
85
+ });
86
+ }
87
+
88
+ if (decisionRecord?.decision === "let_wuz_limit" && limitPlan?.recommendedMode === "deny") {
89
+ return buildPackageAdapterResult(base, {
90
+ effectiveBehavior: "blocked",
91
+ reason: limitPlan.reason || "No safe limited version found. Recommended: deny.",
92
+ });
93
+ }
94
+
95
+ if (decisionRecord?.decision === "let_wuz_limit" && limitPlan?.recommendedMode !== "limited") {
96
+ return buildPackageAdapterResult(base, {
97
+ effectiveBehavior: "blocked",
98
+ reason: limitPlan?.reason || "The limited plan could not safely allow this package action.",
99
+ });
100
+ }
101
+
102
+ if (
103
+ decisionRecord?.decision === "let_wuz_limit" &&
104
+ Array.isArray(limitPlan?.scope?.allowedCommands) &&
105
+ limitPlan.scope.allowedCommands.length > 0 &&
106
+ !limitPlan.scope.allowedCommands.includes(command)
107
+ ) {
108
+ return buildPackageAdapterResult(base, {
109
+ effectiveBehavior: "blocked",
110
+ reason: "The limited plan only allows the exact evaluated package command.",
111
+ });
112
+ }
113
+
114
+ if (!execute) {
115
+ return buildPackageAdapterResult(base, {
116
+ effectiveBehavior: decisionRecord?.decision === "let_wuz_limit" ? "limited" : "dry_run_only",
117
+ reason: decisionRecord?.decision === "let_wuz_limit"
118
+ ? (limitPlan?.reason || "Wuz limited this action to the current task.")
119
+ : "Execution stayed in dry-run mode.",
120
+ });
121
+ }
122
+
123
+ const child = executor
124
+ ? executor({ command, cwd, action, decisionRecord, limitPlan })
125
+ : spawnSync(command, {
126
+ cwd,
127
+ shell: true,
128
+ windowsHide: true,
129
+ encoding: "utf8",
130
+ timeout: 30000,
131
+ });
132
+
133
+ const stdoutPreview = redactPreview(child?.stdout || "");
134
+ const stderrPreview = redactPreview(child?.stderr || child?.error?.message || "");
135
+ const exitCode = typeof child?.status === "number"
136
+ ? child.status
137
+ : typeof child?.exitCode === "number"
138
+ ? child.exitCode
139
+ : child?.error
140
+ ? 1
141
+ : 1;
142
+
143
+ return buildPackageAdapterResult(base, {
144
+ effectiveBehavior: decisionRecord?.decision === "let_wuz_limit" ? "limited" : "allowed",
145
+ executed: true,
146
+ exitCode,
147
+ stdoutPreview,
148
+ stderrPreview,
149
+ reason: exitCode === 0
150
+ ? (decisionRecord?.decision === "let_wuz_limit"
151
+ ? "Package action executed within the limited project scope."
152
+ : "Approved package action executed once.")
153
+ : "Package action executed but exited with a non-zero status.",
154
+ });
155
+ }
156
+
157
+ const PACKAGE_ACTION_ADAPTER = {
158
+ adapterId: PACKAGE_ACTION_ADAPTER_ID,
159
+ canEvaluate: true,
160
+ canEnforce: true,
161
+ supportedActionTypes: ["package.install", "package.run", "package.script"],
162
+ enforce(action, decisionRecord, limitPlan, options = {}) {
163
+ return enforcePackageAction(action, {
164
+ ...options,
165
+ decisionRecord,
166
+ limitPlan,
167
+ });
168
+ },
169
+ };
170
+
171
+ module.exports = {
172
+ PACKAGE_ACTION_ADAPTER_ID,
173
+ PACKAGE_ACTION_ADAPTER,
174
+ enforcePackageAction,
175
+ };
@@ -0,0 +1,233 @@
1
+ "use strict";
2
+
3
+ const {
4
+ isSensitiveWriteTarget,
5
+ isWorkflowWriteTarget,
6
+ normalizePath,
7
+ } = require("./file-write-rules");
8
+
9
+ function normalizeCommand(value) {
10
+ return String(value || "").trim();
11
+ }
12
+
13
+ function normalizePackageManager(explicitValue, command) {
14
+ const explicit = String(explicitValue || "").trim().toLowerCase();
15
+ if (["npm", "pnpm", "yarn", "bun"].includes(explicit)) return explicit;
16
+ const normalized = normalizeCommand(command).toLowerCase();
17
+ if (/^npm\b/.test(normalized)) return "npm";
18
+ if (/^pnpm\b/.test(normalized)) return "pnpm";
19
+ if (/^yarn\b/.test(normalized)) return "yarn";
20
+ if (/^bun\b/.test(normalized)) return "bun";
21
+ return "unknown";
22
+ }
23
+
24
+ function hasRemoteScriptExecution(command) {
25
+ return /\b(curl|wget)\b[^\n]*\|\s*(bash|sh|pwsh|powershell)\b|\b(invoke-webrequest|invoke-restmethod|downloadstring)\b/i.test(
26
+ normalizeCommand(command),
27
+ );
28
+ }
29
+
30
+ function hasDestructiveChaining(command) {
31
+ return /(?:&&|;|\|\|)\s*(?:rm\s+-rf\b|del\s+\/[qs]\b|remove-item\b)/i.test(normalizeCommand(command));
32
+ }
33
+
34
+ function hasGlobalInstall(command) {
35
+ const normalized = normalizeCommand(command).toLowerCase();
36
+ return /\bnpm\s+(?:install|i)\b[^\n]*\s-g\b|\bpnpm\s+add\b[^\n]*\s-g\b|\byarn\s+global\s+add\b|\bbun\s+add\b[^\n]*\s-g\b/i.test(normalized);
37
+ }
38
+
39
+ function hasUnsafeFlags(command) {
40
+ return /\s--force\b|\s--unsafe-perm\b|\s--ignore-scripts=false\b/i.test(normalizeCommand(command));
41
+ }
42
+
43
+ function hasInstallFromUrlOrPath(command) {
44
+ const normalized = normalizeCommand(command);
45
+ return /\b(?:https?:\/\/|git\+|github:|file:|ssh:\/\/|git@)[^\s]+/i.test(normalized) ||
46
+ /(?:^|\s)(?:\.\.?[\\/]|[A-Za-z]:[\\/]|\/)[^\s]+/i.test(normalized) ||
47
+ /\b[^\s]+\.tgz\b/i.test(normalized);
48
+ }
49
+
50
+ function inferScriptName(command, explicitValue) {
51
+ const explicit = String(explicitValue || "").trim();
52
+ if (explicit) return explicit;
53
+ const normalized = normalizeCommand(command);
54
+ const runMatch = normalized.match(/^(?:npm|pnpm)\s+run\s+([a-z0-9:_-]+)/i);
55
+ if (runMatch) return runMatch[1];
56
+ const yarnRunMatch = normalized.match(/^yarn\s+(?!add\b|install\b|global\b)([a-z0-9:_-]+)/i);
57
+ if (yarnRunMatch) return yarnRunMatch[1];
58
+ const bunRunMatch = normalized.match(/^bun\s+run\s+([a-z0-9:_-]+)/i);
59
+ if (bunRunMatch) return bunRunMatch[1];
60
+ const testMatch = normalized.match(/^(?:npm|pnpm|yarn|bun)\s+(test|lint|build)\b/i);
61
+ if (testMatch) return testMatch[1];
62
+ return "unknown";
63
+ }
64
+
65
+ function inferPackageName(command, explicitValue) {
66
+ const explicit = String(explicitValue || "").trim();
67
+ if (explicit) return explicit;
68
+ const normalized = normalizeCommand(command);
69
+ const installPatterns = [
70
+ /^(?:npm\s+(?:install|i)|pnpm\s+add|yarn\s+add|bun\s+add)\s+([^\s-][^\s]*)/i,
71
+ ];
72
+ for (const pattern of installPatterns) {
73
+ const match = normalized.match(pattern);
74
+ if (match) return match[1];
75
+ }
76
+ return "";
77
+ }
78
+
79
+ function hasLifecycleScriptRisk(actionType, scriptName, command) {
80
+ const normalizedScript = String(scriptName || "").toLowerCase();
81
+ if (["postinstall", "preinstall", "prepare"].includes(normalizedScript)) return true;
82
+ if (actionType === "package.script" && /\b(postinstall|preinstall|prepare)\b/i.test(normalizeCommand(command))) return true;
83
+ return false;
84
+ }
85
+
86
+ function isSafeTestOrLintCommand(command, scriptName) {
87
+ const normalized = normalizeCommand(command).toLowerCase();
88
+ if (!normalized || /[|;&><]/.test(normalized)) return false;
89
+ if (["test", "lint"].includes(String(scriptName || "").toLowerCase())) {
90
+ return /^(?:npm|pnpm|yarn|bun)\s+(?:run\s+)?(?:test|lint)\b/i.test(normalized);
91
+ }
92
+ return /^(?:npm|pnpm|yarn|bun)\s+(?:run\s+)?(?:test|lint)\b/i.test(normalized);
93
+ }
94
+
95
+ function isSpecificPackageInstall(command, packageManager, packageName) {
96
+ const normalized = normalizeCommand(command);
97
+ const normalizedPackage = String(packageName || "").trim();
98
+ if (!normalizedPackage) return false;
99
+ if (!["npm", "pnpm", "yarn", "bun"].includes(packageManager)) return false;
100
+ if (hasGlobalInstall(normalized) || hasInstallFromUrlOrPath(normalized)) return false;
101
+ if (/\s-[^\s]/.test(normalized.replace(/\s--ignore-scripts\b/ig, ""))) return false;
102
+ return /^(?:npm\s+(?:install|i)|pnpm\s+add|yarn\s+add|bun\s+add)\s+[^\s]+(?:\s+--ignore-scripts)?\s*$/i.test(normalized);
103
+ }
104
+
105
+ function commandHasIgnoreScripts(command) {
106
+ return /\s--ignore-scripts\b/i.test(normalizeCommand(command));
107
+ }
108
+
109
+ function classifyPackageAction(action = {}) {
110
+ const actionType = String(action?.actionType || "");
111
+ const command = normalizeCommand(action?.command || "");
112
+ const target = normalizePath(action?.target || "");
113
+ const packageManager = normalizePackageManager(action?.packageManager, command);
114
+ const scriptName = inferScriptName(command, action?.scriptName);
115
+ const packageName = inferPackageName(command, action?.packageName);
116
+ const remoteScript = hasRemoteScriptExecution(command);
117
+ const destructiveChain = hasDestructiveChaining(command);
118
+ const globalInstall = hasGlobalInstall(command);
119
+ const unsafeFlags = hasUnsafeFlags(command);
120
+ const installFromUrlOrPath = hasInstallFromUrlOrPath(command);
121
+ const lifecycleRisk = hasLifecycleScriptRisk(actionType, scriptName, command);
122
+ const safeTestOrLint = isSafeTestOrLintCommand(command, scriptName);
123
+ const specificPackageInstall = actionType === "package.install" && isSpecificPackageInstall(command, packageManager, packageName);
124
+ const ignoreScripts = commandHasIgnoreScripts(command);
125
+ const sensitiveTarget = isSensitiveWriteTarget(`${target}\n${command}`);
126
+ const workflowTarget = isWorkflowWriteTarget(`${target}\n${command}`);
127
+ const unknownManager = packageManager === "unknown";
128
+ const reasons = [];
129
+ let riskLevel = "medium";
130
+ let recommendedDecision = "limit";
131
+ let safeLimited = false;
132
+
133
+ if (remoteScript) {
134
+ reasons.push("Remote script execution was detected.");
135
+ riskLevel = "high";
136
+ recommendedDecision = "deny";
137
+ } else if (destructiveChain) {
138
+ reasons.push("Destructive chained command behavior was detected.");
139
+ riskLevel = "high";
140
+ recommendedDecision = "deny";
141
+ } else if (globalInstall) {
142
+ reasons.push("Global package installs are outside the current project scope.");
143
+ riskLevel = "high";
144
+ recommendedDecision = "deny";
145
+ } else if (unsafeFlags) {
146
+ reasons.push("Unsafe package-manager flags were detected.");
147
+ riskLevel = "high";
148
+ recommendedDecision = "deny";
149
+ } else if (installFromUrlOrPath) {
150
+ reasons.push("Install from URL, git source, tarball, or outside-project path was detected.");
151
+ riskLevel = "high";
152
+ recommendedDecision = "deny";
153
+ } else if (lifecycleRisk) {
154
+ reasons.push("Lifecycle scripts like preinstall, postinstall, or prepare require explicit approval.");
155
+ riskLevel = "high";
156
+ recommendedDecision = "deny";
157
+ } else if (sensitiveTarget) {
158
+ reasons.push("Sensitive files or credentials are involved.");
159
+ riskLevel = "high";
160
+ recommendedDecision = "deny";
161
+ } else if (workflowTarget) {
162
+ reasons.push("Workflow modification through a package action requires explicit approval.");
163
+ riskLevel = "high";
164
+ recommendedDecision = "deny";
165
+ } else if (safeTestOrLint) {
166
+ reasons.push("Known local test or lint package command.");
167
+ riskLevel = "low";
168
+ recommendedDecision = "limit";
169
+ safeLimited = true;
170
+ } else if (specificPackageInstall) {
171
+ reasons.push(ignoreScripts
172
+ ? "Specific dependency install is scoped and scripts are disabled."
173
+ : "Specific dependency install is scoped but can still change package state.");
174
+ riskLevel = "medium";
175
+ recommendedDecision = "limit";
176
+ safeLimited = ignoreScripts === true;
177
+ } else if (actionType === "package.run" || actionType === "package.script") {
178
+ reasons.push("Package script execution can run local shell behavior.");
179
+ riskLevel = "medium";
180
+ recommendedDecision = "limit";
181
+ } else if (actionType === "package.install" || actionType === "package.lockfile.modify") {
182
+ reasons.push("Package install or lockfile changes can modify project dependencies.");
183
+ riskLevel = "medium";
184
+ recommendedDecision = "limit";
185
+ } else if (unknownManager) {
186
+ reasons.push("Unknown package manager command needs review.");
187
+ riskLevel = "medium";
188
+ recommendedDecision = "limit";
189
+ } else {
190
+ reasons.push("Package action needs review.");
191
+ }
192
+
193
+ return {
194
+ actionType,
195
+ command,
196
+ target,
197
+ packageManager,
198
+ scriptName,
199
+ packageName,
200
+ remoteScript,
201
+ destructiveChain,
202
+ globalInstall,
203
+ unsafeFlags,
204
+ installFromUrlOrPath,
205
+ lifecycleRisk,
206
+ safeTestOrLint,
207
+ specificPackageInstall,
208
+ ignoreScripts,
209
+ sensitiveTarget,
210
+ workflowTarget,
211
+ unknownManager,
212
+ safeLimited,
213
+ riskLevel,
214
+ recommendedDecision,
215
+ reasons,
216
+ };
217
+ }
218
+
219
+ module.exports = {
220
+ normalizePackageManager,
221
+ inferScriptName,
222
+ inferPackageName,
223
+ hasRemoteScriptExecution,
224
+ hasDestructiveChaining,
225
+ hasGlobalInstall,
226
+ hasUnsafeFlags,
227
+ hasInstallFromUrlOrPath,
228
+ hasLifecycleScriptRisk,
229
+ isSafeTestOrLintCommand,
230
+ isSpecificPackageInstall,
231
+ commandHasIgnoreScripts,
232
+ classifyPackageAction,
233
+ };
@@ -0,0 +1,148 @@
1
+ "use strict";
2
+
3
+ const { safeReadJson, safeWriteJson, nowIso } = require("../fsx");
4
+
5
+ const PERFORMANCE_SUMMARY_REL_PATH = ".claude/cco/security/performance-summary.json";
6
+
7
+ const PERFORMANCE_GUARDRAILS = {
8
+ statusSummaryTargetMs: 150,
9
+ dashboardSummaryTargetMs: 400,
10
+ productSummaryTargetMs: 100,
11
+ guardedActionEvaluationTargetMs: 75,
12
+ autoPolicyDecisionTargetMs: 50,
13
+ basicCheckTargetMs: 1500,
14
+ visibilityScanTargetMs: 4000,
15
+ scanMaxFiles: 300,
16
+ scanMaxFileBytes: 256000,
17
+ scanMaxTotalBytes: 1500000,
18
+ scanMaxDepth: 10,
19
+ scanMaxSourceBytesPerItem: 64000,
20
+ scanMaxDurationMs: 5000,
21
+ };
22
+
23
+ function targetForOperation(operation) {
24
+ switch (operation) {
25
+ case "agent_security_basic_check":
26
+ return PERFORMANCE_GUARDRAILS.basicCheckTargetMs;
27
+ case "agent_security_visibility_scan":
28
+ return PERFORMANCE_GUARDRAILS.visibilityScanTargetMs;
29
+ case "agent_security_guarded_action":
30
+ case "agent_security_preflight":
31
+ return PERFORMANCE_GUARDRAILS.guardedActionEvaluationTargetMs;
32
+ case "agent_security_auto_policy":
33
+ return PERFORMANCE_GUARDRAILS.autoPolicyDecisionTargetMs;
34
+ case "status_summary":
35
+ return PERFORMANCE_GUARDRAILS.statusSummaryTargetMs;
36
+ case "dashboard_summary":
37
+ return PERFORMANCE_GUARDRAILS.dashboardSummaryTargetMs;
38
+ default:
39
+ return PERFORMANCE_GUARDRAILS.productSummaryTargetMs;
40
+ }
41
+ }
42
+
43
+ function createPerformanceTracker(operation, extras = {}) {
44
+ const startedAt = Date.now();
45
+ const tracker = {
46
+ operation,
47
+ startedAt,
48
+ filesScanned: 0,
49
+ bytesScanned: 0,
50
+ cacheHits: 0,
51
+ cacheMisses: 0,
52
+ skippedLargeFiles: 0,
53
+ ignoredDirectories: new Set(),
54
+ ignoredDirectoryCount: 0,
55
+ slowSteps: [],
56
+ timeoutHit: false,
57
+ maxFilesHit: false,
58
+ maxBytesHit: false,
59
+ maxDepthHit: false,
60
+ ...extras,
61
+ };
62
+ tracker.noteFile = (bytes = 0) => {
63
+ tracker.filesScanned += 1;
64
+ tracker.bytesScanned += Math.max(0, Number(bytes || 0));
65
+ };
66
+ tracker.noteCacheHit = () => { tracker.cacheHits += 1; };
67
+ tracker.noteCacheMiss = () => { tracker.cacheMisses += 1; };
68
+ tracker.noteSkippedLargeFile = () => { tracker.skippedLargeFiles += 1; };
69
+ tracker.noteIgnoredDirectory = (name) => {
70
+ if (name) tracker.ignoredDirectories.add(String(name));
71
+ tracker.ignoredDirectoryCount += 1;
72
+ };
73
+ tracker.noteSlowStep = (step, durationMs) => {
74
+ tracker.slowSteps.push({ step, durationMs: Math.max(0, Number(durationMs || 0)) });
75
+ };
76
+ tracker.finish = (more = {}) => {
77
+ const durationMs = Date.now() - startedAt;
78
+ const targetMs = targetForOperation(operation);
79
+ return {
80
+ operation,
81
+ durationMs,
82
+ filesScanned: tracker.filesScanned,
83
+ bytesScanned: tracker.bytesScanned,
84
+ cacheHits: tracker.cacheHits,
85
+ cacheMisses: tracker.cacheMisses,
86
+ skippedLargeFiles: tracker.skippedLargeFiles,
87
+ ignoredDirectories: Array.from(tracker.ignoredDirectories).sort(),
88
+ ignoredDirectoryCount: tracker.ignoredDirectoryCount,
89
+ timeoutHit: tracker.timeoutHit === true,
90
+ maxFilesHit: tracker.maxFilesHit === true,
91
+ maxBytesHit: tracker.maxBytesHit === true,
92
+ maxDepthHit: tracker.maxDepthHit === true,
93
+ slow: durationMs > targetMs,
94
+ targetMs,
95
+ slowSteps: tracker.slowSteps.slice(0, 8),
96
+ generatedAt: nowIso(),
97
+ ...more,
98
+ };
99
+ };
100
+ return tracker;
101
+ }
102
+
103
+ function loadPerformanceSummary(cwd) {
104
+ return safeReadJson(cwd, PERFORMANCE_SUMMARY_REL_PATH, {
105
+ generatedAt: null,
106
+ operations: [],
107
+ });
108
+ }
109
+
110
+ function recordPerformanceSummary(cwd, operationEntry) {
111
+ const current = loadPerformanceSummary(cwd);
112
+ const operations = [...(Array.isArray(current.operations) ? current.operations : []), operationEntry].slice(-50);
113
+ const next = {
114
+ generatedAt: nowIso(),
115
+ operations,
116
+ };
117
+ safeWriteJson(cwd, PERFORMANCE_SUMMARY_REL_PATH, next);
118
+ return next;
119
+ }
120
+
121
+ function latestOperationForKind(cwd, predicate) {
122
+ const summary = loadPerformanceSummary(cwd);
123
+ const operations = Array.isArray(summary.operations) ? summary.operations : [];
124
+ for (let index = operations.length - 1; index >= 0; index -= 1) {
125
+ if (predicate(operations[index])) return operations[index];
126
+ }
127
+ return null;
128
+ }
129
+
130
+ function buildCompactPerformanceSummary(cwd, operationNames) {
131
+ const names = new Set(Array.isArray(operationNames) ? operationNames : [operationNames]);
132
+ const latest = latestOperationForKind(cwd, (entry) => names.has(entry.operation));
133
+ if (!latest) return { lastOperationMs: null, slow: false };
134
+ return {
135
+ lastOperationMs: Number(latest.durationMs || 0),
136
+ slow: latest.slow === true,
137
+ };
138
+ }
139
+
140
+ module.exports = {
141
+ PERFORMANCE_SUMMARY_REL_PATH,
142
+ PERFORMANCE_GUARDRAILS,
143
+ createPerformanceTracker,
144
+ loadPerformanceSummary,
145
+ recordPerformanceSummary,
146
+ latestOperationForKind,
147
+ buildCompactPerformanceSummary,
148
+ };