free-computer-use 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 (135) hide show
  1. package/.env.example +31 -0
  2. package/CHANGELOG.md +19 -0
  3. package/CONTRIBUTING.md +66 -0
  4. package/LICENSE +21 -0
  5. package/README.md +140 -0
  6. package/SECURITY.md +133 -0
  7. package/artifacts/benchmark-public.json +797 -0
  8. package/assets/readme/hero.svg +53 -0
  9. package/assets/readme/incident-demo.gif +0 -0
  10. package/assets/readme/incident-evidence.json +52 -0
  11. package/dist/actions/compiler.d.ts +5 -0
  12. package/dist/actions/compiler.js +16 -0
  13. package/dist/actions/compiler.js.map +1 -0
  14. package/dist/actions/executor.d.ts +38 -0
  15. package/dist/actions/executor.js +305 -0
  16. package/dist/actions/executor.js.map +1 -0
  17. package/dist/actions/policy.d.ts +4 -0
  18. package/dist/actions/policy.js +18 -0
  19. package/dist/actions/policy.js.map +1 -0
  20. package/dist/actions/schema.d.ts +4149 -0
  21. package/dist/actions/schema.js +59 -0
  22. package/dist/actions/schema.js.map +1 -0
  23. package/dist/adapters/generic.d.ts +14 -0
  24. package/dist/adapters/generic.js +33 -0
  25. package/dist/adapters/generic.js.map +1 -0
  26. package/dist/agent/Agent.d.ts +69 -0
  27. package/dist/agent/Agent.js +375 -0
  28. package/dist/agent/Agent.js.map +1 -0
  29. package/dist/agent/Control.d.ts +23 -0
  30. package/dist/agent/Control.js +51 -0
  31. package/dist/agent/Control.js.map +1 -0
  32. package/dist/agent/TokenBudget.d.ts +52 -0
  33. package/dist/agent/TokenBudget.js +47 -0
  34. package/dist/agent/TokenBudget.js.map +1 -0
  35. package/dist/agent/goalCriteria.d.ts +2 -0
  36. package/dist/agent/goalCriteria.js +13 -0
  37. package/dist/agent/goalCriteria.js.map +1 -0
  38. package/dist/browser/Browser.d.ts +72 -0
  39. package/dist/browser/Browser.js +378 -0
  40. package/dist/browser/Browser.js.map +1 -0
  41. package/dist/browser/DomExtractor.d.ts +6 -0
  42. package/dist/browser/DomExtractor.js +134 -0
  43. package/dist/browser/DomExtractor.js.map +1 -0
  44. package/dist/browser/Interaction.d.ts +43 -0
  45. package/dist/browser/Interaction.js +225 -0
  46. package/dist/browser/Interaction.js.map +1 -0
  47. package/dist/browser/NetworkGuardProxy.d.ts +31 -0
  48. package/dist/browser/NetworkGuardProxy.js +331 -0
  49. package/dist/browser/NetworkGuardProxy.js.map +1 -0
  50. package/dist/browser/Observer.d.ts +12 -0
  51. package/dist/browser/Observer.js +31 -0
  52. package/dist/browser/Observer.js.map +1 -0
  53. package/dist/browser/PageCompressor.d.ts +47 -0
  54. package/dist/browser/PageCompressor.js +62 -0
  55. package/dist/browser/PageCompressor.js.map +1 -0
  56. package/dist/browser/SecurityBoundaryError.d.ts +3 -0
  57. package/dist/browser/SecurityBoundaryError.js +4 -0
  58. package/dist/browser/SecurityBoundaryError.js.map +1 -0
  59. package/dist/browser/SelectorEngine.d.ts +18 -0
  60. package/dist/browser/SelectorEngine.js +72 -0
  61. package/dist/browser/SelectorEngine.js.map +1 -0
  62. package/dist/browser/types.d.ts +38 -0
  63. package/dist/browser/types.js +2 -0
  64. package/dist/browser/types.js.map +1 -0
  65. package/dist/cli/index.d.ts +2 -0
  66. package/dist/cli/index.js +284 -0
  67. package/dist/cli/index.js.map +1 -0
  68. package/dist/config.d.ts +11 -0
  69. package/dist/config.js +77 -0
  70. package/dist/config.js.map +1 -0
  71. package/dist/history/TraceStore.d.ts +29 -0
  72. package/dist/history/TraceStore.js +53 -0
  73. package/dist/history/TraceStore.js.map +1 -0
  74. package/dist/index.d.ts +18 -0
  75. package/dist/index.js +16 -0
  76. package/dist/index.js.map +1 -0
  77. package/dist/llm/ClaudeSubscriptionProvider.d.ts +26 -0
  78. package/dist/llm/ClaudeSubscriptionProvider.js +182 -0
  79. package/dist/llm/ClaudeSubscriptionProvider.js.map +1 -0
  80. package/dist/llm/CodexSubscriptionProvider.d.ts +26 -0
  81. package/dist/llm/CodexSubscriptionProvider.js +168 -0
  82. package/dist/llm/CodexSubscriptionProvider.js.map +1 -0
  83. package/dist/llm/FlashProvider.d.ts +27 -0
  84. package/dist/llm/FlashProvider.js +103 -0
  85. package/dist/llm/FlashProvider.js.map +1 -0
  86. package/dist/llm/LLMProvider.d.ts +37 -0
  87. package/dist/llm/LLMProvider.js +2 -0
  88. package/dist/llm/LLMProvider.js.map +1 -0
  89. package/dist/llm/cliEnvironment.d.ts +5 -0
  90. package/dist/llm/cliEnvironment.js +21 -0
  91. package/dist/llm/cliEnvironment.js.map +1 -0
  92. package/dist/llm/prompts.d.ts +4 -0
  93. package/dist/llm/prompts.js +12 -0
  94. package/dist/llm/prompts.js.map +1 -0
  95. package/dist/llm/structuredOutput.d.ts +3 -0
  96. package/dist/llm/structuredOutput.js +58 -0
  97. package/dist/llm/structuredOutput.js.map +1 -0
  98. package/dist/mcp/index.d.ts +13 -0
  99. package/dist/mcp/index.js +243 -0
  100. package/dist/mcp/index.js.map +1 -0
  101. package/dist/profile/ProfileStore.d.ts +7 -0
  102. package/dist/profile/ProfileStore.js +52 -0
  103. package/dist/profile/ProfileStore.js.map +1 -0
  104. package/dist/profile/VariableResolver.d.ts +15 -0
  105. package/dist/profile/VariableResolver.js +50 -0
  106. package/dist/profile/VariableResolver.js.map +1 -0
  107. package/dist/server/index.d.ts +14 -0
  108. package/dist/server/index.js +239 -0
  109. package/dist/server/index.js.map +1 -0
  110. package/dist/ui/app.js +132 -0
  111. package/dist/ui/index.html +29 -0
  112. package/dist/ui/logo.svg +5 -0
  113. package/dist/ui/results.js +59 -0
  114. package/dist/ui/style.css +33 -0
  115. package/dist/verification/Verifier.d.ts +72 -0
  116. package/dist/verification/Verifier.js +87 -0
  117. package/dist/verification/Verifier.js.map +1 -0
  118. package/dist/workflows/WorkflowEngine.d.ts +23 -0
  119. package/dist/workflows/WorkflowEngine.js +52 -0
  120. package/dist/workflows/WorkflowEngine.js.map +1 -0
  121. package/docs/ADOPTION.md +61 -0
  122. package/docs/ARCHITECTURE.md +65 -0
  123. package/docs/BENCHMARKS.md +64 -0
  124. package/docs/IMPLEMENTATION.md +93 -0
  125. package/docs/LOCAL_DATA.md +98 -0
  126. package/docs/LOCAL_VALIDATION.md +87 -0
  127. package/docs/MCP.md +81 -0
  128. package/docs/PROVIDERS.md +150 -0
  129. package/docs/RELEASE_CHECKLIST.md +37 -0
  130. package/docs/REQUIREMENTS.md +39 -0
  131. package/docs/SUPPORT_MATRIX.md +193 -0
  132. package/docs/THREAT_MODEL.md +108 -0
  133. package/docs/USEFUL_EXAMPLES.md +151 -0
  134. package/docs/brand-mark.svg +12 -0
  135. package/package.json +90 -0
@@ -0,0 +1,33 @@
1
+ @font-face{font-family:Workspace;src:local("Avenir Next")}@font-face{font-family:Editorial;src:local("Georgia")}*{box-sizing:border-box}html{background:#f4f3ee;color:#252d29;font-family:Workspace,"Segoe UI",sans-serif;font-size:14px}body{margin:0}button,input,textarea,select{font:inherit}button,a,input,textarea,select{outline-offset:4px}button{cursor:pointer;border:1px solid #d9ddd3;background:transparent;border-radius:5px;padding:9px 13px;color:inherit;transition:background .15s}button:hover:enabled{background:#e6eadf}button:disabled{opacity:.4;cursor:default}button:focus-visible,input:focus-visible,textarea:focus-visible,select:focus-visible{outline:2px solid #456a3d}header{height:82px;padding:0 28px;display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid #d9ddd3;background:#fcfcf7}.brand{display:flex;gap:12px;align-items:center;text-decoration:none;color:inherit;font-weight:700;font-size:18px;letter-spacing:-.5px}.brandmark{height:44px;width:44px;display:block;flex:none}.edition{display:block;font:9px monospace;letter-spacing:1.6px;margin-top:4px;color:#52634a}.header-tools{display:flex;gap:24px;align-items:center}.local-badge{color:#52634a;font-size:12px}.local-badge i,.control-bar i{display:inline-block;width:6px;height:6px;border-radius:50%;background:#679752;margin-right:7px}.quiet{border:0;padding:8px 0}.quiet span{margin-left:10px}.workspace{display:grid;grid-template-columns:minmax(260px,310px) minmax(400px,1fr) 278px;min-height:calc(100vh - 82px)}.task-panel{padding:28px 26px 20px;border-right:1px solid #d9ddd3;display:flex;flex-direction:column}.panel-label,.micro,.section-title,.eyebrow{font-family:monospace;font-size:10px;letter-spacing:1.4px;color:#52634a}.panel-label{margin-bottom:26px}h1{font-size:27px;line-height:1.3;letter-spacing:-.9px;margin:0 0 15px;font-weight:500}h1 em{font-family:Editorial,serif;font-weight:400;color:#627656}.intro{line-height:1.65;color:#52634a;font-size:12px;margin:0 0 24px}label{display:block;font-size:11px;font-weight:600;margin:17px 0 8px}input,textarea,select{background:#fcfcf8;border:1px solid #d9ddd3;border-radius:5px;padding:11px;width:100%;color:#344030}textarea{resize:vertical;line-height:1.6}input::placeholder,textarea::placeholder{color:#52634a;font-size:12px}.options{margin:18px 0;color:#52634a;font-size:11px}.options summary{cursor:pointer;list-style:none;display:flex;justify-content:space-between}.check{display:flex;align-items:center;gap:8px}.check input{width:14px;accent-color:#456a3d}.primary{background:#d5ee79;border:1px solid #bcd962;font-weight:600;padding:12px 15px;display:flex;justify-content:space-between;align-items:center;color:#2b4024}.primary:hover:enabled{background:#c8e466}#run{width:100%;margin:22px 0 6px}.notice{font-size:12px;color:#526343;line-height:1.5;min-height:18px}.notice.error{color:#aa442f}.recent{border-top:1px solid #d9ddd3;margin-top:28px;padding-top:21px}.section-title{display:flex;align-items:center;justify-content:space-between;margin-bottom:15px}.section-title>span{letter-spacing:0;background:#e8eadf;padding:2px 6px;border-radius:3px}.section-title button{font-family:Workspace,sans-serif;letter-spacing:0;font-size:10px;padding:3px 7px}.empty-list{color:#52634a;font-size:11px;padding:10px 0}.history-item{border:0;border-bottom:1px solid #e0e3d8;text-align:left;padding:11px 0;width:100%;display:block;border-radius:0}.history-item strong{font-size:11px;font-weight:500;display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.history-item small{color:#52634a;font-size:9px;display:block;margin-top:5px}.history-item small b{font-weight:500;color:#52634a}.workflow-button{display:flex;justify-content:space-between;margin:15px 0;font-size:11px;color:#60724f}.task-footer{margin-top:auto;padding-top:30px;font:italic 15px Editorial,serif;line-height:1.6;color:#52634a}.task-footer strong{color:#53654b;font-weight:400}.browser-panel{padding:24px;min-width:0;background:#eeeee6}.browser-toolbar{background:#fafaf5;display:flex;align-items:center;gap:14px;padding:13px;border:1px solid #d8dcd0;border-radius:8px 8px 0 0}.traffic{display:flex;gap:5px}.traffic i{width:7px;height:7px;background:#c3c8bb;border-radius:50%}.traffic i:first-child{background:#cda997}.page-url{flex:1;font-family:monospace;font-size:10px;color:#52634a;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;background:#efefe7;padding:7px;border-radius:3px}.preview-tag{font:9px monospace;letter-spacing:1px;color:#52634a}.browser-stage{position:relative;min-height:365px;aspect-ratio:16/10;display:grid;place-items:center;background:#fcfcf7;border:1px solid #d8dcd0;border-top:0;overflow:hidden}.browser-empty{padding:28px;text-align:center;animation:arrive .5s both}.empty-symbol{width:48px;height:48px;font-size:30px;color:#4b6540;background:#e8eedc;margin:0 auto 25px;border-radius:50%;display:grid;place-items:center}.eyebrow{font-size:9px;color:#52634a}h2{font-weight:500;letter-spacing:-.6px}.browser-empty h2{font:34px/1.18 Editorial,serif;letter-spacing:-1px;margin:18px 0}.browser-empty p{font-size:12px;line-height:1.7;color:#52634a}.method{display:flex;justify-content:center;gap:12px;align-items:center;margin-top:24px;font:10px monospace;color:#52634a}.method b{color:#52634a;font-weight:400}#preview{display:block;width:100%;max-height:100%;object-fit:contain;cursor:default}#preview[hidden]{display:none}#preview.manual{cursor:crosshair}.control-bar{display:flex;justify-content:space-between;align-items:center;gap:8px;padding:13px 0;border-bottom:1px solid #d7dccf;font-size:10px;color:#52634a}.control-bar div{display:flex;gap:5px}.control-bar button{font-size:10px;padding:7px 9px;background:#f8f9f0}.danger{color:#8a3b35}.manual-tools{padding:12px;background:#e5ecd7;border-radius:5px;margin-top:10px}.manual-tools label{margin:0 0 10px}.manual-tools>div{display:flex;gap:7px}.manual-tools button{white-space:nowrap;font-size:11px}.manual-tools input{min-width:50px}.approval{padding:18px;background:#f4f7d3;border:1px solid #d5dbaa;margin-top:14px;border-radius:7px}.approval h3{margin:8px 0;font-size:18px;font-weight:500}.approval p{font-size:12px}.approval pre{font-size:10px;white-space:pre-wrap;overflow-wrap:anywhere;color:#52634a}.approval-actions{display:flex;gap:8px}.approval-actions button{font-size:11px}.activity{margin-top:24px}.activity ol{list-style:none;padding:0;margin:0;max-height:260px;overflow:auto;scrollbar-width:thin}.activity li{display:flex;align-items:flex-start;gap:12px;padding:10px 0;border-bottom:1px solid #dfe2d7;font-size:11px;color:#52634a}.activity li .phase{font:9px monospace;width:55px;flex-shrink:0;margin-top:2px;color:#52634a}.activity li .phase.EXECUTE{color:#52634a}.activity li .phase.ERROR{color:#8a3b35}.activity li .time{margin-left:auto;color:#52634a;font:9px monospace;white-space:nowrap}.stream-empty{font-family:monospace;color:#52634a!important}.state-panel{padding:28px 23px;background:#fcfcf7;border-left:1px solid #d9ddd3}.state-panel .panel-label{margin-bottom:23px}.state-title{display:flex;align-items:center;justify-content:space-between}.state-title h2{margin:0;font-size:18px}.status{background:#edf0e3;color:#52634a;font:9px monospace;letter-spacing:.5px;border-radius:3px;padding:5px 7px}.status.active{background:#e4eeb6;color:#52634a}.loop{display:flex;flex-wrap:wrap;gap:6px;margin:20px 0 26px}.loop span{font:9px monospace;border:1px solid #e3e7da;padding:5px;color:#52634a;border-radius:3px}.loop span.current{border-color:#a8c36e;color:#47612e;background:#f1f6df}.model-block{border-top:1px solid #dce1d3;border-bottom:1px solid #dce1d3;padding:19px 0}.model-block strong{display:block;margin-top:9px;font-size:14px;font-weight:500}.model-block p,.dom-stat p,.budget p{font-size:10px;line-height:1.5;color:#52634a;margin:6px 0 0}.metrics{margin-top:12px}.metrics>div{display:flex;justify-content:space-between;align-items:center;border-bottom:1px solid #e7eadf;padding:11px 0}.metrics span{font-size:11px;color:#52634a}.metrics strong{font:20px monospace;letter-spacing:-1px;color:#4a6237}.metrics .cost{border-bottom:0;padding-top:16px}.metrics .cost strong{font-size:22px}.budget{margin:20px 0 28px}.budget .section-title{margin-bottom:10px}.meter{height:4px;background:#eaeee0;border-radius:3px;overflow:hidden}.meter i{display:block;height:100%;width:0;background:#aacd61;transition:width .3s}.plan-section ol{padding-left:16px;font-size:11px;line-height:1.7;color:#52634a}.plan-section li{margin-bottom:8px}.dom-stat{border-top:1px solid #dce1d3;padding-top:19px;margin-top:25px}.dom-stat strong{display:block;font:26px Editorial,serif;margin-top:9px;color:#52634a}.warnings{font-size:11px;color:#795021;line-height:1.6;margin-top:15px}.privacy{font-size:9px;line-height:1.7;color:#52634a;border-top:1px solid #e4e9d9;padding-top:17px;margin-top:24px}dialog{border:1px solid #cdd6bb;border-radius:10px;width:min(640px,94vw);padding:28px;color:#34472c;background:#fcfdf5;box-shadow:0 30px 100px #20351333}dialog::backdrop{background:#22331966;backdrop-filter:blur(3px)}.dialog-heading{display:flex;align-items:center;justify-content:space-between}.dialog-heading h2{margin:0}.dialog-heading button{border:0;font-size:22px}dialog p{color:#52634a;font-size:12px;line-height:1.7}dialog textarea{font:11px/1.6 monospace;min-height:150px}dialog .primary{margin-top:17px}.hint{font-size:10px!important}.workflow-row{padding:16px 0;border-top:1px solid #dde5d0;font-size:12px;overflow-wrap:anywhere}.workflow-row small{display:block;color:#52634a;margin-top:7px}[hidden]{display:none!important}@keyframes arrive{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}@media(min-width:1600px){.workspace{grid-template-columns:340px 1fr 300px}.browser-panel{padding:32px}.browser-stage{max-height:650px}.task-panel{padding:32px}.state-panel{padding:32px}}@media(max-width:1120px){.workspace{grid-template-columns:260px minmax(350px,1fr)}.state-panel{grid-column:1/-1;display:grid;grid-template-columns:repeat(3,1fr);gap:20px;border-left:0;border-top:1px solid #d9ddd3}.state-panel>.panel-label,.state-panel>.privacy{display:none}.state-title{grid-column:1}.loop{grid-column:2/4;margin:0}.model-block{grid-column:1;padding:14px 0}.metrics{grid-column:2;grid-row:2/4;margin:0}.budget{grid-column:3;margin:0}.plan-section{grid-column:3}.dom-stat{grid-column:1;grid-row:3;margin:0}.warnings{grid-column:1/-1}}@media(max-width:650px){header{height:70px;padding:0 16px}.brand{font-size:15px}.header-tools{gap:12px}.local-badge{display:none}.header-tools button{font-size:11px}.workspace{display:flex;flex-direction:column}.task-panel{padding:23px;border-right:0}h1{font-size:27px}.task-panel .panel-label{margin-bottom:15px}.intro{margin-bottom:8px}.task-footer{display:none}.recent{margin-top:20px}#history{max-height:125px;overflow:auto}.browser-panel{padding:16px}.browser-stage{min-height:300px;aspect-ratio:auto}.browser-empty h2{font-size:30px}.browser-empty{padding:22px}.method{gap:8px}.control-bar{flex-wrap:wrap;gap:12px}.manual-tools>div{flex-wrap:wrap}.state-panel{padding:23px;display:grid;grid-template-columns:1fr 1fr}.state-title{grid-column:1/-1}.loop{grid-column:1/-1;grid-row:2}.model-block{grid-column:1;grid-row:3}.metrics{grid-column:2;grid-row:3/6}.budget{grid-column:1;grid-row:4}.plan-section{grid-column:1/-1;grid-row:6}.dom-stat{grid-column:1;grid-row:5}.activity li .time{display:none}}@media(prefers-reduced-motion:reduce){*{animation:none!important;transition:none!important}}
2
+
3
+ .page-scroll{display:flex;gap:3px;flex:none}.page-scroll button{padding:4px 8px;font-size:14px}
4
+ #result-dialog{width:min(840px,94vw);padding:28px;background:#f8f9f3}
5
+ #result-dialog .dialog-heading h2{font:30px Editorial,serif;margin:7px 0 0;color:#263e34}
6
+ .result-tools{display:flex;gap:8px;margin:20px 0}.result-tools button{font-size:11px;background:#fff}
7
+ #result-panel{margin:0;padding:0;border:0;background:transparent;max-height:62dvh;overflow:auto;scrollbar-width:thin}
8
+ .result-overview{display:flex;align-items:center;justify-content:space-between;gap:10px;margin:0 0 14px}
9
+ .result-status{font:10px monospace;text-transform:uppercase;letter-spacing:1px;border-radius:20px;padding:7px 10px;background:#e7efdf;color:#3d643a}
10
+ .result-status.partial{background:#fff0d8;color:#795021}.result-count{font-size:11px;color:#52634a}
11
+ .result-caveat{padding:13px 16px;border-left:3px solid #d7a35e;background:#fff3df;border-radius:0 6px 6px 0;color:#795021!important;font-size:12px!important}
12
+ .result-card{margin:12px 0;padding:21px;background:#fff;border:1px solid #dce3d7;border-radius:10px}
13
+ .result-card h3{font:10px monospace;text-transform:uppercase;letter-spacing:1.2px;color:#52634a;margin:0 0 20px}
14
+ .result-facts{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:20px 32px;margin:0}
15
+ .result-facts dt{font-size:11px;color:#52634a}.result-facts dd{margin:5px 0 0;font-size:17px;color:#2b4236;font-weight:600;overflow-wrap:anywhere}
16
+ .result-prose{font-size:13px;line-height:1.8;white-space:pre-wrap;overflow-wrap:anywhere;color:#3a5040}
17
+ .result-source{margin-top:22px;padding-top:13px;border-top:1px solid #edf0e9;font-size:11px;color:#52634a}.result-source summary{cursor:pointer}.result-source .result-prose{margin-top:16px;font-size:12px}
18
+ .result-supporting{font-size:11px;color:#52634a}.result-supporting summary{cursor:pointer}.result-supporting .result-prose{margin-top:16px}
19
+ #agent-cursor.preparing::before{content:"";position:absolute;left:-8px;top:-8px;width:18px;height:18px;border:1px solid #567bcb88;background:#a9c6ff22;border-radius:50%;animation:preparing-cursor 1.6s ease-in-out infinite;z-index:-1}
20
+ #pointer-layer #agent-cursor{left:-2px;top:-2px;filter:drop-shadow(0 2px 3px #1452a855)}
21
+ @keyframes preparing-cursor{0%,100%{opacity:.35}50%{opacity:.9}}
22
+ .result-table-wrap{overflow:auto}.result-table{width:100%;border-collapse:collapse;white-space:normal;font-size:12px}
23
+ .result-table th{text-align:left;font-size:10px;color:#52634a;font-weight:500;background:#f6f8f1;padding:12px}
24
+ .result-table td{padding:14px 12px;border-bottom:1px solid #e9eee4;color:#324d3a;min-width:100px;max-width:320px;overflow-wrap:anywhere}.result-table tbody tr:last-child td{border-bottom:0}
25
+ .result-links{list-style:none;margin:0;padding:0}.result-links li{padding:12px 0;border-bottom:1px solid #edf0e9}.result-links a{color:#345e99;font-size:13px}.result-links small{display:block;font-size:10px;overflow-wrap:anywhere;color:#52634a;margin-top:5px}
26
+ .result-file{display:flex;gap:12px;align-items:center;flex-wrap:wrap;padding:12px 0}.file-icon{width:32px;height:38px;display:grid;place-items:center;border:1px solid #d9e1d2;border-radius:4px;color:#4c6c40;background:#f4f8ed;font-size:20px}.result-file strong{font-weight:500;font-size:12px;overflow-wrap:anywhere;min-width:0}.file-save{margin-left:auto;color:#375d44;font-size:11px;border:1px solid #d4dfca;border-radius:5px;padding:8px 10px;text-decoration:none}
27
+ .result-empty{font-size:12px;color:#52634a}.result-list{font-size:13px;line-height:1.8}
28
+ @media(max-width:650px){#result-dialog{padding:18px}.result-card{padding:16px}.result-facts{gap:18px}.result-facts dd{font-size:15px}.result-count{font-size:10px}.file-save{margin-left:44px}.browser-toolbar .preview-tag{display:none}}
29
+
30
+ #preview{height:100%;min-height:0}#pointer-layer{position:absolute;inset:0;pointer-events:none;overflow:hidden}#agent-cursor{position:absolute;left:-1px;top:-1px;will-change:transform;filter:drop-shadow(0 1px 2px #183c3444);transition:transform 35ms linear}#agent-cursor svg{display:block}#agent-cursor.typing{filter:drop-shadow(0 0 3px #507bec66)}#click-ring{position:absolute;width:28px;height:28px;margin:-14px;border:1.5px solid #537be6;background:#87a5ff22;border-radius:50%;opacity:0}#click-ring.pulse{animation:click-pulse .55s ease-out}.interaction-line{display:flex;align-items:center;gap:7px;padding:12px 0 0;color:#526343;font-size:11px;min-width:0}.interaction-dot{height:5px;width:5px;background:#8eab53;border-radius:50%;flex-shrink:0}.interaction-note{margin-left:auto;color:#52634a;font:9px monospace;white-space:nowrap}@keyframes click-pulse{0%{opacity:1;scale:.4}100%{opacity:0;scale:1.6}}@media(max-width:650px){.interaction-note{display:none}}@media(prefers-reduced-motion:reduce){#click-ring.pulse{animation:none;opacity:.7}}
31
+ #fullscreen{font-size:10px;padding:6px 8px;white-space:nowrap}.mobile-view-switch{display:none}.run-options{border:0;padding:0;display:flex;justify-content:space-between;width:100%;font-size:11px;color:#52634a;margin-top:18px}.permission-note{font-size:10px;color:#52634a;line-height:1.5;margin:10px 0 0}.workspace-links{border-top:1px solid #d9ddd3;margin-top:22px;padding-top:8px}.workspace-links button{width:100%;margin:10px 0}.workspace{height:calc(100dvh - 82px);min-height:0}.task-panel,.state-panel{min-height:0;overflow:auto}.browser-panel{display:flex;flex-direction:column;min-height:0;padding:20px}.browser-toolbar,.interaction-line,.control-bar,.approval,.manual-tools{flex:none}.browser-stage{flex:1;aspect-ratio:auto;min-height:120px;max-height:none}#preview{position:absolute;inset:0;width:100%;height:100%;max-height:none}.browser-empty{padding:16px}.control-bar{flex-wrap:wrap;gap:10px}.control-bar>div{flex-wrap:wrap}.approval{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:14px;margin-top:10px}.approval h3{font-size:14px;margin:4px 0}.approval p{font-size:11px;margin:4px 0;overflow-wrap:anywhere;max-width:60ch}.approval-actions{flex:none;align-items:center}.approval-actions .primary{padding:10px 12px}.approval-details{position:relative;flex:none;font-size:10px;color:#52634a}.approval-details summary{cursor:pointer}.approval-details pre{position:absolute;bottom:100%;right:0;width:min(430px,75vw);max-height:250px;overflow:auto;padding:15px;background:#fcfdf5;border:1px solid #c6d09e;border-radius:6px;box-shadow:0 8px 30px #20351322;z-index:5}.stream-dialog{width:min(850px,94vw)}.stream-dialog .activity{margin-top:16px}.stream-dialog .activity ol{max-height:55dvh}.results{margin:15px 0 0}.results pre{max-height:60dvh;overflow:auto;white-space:pre-wrap;overflow-wrap:anywhere;font:11px/1.7 monospace}.browser-panel:fullscreen,.browser-panel.expanded{width:100vw;height:100dvh;padding:20px;background:#eeeee6;display:flex}.browser-panel.expanded{position:fixed;inset:0;z-index:200}.browser-panel:fullscreen .browser-stage,.browser-panel.expanded .browser-stage{max-height:none}.task-footer{padding-top:14px}body{height:100dvh;overflow:hidden}dialog{max-height:90dvh;overflow:auto}@media(min-width:651px) and (max-width:1120px){.workspace{grid-template-columns:240px minmax(0,1fr) 220px}.state-panel{grid-column:auto;display:block;padding:22px 18px;border-left:1px solid #d9ddd3;border-top:0}.state-panel>.panel-label,.state-panel>.privacy{display:block}.state-panel .loop{margin:16px 0}.state-panel .metrics{margin-top:12px}.state-panel .budget{margin:18px 0}.state-panel .dom-stat{margin-top:20px}.task-panel{padding:22px 18px}.browser-panel{padding:16px}.approval{flex-wrap:wrap;gap:8px}.approval>div:first-child{width:100%}.browser-empty h2{font-size:28px}.browser-empty .eyebrow{font-size:8px}.interaction-note{display:none}}@media(max-height:800px){.task-panel{padding-top:18px}.task-panel .panel-label{margin-bottom:16px}.task-panel h1{font-size:24px;margin-bottom:10px}.task-panel .intro{margin-bottom:10px}.task-panel label{margin-top:12px}.task-panel textarea{height:110px}.workspace-links{margin-top:12px}.task-footer{display:none}.state-panel{padding-top:18px}.state-panel .loop{margin:12px 0 16px}.state-panel .model-block{padding:12px 0}.state-panel .metrics>div{padding:9px 0}.state-panel .budget{margin:16px 0}}@media(max-width:650px){.mobile-view-switch{display:flex;height:40px;align-items:center;justify-content:center;gap:8px;background:#fcfcf7;border-bottom:1px solid #d9ddd3}.mobile-view-switch button{font-size:11px;padding:6px 16px;border:0}.mobile-view-switch button[aria-pressed=true]{background:#e9efda;color:#3d582f}.workspace{height:calc(100dvh - 110px)}.workspace>.task-panel,.workspace>.browser-panel,.workspace>.state-panel{height:100%;width:100%;flex:none}.workspace>.state-panel{display:block;overflow:auto}.workspace>.browser-panel{display:flex}.workspace>.task-panel{overflow:auto}body:not([data-mobile-view=browser]) .workspace>.browser-panel{display:none}body:not([data-mobile-view=stats]) .workspace>.state-panel{display:none}body[data-mobile-view=browser] .workspace>.task-panel,body[data-mobile-view=stats] .workspace>.task-panel{display:none}.browser-panel{padding:12px}.browser-stage{min-height:100px}.browser-empty h2{font-size:28px}.browser-empty .method{margin-top:12px}.empty-symbol{margin-bottom:14px}.browser-toolbar{gap:8px;padding:10px}.traffic{display:none}#fullscreen span{display:none}#fullscreen{font-size:18px}.control-bar{font-size:10px;gap:8px}.control-bar button{padding:7px}.approval{flex-wrap:wrap;gap:10px}.approval>div:first-child{width:100%}.approval-details{margin-right:auto}.approval-details pre{right:auto;left:0}.workspace-links button{margin:8px 0}.browser-panel:fullscreen,.browser-panel.expanded{padding:12px}.manual-tools{padding:10px}.state-panel .state-title{margin-bottom:18px}.state-panel .model-block{margin-top:16px}}
32
+ .site-permissions{border-top:1px solid #d9ddd3;margin-top:20px;padding-top:16px}.site-permissions h3{font-size:14px;margin:0 0 6px}.site-permissions p{font-size:11px;line-height:1.55;color:#687467;margin:0 0 12px}.site-permissions ul{list-style:none;padding:0;margin:0;display:grid;gap:8px}.site-permissions li{display:flex;align-items:center;justify-content:space-between;gap:12px;min-width:0;padding:8px 10px;border:1px solid #d9ddd3;border-radius:8px;font-size:12px}.site-permissions li span{min-width:0;overflow-wrap:anywhere}.site-permissions li.empty{color:#687467}.site-permissions li button{flex:none;padding:6px 10px;color:#8a3b35;border-color:#d9b3af;background:#fff9f8}
33
+ .status.blocked{background:#f7dfdc;color:#8a3b35}.phase.BLOCKED{background:#f7dfdc;color:#8a3b35}
@@ -0,0 +1,72 @@
1
+ import type { Condition } from '../actions/schema.js';
2
+ import type { Browser } from '../browser/Browser.js';
3
+ import type { Observer } from '../browser/Observer.js';
4
+ import type { VariableResolver } from '../profile/VariableResolver.js';
5
+ export declare class Verifier {
6
+ readonly browser: Browser;
7
+ readonly observer: Observer;
8
+ readonly variables: VariableResolver;
9
+ constructor(browser: Browser, observer: Observer, variables: VariableResolver);
10
+ one(condition: Condition, since?: number): Promise<boolean>;
11
+ check(conditions: Condition[], timeoutMs?: number, since?: number): Promise<{
12
+ success: boolean;
13
+ failed: ({
14
+ type: "input_value_equals";
15
+ target: string | {
16
+ role?: string | undefined;
17
+ name?: string | undefined;
18
+ label?: string | undefined;
19
+ placeholder?: string | undefined;
20
+ testId?: string | undefined;
21
+ id?: string | undefined;
22
+ attributeName?: string | undefined;
23
+ text?: string | undefined;
24
+ css?: string | undefined;
25
+ frame?: number | undefined;
26
+ };
27
+ value: string;
28
+ } | {
29
+ type: "extraction_created";
30
+ key?: string | undefined;
31
+ } | {
32
+ type: "extraction_contains";
33
+ key?: string | undefined;
34
+ value: string;
35
+ } | {
36
+ type: "tab_count";
37
+ count: number;
38
+ } | {
39
+ type: "extraction_count";
40
+ key?: string | undefined;
41
+ min: number;
42
+ max?: number | undefined;
43
+ } | {
44
+ type: "checkbox_checked" | "element_exists" | "element_not_visible" | "element_visible" | "form_submitted";
45
+ target: string | {
46
+ role?: string | undefined;
47
+ name?: string | undefined;
48
+ label?: string | undefined;
49
+ placeholder?: string | undefined;
50
+ testId?: string | undefined;
51
+ id?: string | undefined;
52
+ attributeName?: string | undefined;
53
+ text?: string | undefined;
54
+ css?: string | undefined;
55
+ frame?: number | undefined;
56
+ };
57
+ } | {
58
+ type: "text_disappeared" | "text_exists" | "title_changed" | "url_contains" | "url_equals";
59
+ value: string;
60
+ } | {
61
+ type: "network_response";
62
+ value: string;
63
+ status?: number | undefined;
64
+ } | {
65
+ type: "download_created";
66
+ value?: string | undefined;
67
+ } | {
68
+ type: "page_changed";
69
+ value: string;
70
+ })[];
71
+ }>;
72
+ }
@@ -0,0 +1,87 @@
1
+ export class Verifier {
2
+ browser;
3
+ observer;
4
+ variables;
5
+ constructor(browser, observer, variables) {
6
+ this.browser = browser;
7
+ this.observer = observer;
8
+ this.variables = variables;
9
+ }
10
+ async one(condition, since = 0) {
11
+ const page = this.browser.page;
12
+ if (condition.type === 'form_submitted') {
13
+ const target = this.observer.selectors.descriptor(condition.target);
14
+ return this.browser.formReceipts.some(f => {
15
+ const matches = JSON.stringify(f.target) === JSON.stringify(target) || (f.id && (target.id === f.id || target.css === `#${f.id}` || target.css === `form#${f.id}`)) || (f.label && (target.label === f.label || target.role === 'form' && target.name === f.label)) || (f.unique && target.css === 'form');
16
+ const action = new URL(f.actionURL);
17
+ return matches && f.time >= since && this.browser.responses.some(r => { const url = new URL(r.url); return r.time >= f.time && r.status >= 200 && r.status < 400 && r.method === f.method && r.resource === 'document' && url.origin === action.origin && url.pathname === action.pathname; });
18
+ });
19
+ }
20
+ if ('target' in condition) {
21
+ let locator;
22
+ try {
23
+ locator = (await this.observer.selectors.resolve(page, condition.target, 100)).locator;
24
+ }
25
+ catch {
26
+ return condition.type === 'element_not_visible';
27
+ }
28
+ switch (condition.type) {
29
+ case 'element_exists': return await locator.count() > 0;
30
+ case 'element_visible': return locator.isVisible();
31
+ case 'element_not_visible': return !(await locator.isVisible());
32
+ case 'input_value_equals': return await locator.inputValue() === this.variables.resolve(condition.value);
33
+ case 'checkbox_checked': return locator.isChecked();
34
+ }
35
+ }
36
+ switch (condition.type) {
37
+ case 'extraction_created': return this.browser.extractions.some(e => !condition.key || e.key === condition.key);
38
+ case 'extraction_contains': return this.browser.extractions.some(e => (!condition.key || e.key === condition.key) && JSON.stringify(e.value).includes(this.variables.resolve(condition.value)));
39
+ case 'tab_count': return this.browser.context.pages().length === condition.count;
40
+ case 'extraction_count': {
41
+ const values = this.browser.extractions.filter(e => !condition.key || e.key === condition.key).flatMap(e => Array.isArray(e.value) ? e.value : []);
42
+ const size = new Set(values.map(v => JSON.stringify(v))).size;
43
+ return size >= condition.min && (condition.max === undefined || size <= condition.max);
44
+ }
45
+ case 'url_equals': return page.url() === this.variables.resolve(condition.value);
46
+ case 'url_contains': return page.url().includes(this.variables.resolve(condition.value));
47
+ case 'title_changed': return await page.title() !== condition.value;
48
+ case 'text_exists':
49
+ for (const frame of page.frames())
50
+ if (await frame.getByText(this.variables.resolve(condition.value), { exact: false }).filter({ visible: true }).count() > 0)
51
+ return true;
52
+ return false;
53
+ case 'text_disappeared':
54
+ for (const frame of page.frames())
55
+ if (await frame.getByText(this.variables.resolve(condition.value), { exact: false }).filter({ visible: true }).count() > 0)
56
+ return false;
57
+ return true;
58
+ case 'download_created': return this.browser.downloads.some(d => !condition.value || d.filename === condition.value);
59
+ case 'network_response': return this.browser.responses.some(r => r.time >= since && r.url.includes(condition.value) && (!condition.status || r.status === condition.status));
60
+ case 'page_changed': return (await this.observer.inspect(page)).hash !== condition.value;
61
+ }
62
+ return false;
63
+ }
64
+ async check(conditions, timeoutMs = 3000, since = 0) {
65
+ const deadline = Date.now() + timeoutMs;
66
+ let failed = [];
67
+ do {
68
+ if (this.browser.page.isClosed())
69
+ return { success: false, failed: conditions };
70
+ failed = [];
71
+ for (const condition of conditions) {
72
+ try {
73
+ if (!await this.one(condition, since))
74
+ failed.push(condition);
75
+ }
76
+ catch {
77
+ failed.push(condition);
78
+ }
79
+ }
80
+ if (!failed.length)
81
+ return { success: true, failed };
82
+ await this.browser.page.waitForTimeout(60);
83
+ } while (Date.now() < deadline);
84
+ return { success: false, failed };
85
+ }
86
+ }
87
+ //# sourceMappingURL=Verifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Verifier.js","sourceRoot":"","sources":["../../src/verification/Verifier.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import { type Plan } from '../actions/schema.js';
2
+ import type { PageState } from '../browser/types.js';
3
+ import type { TraceStore, Trace } from '../history/TraceStore.js';
4
+ export declare const normalizeIntent: (goal: string) => string;
5
+ export declare const structureHash: (state: PageState) => string;
6
+ export interface Workflow {
7
+ id: string;
8
+ origin: string;
9
+ path: string;
10
+ intent: string;
11
+ structure: string;
12
+ plan: Plan;
13
+ learnedFrom: string;
14
+ createdAt: number;
15
+ }
16
+ export declare class WorkflowEngine {
17
+ readonly store: TraceStore;
18
+ constructor(store: TraceStore);
19
+ match(goal: string, state: PageState): Workflow | undefined;
20
+ learn(trace: Trace, initial: PageState): Workflow | undefined;
21
+ list(): Record<string, import("node:sqlite").SQLOutputValue>[];
22
+ get(id: string): Workflow | undefined;
23
+ }
@@ -0,0 +1,52 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { PlanSchema } from '../actions/schema.js';
3
+ export const normalizeIntent = (goal) => goal.toLowerCase().replace(/\s+/g, ' ').trim();
4
+ export const structureHash = (state) => createHash('sha256').update(JSON.stringify(state.elements.map(e => [e.role, e.name, e.type, e.required]))).digest('hex').slice(0, 20);
5
+ export class WorkflowEngine {
6
+ store;
7
+ constructor(store) {
8
+ this.store = store;
9
+ }
10
+ match(goal, state) {
11
+ const url = new URL(state.url);
12
+ const intent = normalizeIntent(goal), structure = structureHash(state);
13
+ const rows = this.store.db.prepare('SELECT workflow FROM workflows WHERE domain=? AND intent=? AND structure=?').all(url.origin, intent, structure);
14
+ for (const row of rows) {
15
+ const workflow = JSON.parse(row.workflow);
16
+ if (workflow.path === url.pathname) {
17
+ PlanSchema.parse(workflow.plan);
18
+ this.store.db.prepare('UPDATE workflows SET hits=hits+1 WHERE id=?').run(workflow.id);
19
+ return workflow;
20
+ }
21
+ }
22
+ return;
23
+ }
24
+ learn(trace, initial) {
25
+ if (trace.status !== 'completed' || !trace.actions.length)
26
+ return;
27
+ const actions = trace.actions.filter(result => result.success).map(result => result.action);
28
+ const completion = [...new Map(trace.completion.map(c => [JSON.stringify(c), c])).values()];
29
+ if (actions.length > 80 || completion.length > 12)
30
+ return;
31
+ if (actions.some(action => containsRef(action)))
32
+ return; // Only portable semantic workflows.
33
+ const url = new URL(initial.url), intent = normalizeIntent(trace.goal), structure = structureHash(initial);
34
+ const id = createHash('sha256').update([url.origin, url.pathname, intent, structure].join('\n')).digest('hex').slice(0, 16);
35
+ const plan = PlanSchema.parse({ goal: trace.goal, steps: trace.plans.flatMap(p => p.steps).slice(0, 12), actions, completion, continue: false });
36
+ const workflow = { id, origin: url.origin, path: url.pathname, intent, structure, plan, learnedFrom: trace.id, createdAt: Date.now() };
37
+ this.store.db.prepare('INSERT OR REPLACE INTO workflows(id,domain,intent,structure,workflow,hits) VALUES(?,?,?,?,?,COALESCE((SELECT hits FROM workflows WHERE id=?),0))').run(id, url.origin, intent, structure, JSON.stringify(workflow), id);
38
+ return workflow;
39
+ }
40
+ list() { return this.store.db.prepare('SELECT id,domain,intent,hits FROM workflows ORDER BY hits DESC').all(); }
41
+ get(id) { const row = this.store.db.prepare('SELECT workflow FROM workflows WHERE id=?').get(id); return row ? JSON.parse(row.workflow) : undefined; }
42
+ }
43
+ function containsRef(action) {
44
+ if ('target' in action && typeof action.target === 'string')
45
+ return true;
46
+ if ('condition' in action && containsRef(action.condition))
47
+ return true;
48
+ if ('verify' in action && action.verify?.some(containsRef))
49
+ return true;
50
+ return false;
51
+ }
52
+ //# sourceMappingURL=WorkflowEngine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WorkflowEngine.js","sourceRoot":"","sources":["../../src/workflows/WorkflowEngine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ # Adoption tracking
2
+
3
+ This project does not collect hidden product telemetry. Adoption is reviewed from
4
+ public repository and registry data, plus task reports that users choose to
5
+ share. Local browser interaction events only drive the dashboard visualization;
6
+ they are not an installation or usage counter.
7
+
8
+ ## Public baseline — 24 September 2026
9
+
10
+ | Signal | Observed value | Source |
11
+ | --- | ---: | --- |
12
+ | GitHub stars | 5 | Public repository metadata |
13
+ | GitHub forks | 1 | Public repository metadata |
14
+ | Watchers | 0 | Public repository metadata |
15
+ | Listed contributors | 1 | Public contributors endpoint |
16
+ | Open issues / pull requests | 0 / 0 | Public GitHub API |
17
+ | Discussions | Disabled | Public repository metadata |
18
+ | GitHub releases / asset downloads | 0 / not applicable | Public releases endpoint |
19
+ | npm `free-computer-use@0.1.0` | Not published (registry returned 404) | npm registry query |
20
+ | Installations / community task reproductions | Installations not measured; no public reproductions documented | No installation telemetry; public issue list is empty and Discussions are disabled |
21
+
22
+ This is a dated baseline, not a growth claim. GitHub stars and forks are
23
+ secondary signals; they do not show that an installation or browser task
24
+ worked. No public issue or discussion currently records a user reproduction.
25
+
26
+ ## Monthly review
27
+
28
+ Review these public signals on or after the 24th of each month, after a public
29
+ release exists:
30
+
31
+ 1. Record stars, forks, listed contributors, open issues and pull requests.
32
+ 2. Sum download counts for published GitHub Release assets. Record npm registry
33
+ downloads only after the package is published.
34
+ 3. Review public bug reports for installation, provider, security, documentation
35
+ and workflow blockers. Link each confirmed problem to a roadmap acceptance
36
+ criterion and an issue; close the loop with a reproduced fix or a documented
37
+ limitation.
38
+ 4. Record user-reported task reproductions only when the user chooses to share
39
+ them. Ask before quoting or publishing private feedback.
40
+
41
+ Do not infer installation counts from stars, add background analytics, or use
42
+ owner-only GitHub traffic reports as public adoption data. Keep reviews manual;
43
+ the repository's current policy does not allow GitHub Actions validation.
44
+
45
+ ## Collection commands
46
+
47
+ These read public metadata and do not change the repository:
48
+
49
+ ```sh
50
+ gh api repos/OthmaneBlial/FreeComputerUse --jq '{stars: .stargazers_count, forks: .forks_count, watchers: .subscribers_count, discussions: .has_discussions}'
51
+ gh api 'repos/OthmaneBlial/FreeComputerUse/issues?state=open&per_page=100' --jq '[.[] | select(has("pull_request") | not)] | length'
52
+ gh api 'repos/OthmaneBlial/FreeComputerUse/pulls?state=open&per_page=100' --jq 'length'
53
+ gh api 'repos/OthmaneBlial/FreeComputerUse/contributors?per_page=100' --jq 'length'
54
+ gh api 'repos/OthmaneBlial/FreeComputerUse/releases?per_page=100' --jq '[.[] | .assets[].download_count] | add // 0'
55
+ npm view free-computer-use@0.1.0 version
56
+ ```
57
+
58
+ An npm 404 means no public version was found; it is not a zero-download
59
+ measurement. Do not query or publish private analytics to fill gaps.
60
+
61
+ **Next review:** 24 October 2026, or after the first public release if later.
@@ -0,0 +1,65 @@
1
+ # Architecture
2
+
3
+ FreeComputerUse is a local Node.js process. The model proposes bounded browser
4
+ actions; the local policy and executor decide whether and how those actions run.
5
+ There is no hosted application server or background cloud sync in this design.
6
+
7
+ ```mermaid
8
+ flowchart LR
9
+ CLI[CLI] --> CONFIG[Config]
10
+ UI[Local dashboard] --> API[Loopback HTTP API]
11
+ API --> AGENT[Agent]
12
+ CLI --> AGENT
13
+ AGENT --> OBS[DOM observer and compressor]
14
+ OBS --> PROVIDER[API provider or local CLI]
15
+ PROVIDER --> SCHEMA[Validated action plan]
16
+ SCHEMA --> POLICY[Origin and action policy]
17
+ POLICY --> EXEC[Playwright executor]
18
+ EXEC --> BROWSER[Local browser]
19
+ BROWSER --> VERIFY[Result verifier]
20
+ AGENT --> STORE[Local SQLite traces and workflows]
21
+ API --> PROFILE[Local profile vault]
22
+ ```
23
+
24
+ ## Request path
25
+
26
+ 1. `src/cli/index.ts` loads environment configuration and starts a task, the
27
+ local dashboard, or a diagnostic. `src/config.ts` resolves provider settings,
28
+ token limits and the dedicated local data directory.
29
+ 2. `src/agent/Agent.ts` coordinates observation, planning, execution, repair,
30
+ independent completion checks and trace updates. `Control` carries approval,
31
+ pause, resume and stop signals.
32
+ 3. `Observer`, `DomExtractor` and `PageCompressor` collect a bounded DOM-based
33
+ page description. `LLMProvider` adapters return a structured plan; Zod
34
+ schemas validate it before `Executor` can act.
35
+ 4. `policy.ts` applies site-origin and sensitive-action rules. `Browser.ts`
36
+ attaches Chromium request guards, and `NetworkGuardProxy.ts` checks proxied
37
+ HTTP(S)/WebSocket destinations. `Executor` performs the fixed action set;
38
+ it does not evaluate model-supplied JavaScript or shell commands.
39
+ 5. `Verifier` checks task-specific completion evidence. `WorkflowEngine` stores
40
+ compatible learned workflows and replays them without another model request,
41
+ while retaining the regular permission checks.
42
+
43
+ ## Local surfaces and data
44
+
45
+ - `src/server/index.ts` serves the dashboard only on loopback and checks its
46
+ session cookie, Host, Origin and CSRF token. `src/ui/` contains the browser UI.
47
+ - `ProfileStore` stores explicitly configured aliases; `TraceStore` stores run
48
+ history and learned workflows in SQLite. Browser profiles and downloads use
49
+ the same configured data directory. Details, retention and deletion are in
50
+ [Local data](LOCAL_DATA.md).
51
+ - API mode sends the page context needed to plan to the selected provider.
52
+ Subscription modes invoke the corresponding local provider CLI. Provider
53
+ routes and evidence are in [Providers](PROVIDERS.md) and the
54
+ [support matrix](SUPPORT_MATRIX.md).
55
+ - `lab/` is a set of deterministic local practice pages. `docs/` is the GitHub
56
+ Pages source and contains the public landing page and lab copy. It is not the
57
+ agent runtime.
58
+
59
+ ## Change boundaries
60
+
61
+ Changes to a trust boundary need negative tests plus a matching allowed-path
62
+ test. Changes to a provider need contract tests and updated support evidence.
63
+ Changes to local storage need import-failure, permission and cleanup checks.
64
+ Run `npm run check` for types and `npm run validate` for the complete local
65
+ gate; the validation policy intentionally does not use GitHub Actions.
@@ -0,0 +1,64 @@
1
+ # Measured validation
2
+
3
+ Provider-by-provider implementation, automated-test and live-evidence status is
4
+ tracked in the [support matrix](SUPPORT_MATRIX.md). This report records the
5
+ specific dated trials below; it does not establish general provider or website
6
+ compatibility.
7
+
8
+ Public suite measured 2026-09-18T16:52:19.246Z using real deepseek-flash, Node v25.9.0, Playwright 1.63.0.
9
+
10
+ 14/14 public tasks passed their independent result checks. 14/14 compatible learned repeats passed with no provider installed and zero model calls. First runs used 30 successful browser actions, 18 model calls and 31,654 total tokens. Configured-price estimate: $0.006109 for those first runs.
11
+
12
+ | Scenario | Correctness | Actions | Calls | Tokens | Execution repairs | Learned repeat |
13
+ | --- | --- | ---: | ---: | ---: | ---: | --- |
14
+ | Product comparison / Books to Scrape | Pass | 1 | 1 | 3772 | 0 | Pass / 0 |
15
+ | Travel search / BlazeDemo | Pass | 4 | 1 | 1687 | 0 | Pass / 0 |
16
+ | Dashboard tables / The Internet | Pass | 1 | 1 | 2054 | 0 | Pass / 0 |
17
+ | Dropdown setting / The Internet | Pass | 1 | 1 | 1435 | 0 | Pass / 0 |
18
+ | Dynamic loading / The Internet | Pass | 3 | 1 | 1482 | 0 | Pass / 0 |
19
+ | Structured research / Quotes to Scrape | Pass | 1 | 1 | 2201 | 0 | Pass / 0 |
20
+ | Invoice download / public Northstar lab | Pass | 1 | 1 | 1470 | 0 | Pass / 0 |
21
+ | Revenue extraction / public Northstar lab | Pass | 1 | 1 | 1573 | 0 | Pass / 0 |
22
+ | Local preferences / public Northstar lab | Pass | 3 | 1 | 1657 | 0 | Pass / 0 |
23
+ | Persistent session / public Northstar lab | Pass | 1 | 1 | 1510 | 0 | Pass / 0 |
24
+ | Dynamic modal / public Northstar lab | Pass | 4 | 2 | 3123 | 0 | Pass / 0 |
25
+ | Embedded form / public Northstar lab | Pass | 3 | 1 | 1686 | 0 | Pass / 0 |
26
+ | Multiple tabs / public Northstar lab | Pass | 5 | 3 | 4936 | 1 | Pass / 0 |
27
+ | DOM repair / public Northstar lab | Pass | 1 | 2 | 3068 | 1 | Pass / 0 |
28
+
29
+ ## Local integration suite
30
+
31
+ Measured 2026-09-18T16:52:23.922Z: 6/6 tasks and 6/6 provider-free learned repeats passed. First runs used 31 actions, 10 model calls and 16,392 tokens. Cases include synthetic search, contact form, travel wizard, product filtering, a multi-page application with upload/approval, and changed-control recovery.
32
+
33
+ ## Method and limitations
34
+
35
+ Every scenario requires deterministic final conditions plus an independent oracle for extracted data, field values, saved settings, file bytes or browser/session outcome. Runtime completion alone is not accepted as task correctness. A repeat uses the same goal and compatible starting page; no general site-transfer claim is made. Website approvals remain enabled and are explicitly handled by the harness for its selected sandbox origin.
36
+
37
+ External sites are read-only scraping/automation sandboxes. Forms, settings, session login and injected DOM changes use our own synthetic lab. No messages to people, purchases, real accounts or real account changes occur. The session case manually seeds a fake session, then checks persistent cookies and localStorage after browser restart without logging in again.
38
+
39
+ One measured trial per case. Individual failures during development led to fixes for table row extraction, downloads, popup timing, schema correction and the demo cookie's expiry; these results describe the final trial, not all development attempts or a general success rate. The live JSON reports remain the source of truth. Execution repair counts do not include provider schema-correction calls; those calls are included in total calls/tokens.
40
+
41
+ Costs use configured peak rates ($0.30/M uncached input, $0.006/M cached input, $1.20/M output), verified against the [provider pricing page](https://api-docs.deepseek.com/quick_start/pricing/) on 2026-09-18. These are conservative estimates, not billing receipts; off-peak charges can be lower. Context reduction varies by site. Decorative CSS intentionally enlarged the original local/static fixtures used for the earlier measurements above; the redesigned public lab now uses shared styling. No screenshot-agent baseline, benchmark savings percentage or universal success rate was measured.
42
+
43
+ ## Complex styled workflows and real-world research
44
+
45
+ The new lab has six complex browser-only practice cases. Three use separate HTML
46
+ documents: product details/comparison, journey results/itinerary, invoice details.
47
+ Local execution tests supply validated action plans, check independent data/state/
48
+ download oracles, and repeat all six without a provider. This validates execution
49
+ and reuse, not model planning.
50
+
51
+ Real Flash trials are in [the complex report](../artifacts/benchmark-complex-live.json)
52
+ and the dated subset reports beside it. Outcomes vary across trials; failures from
53
+ strict schema validation, guessed controls, intermediate criteria and budget
54
+ limits remain recorded. Do not substitute an earlier pass for a later failure.
55
+ All listed cases have independent correctness checks; a runtime completion alone
56
+ does not establish correctness.
57
+
58
+ [Real-world trials](../artifacts/benchmark-real-world.json) run the full sourced
59
+ GitHub and GOV.UK goals without supplied plans. GOV.UK completed and repeated
60
+ without a provider. The GitHub audit remained unsuccessful in the recorded trial,
61
+ including a repeated extraction loop. Other researched website goals are source
62
+ checks, not completed-agent evidence. See [the examples guide](USEFUL_EXAMPLES.md).
63
+
64
+ Reproduce with npm run benchmark -- --live and npm run benchmark:public. Both opt into API spend. Public selection: npm run benchmark:public -- --only=travel. Reports: [public](../artifacts/benchmark-public.json), [local](../artifacts/benchmark-live.json), [earlier demo measurements](../artifacts/demo-measurements.json).
@@ -0,0 +1,93 @@
1
+ # Implementation notes
2
+
3
+ The eight MVP milestones are implemented: browser runtime, Flash integration,
4
+ verification/repair, metrics/diffs, workflow/replay, CLI, local UI, and validation.
5
+ The workspace and repository retain the name FreeComputerUse.
6
+
7
+ ## Runtime decisions
8
+
9
+ The model produces strictly validated JSON actions, never code. The runtime owns
10
+ selectors, local variables, browser state, permission gates and final verification.
11
+ Known narrow tasks use local strategies; compatible learned tasks reuse semantic
12
+ actions. New page content needs another batch; ordinary clicks do not.
13
+
14
+ `Agent` asks permission for each new origin. The exported low-level `Browser`
15
+ blocks network requests by default; library callers must pass `allowedOrigins`
16
+ or explicitly choose `allowExternal`. Chromium DevTools Protocol interception
17
+ attaches to each page target before its first navigation and checks redirect
18
+ hops. Redirected documents use the same approval callback. A synthetic local
19
+ test on Chrome 154 confirms the first fast redirect from a new popup is checked
20
+ before the target server receives it. Browser HTTP(S) and WebSocket traffic also
21
+ uses a loopback-only proxy, which connects to the vetted address it resolved;
22
+ synthetic DNS-rebinding and plain WebSocket tests pass on system Chrome 154.
23
+ Chrome-originated approved WSS returns a frame through the proxy, while an
24
+ unapproved WSS origin is blocked before the target receives a TCP connection.
25
+ The test ignores errors from its generated local certificate. A separate
26
+ opt-in WSS smoke on 24 September 2026 connected to Postman Echo with Chrome's
27
+ normal TLS validation and received its fixed synthetic payload; this proves one
28
+ endpoint/runtime only. Other browser builds, network-specific NAT64 and
29
+ non-HTTP egress remain open in Phase 2.2 of `ROADMAP.md`.
30
+ Closing the active page stops its run and cancels a pending site approval. The
31
+ browser context stays open; the next task starts in a fresh tab. Closing a tab
32
+ through an action first switches the active page to the remaining tab.
33
+
34
+ Semantic references are stable for each live document and frame. Selector ranking
35
+ prefers role/name, label, placeholder, test ID, ID/name, text, CSS and observed DOM
36
+ path. Multiple matches fail for mutations. Extraction permits collections.
37
+
38
+ Plans and repairs have separate strict schemas. Repair preserves the successful
39
+ prefix and pending compatible actions. Invalid provider JSON gets at most one
40
+ schema correction, counted as another call. Execution repair, action/state loops,
41
+ navigation loops, step count and provider token admissions are bounded separately.
42
+ User-owned final criteria cannot be removed by model repair. Completion proves
43
+ those checks, not arbitrary semantic correctness; benchmark oracles also inspect
44
+ actual data and browser outcomes.
45
+
46
+ ## Data and reuse
47
+
48
+ The profile sends alias names instead of values. Runtime resolution is local;
49
+ known values are redacted from serialized prompts/traces. SQLite stores private
50
+ run metadata, plans, actions, timing, provider usage and compatible workflows.
51
+ Successful actions are converted to semantic descriptors. Matching uses exact
52
+ origin/path, normalized intent and an initial control fingerprint. Changed tasks
53
+ or incompatible structures are not assumed to be the same workflow.
54
+
55
+ Replay disables the provider even if one is configured. It stops on failure.
56
+ Site and sensitive-action approvals still apply. Persistent browser contexts retain
57
+ localStorage and unexpired persistent cookies; session-only cookies can expire on
58
+ browser shutdown according to site policy. The public lab uses synthetic persistent
59
+ cookies to validate a restart without another simulated login.
60
+
61
+ ## Progressive context and visual boundary
62
+
63
+ Observation exposes overview/controls/regions and bounded visible text/tables.
64
+ Batch transitions and repairs can use DOM diffs. Repeated failures escalate to
65
+ accessibility and a sanitized component HTML fragment. The UI preview and explicit
66
+ CLI screenshot are local. Images are not sent to the provider. Vision control,
67
+ canvas execution, multi-model routing and named external site adapters are planned.
68
+
69
+ The dashboard executes mouse movement over multiple real Playwright mouse events,
70
+ types short text progressively, and scrolls in increments. Trusted pointer telemetry
71
+ travels over the authenticated event stream; a cursor and click ring are drawn in
72
+ the dashboard, without injecting code into websites or including typed values.
73
+ Preview requests are serialized and refresh continuously while a task runs.
74
+ Cursor projection accounts for image scaling, letterboxing and iframe coordinates;
75
+ document IDs hide stale cursors on navigation. Approval guards are checked again
76
+ after movement, and pause/stop checkpoints interrupt movement and typing. Native
77
+ input types, passwords and long text retain direct entry. CLI/benchmark execution
78
+ keeps its original pace unless visual interaction is explicitly enabled.
79
+
80
+ ## Evidence
81
+
82
+ `npm test` runs actual Chromium against deterministic local pages. Real provider
83
+ measurements are stored in `artifacts/demo-measurements.json`,
84
+ `artifacts/benchmark-live.json` and `artifacts/benchmark-public.json`. Scripted
85
+ fixture-provider runs are explicitly distinguished from model performance.
86
+ Public tasks use scraping/automation sandboxes and our browser-only simulation
87
+ lab; no real people, messages, payments or account mutations are involved.
88
+ See `README.md` and `SECURITY.md` for scope, installation and security limitations.
89
+
90
+ Provider implementation, mock-test coverage, dated live evidence and unverified
91
+ routes are listed separately in the [support matrix](SUPPORT_MATRIX.md). The
92
+ DeepSeek benchmark is a historical single-trial measurement, not proof that all
93
+ OpenAI-compatible endpoints work.