stelz 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -6
- package/THIRD_PARTY_NOTICES.md +3 -1
- package/dist/cli.js +4295 -1291
- package/dist/plugin.js +92 -17
- package/dist/supervisor.js +137 -34
- package/dist/ui/assets/index-7xWId3LL.js +11 -0
- package/dist/ui/assets/index-By17r8AD.css +1 -0
- package/dist/ui/index.html +4 -3
- package/docs/README.md +24 -7
- package/docs/architecture.md +56 -5
- package/docs/bootstrap.md +195 -0
- package/docs/clients.md +5 -1
- package/docs/distribution.md +26 -17
- package/docs/onboarding-acceptance.md +79 -0
- package/docs/profile-transfer.md +89 -0
- package/docs/tests.md +76 -27
- package/docs/ui.md +31 -15
- package/examples/onboarding-fixture.html +22 -0
- package/package.json +62 -8
- package/skills/stelz-browser/SKILL.md +7 -3
- package/skills/stelz-browser/references/bootstrap.md +16 -0
- package/dist/ui/chunk-6y88c98t.css +0 -1
- package/dist/ui/chunk-jt6ajg4c.js +0 -11
- /package/dist/ui/{font-328d50b6ece9ca25.woff → assets/ibm-plex-mono-latin-400-normal-CvHOgSBP.woff} +0 -0
- /package/dist/ui/{font-08949f728dc52d52.woff2 → assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2} +0 -0
- /package/dist/ui/{font-3b646991d30055a9.woff2 → assets/ibm-plex-sans-latin-400-normal-CDDApCn2.woff2} +0 -0
- /package/dist/ui/{font-828907bfd14855c8.woff → assets/ibm-plex-sans-latin-400-normal-CYLoc0-x.woff} +0 -0
- /package/dist/ui/{font-0717336fb31fcdcd.woff2 → assets/ibm-plex-sans-latin-500-normal-6ng42L7E.woff2} +0 -0
- /package/dist/ui/{font-8d2c7b2eca91869d.woff → assets/ibm-plex-sans-latin-500-normal-BgVn5rGT.woff} +0 -0
- /package/dist/ui/{font-7861a349af1e925a.woff → assets/ibm-plex-sans-latin-600-normal-Cu4Hd6ag.woff} +0 -0
- /package/dist/ui/{font-8960851d691c054e.woff2 → assets/ibm-plex-sans-latin-600-normal-CuJfVYMP.woff2} +0 -0
- /package/dist/ui/{theme-j8bgvgsv.js → theme-fqsa3r76.js} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@font-face{font-family:IBM Plex Sans;font-style:normal;font-display:swap;font-weight:400;src:url(./ibm-plex-sans-latin-400-normal-CDDApCn2.woff2)format("woff2"),url(./ibm-plex-sans-latin-400-normal-CYLoc0-x.woff)format("woff")}@font-face{font-family:IBM Plex Sans;font-style:normal;font-display:swap;font-weight:500;src:url(./ibm-plex-sans-latin-500-normal-6ng42L7E.woff2)format("woff2"),url(./ibm-plex-sans-latin-500-normal-BgVn5rGT.woff)format("woff")}@font-face{font-family:IBM Plex Sans;font-style:normal;font-display:swap;font-weight:600;src:url(./ibm-plex-sans-latin-600-normal-CuJfVYMP.woff2)format("woff2"),url(./ibm-plex-sans-latin-600-normal-Cu4Hd6ag.woff)format("woff")}@font-face{font-family:IBM Plex Mono;font-style:normal;font-display:swap;font-weight:400;src:url(./ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2)format("woff2"),url(./ibm-plex-mono-latin-400-normal-CvHOgSBP.woff)format("woff")}:root{--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light;--ground:#f6f6f6;--surface:#fff;--raised:#fafafa;--hover:#f3f3f3;--active:#ebebeb;--border:#e9e9e9;--rule:#efefef;--control:#d5d5d5;--control-hover:#bcbcbc;--text:#191919;--muted:#616161;--faint:#707070;--accent:#2f70bb;--positive:#16804a;--warning:#8a5c0a;--warning-ground:#fffbef;--warning-border:#ebddb9;--danger:#b52f35;--danger-ground:#fff5f4;--danger-border:#edd3d3;--danger-hover:#98272c;--danger-active:#7d1e22;--on-danger:#fff;--primary-hover:#363636;--primary-active:#060606;--selection:#dce9f7;--idle:#aaa;--modal-backdrop:#19191955;--modal-shadow:0 16px 64px #0002;--font:"IBM Plex Sans", sans-serif;--mono:"IBM Plex Mono", monospace;--gap:24px;--radius-panel:12px;--radius-control:6px;font-family:var(--font);background:var(--ground);color:var(--text);font-synthesis:none;text-rendering:optimizelegibility;-webkit-font-smoothing:antialiased;scrollbar-color:var(--control) var(--surface);font-size:14px;font-weight:400;line-height:1.5}:root[data-theme=dark]{--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark;--ground:#111112;--surface:#18181a;--raised:#202022;--hover:#252528;--active:#2d2d31;--border:#303034;--rule:#29292d;--control:#505057;--control-hover:#777780;--text:#ededee;--muted:#b5b5bd;--faint:#a0a0aa;--accent:#82b6f4;--positive:#55bd88;--warning:#e6b86b;--warning-ground:#2b2418;--warning-border:#63502d;--danger-ground:#301e22;--danger-border:#68414a;--danger-hover:#c83b49;--primary-hover:#fff;--primary-active:#d7d7db;--selection:#264f77;--idle:#85858e;--modal-backdrop:#0009;--modal-shadow:0 16px 64px #0008}*{box-sizing:border-box}body{min-width:320px;margin:0}button,input,select,textarea{font:inherit}button{color:inherit;cursor:pointer}button:disabled{cursor:not-allowed}a{color:inherit}button,a,input,select,[tabindex]{-webkit-tap-highlight-color:transparent}:focus-visible{outline:2px solid var(--accent);outline-offset:3px}::selection{background:var(--selection);color:var(--text)}h1,h2,h3,h4,p{margin:0}h1,h2,h3,h4,strong{font-weight:500}h2{font-size:16px;line-height:24px}h3{font-size:14px;line-height:22px}h4{font-size:14px}code,pre,.mono{font-family:var(--mono);font-size:12px;font-weight:400}code{overflow-wrap:anywhere}[hidden]{display:none!important}.muted{color:var(--faint)}.sr-only{clip:rect(0,0,0,0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.icon{vertical-align:middle;flex:none}.initial-loading{color:var(--muted);padding:24px}.skip-link{z-index:10;background:var(--text);color:var(--surface);border-radius:var(--radius-control);padding:8px 16px;position:fixed;top:-60px;left:16px}.skip-link:focus{top:8px}.app-shell{min-height:100dvh;padding:0 8px 8px}.topbar{justify-content:space-between;align-items:center;gap:24px;height:56px;padding:0 20px;display:flex}.topbar-navigation{align-items:center;gap:32px;min-width:0;display:flex}.brand{letter-spacing:-.02em;flex:none;align-items:center;gap:8px;font-size:16px;font-weight:500;display:flex}.brand-mark{color:var(--text);flex:none}.desktop-navigation nav{align-items:center;gap:4px;display:flex}.nav-item{text-align:left;border-radius:var(--radius-control);min-height:34px;color:var(--muted);white-space:nowrap;background:0 0;border:0;align-items:center;gap:8px;padding:6px 12px;display:flex}.nav-item:hover,.nav-item.is-active{color:var(--text);background:var(--active)}.menu-toggle{display:none!important}.workspace{border:1px solid var(--border);background:var(--surface);border-radius:16px;min-width:0;min-height:calc(100dvh - 64px)}.main-content{width:min(100%,800px);min-width:0;margin:0 auto;padding:40px 32px 32px}.main-content:focus{outline:none}.page-heading{justify-content:space-between;align-items:center;gap:24px;min-height:36px;margin-bottom:28px;display:flex}.page-heading-title{flex:1;align-items:center;gap:8px;min-width:0;display:flex}.page-heading:has(.profile-name-editor){align-items:flex-start}.profile-name-editor{flex:1;min-width:0}.profile-name-editor-row{align-items:center;gap:4px;display:flex}.profile-name-editor-row input{flex:1;min-width:0;min-height:34px;padding:4px 8px;font-size:18px;line-height:24px}.profile-name-editor .field-help{margin-top:4px}.profile-name-editor .notice{margin-bottom:0}.page-heading h1{letter-spacing:-.025em;white-space:nowrap;align-items:center;gap:10px;min-width:0;font-size:24px;font-weight:500;line-height:32px;display:flex}.page-heading h1>span{text-overflow:ellipsis;overflow:hidden}.page-heading h1:focus{outline:none}.status-dot{background:var(--idle);border-radius:50%;flex:none;width:6px;height:6px;display:inline-block}.button,.icon-button,.text-button{border:1px solid var(--control);border-radius:var(--radius-control);background:var(--surface);min-height:34px;color:var(--text);white-space:nowrap;justify-content:center;align-items:center;gap:7px;padding:5px 12px;line-height:22px;text-decoration:none;transition:border-color .12s;display:inline-flex}.button:not(:disabled):hover,.icon-button:not(:disabled):hover{border-color:var(--control-hover);background:var(--hover)}.button:not(:disabled):active,.icon-button:not(:disabled):active{background:var(--active)}.button:disabled,.icon-button:disabled{background:var(--raised);color:var(--faint);border-color:var(--border)}.button-primary{background:var(--text);border-color:var(--text);color:var(--surface);font-weight:500}.button-primary:not(:disabled):hover{background:var(--primary-hover);color:var(--surface);border-color:var(--primary-hover)}.button-primary:not(:disabled):active{background:var(--primary-active);border-color:var(--primary-active)}.button-danger{background:var(--danger);border-color:var(--danger);color:var(--on-danger);font-weight:500}.button-danger:not(:disabled):hover{background:var(--danger-hover);color:var(--on-danger);border-color:var(--danger-hover)}.button-danger:not(:disabled):active{background:var(--danger-active);border-color:var(--danger-active)}.icon-button{width:34px;color:var(--muted);background:0 0;border-color:#0000;flex:none;padding:4px}.ui-power-button{flex:none}.text-button{min-height:28px;color:var(--text);background:0 0;border-color:#0000;padding:0}.text-button:not(:disabled):hover{text-underline-offset:3px;text-decoration:underline}.text-button:disabled{color:var(--faint)}.button-row{align-items:center;gap:8px;display:flex}.notice{border:1px solid var(--border);border-radius:var(--radius-control);background:var(--raised);color:var(--muted);overflow-wrap:anywhere;justify-content:space-between;align-items:center;gap:16px;margin:16px 0;padding:12px 16px;display:flex}.notice-warning{border-color:var(--warning-border);background:var(--warning-ground);color:var(--text)}.notice-error{border-color:var(--danger-border);background:var(--danger-ground);color:var(--text)}.notice .text-button{flex:none}.notice .command-wrap{min-width:150px}.create-options{margin-top:24px}.create-options summary{cursor:pointer;color:var(--muted)}.profile-name{max-width:100%;color:var(--text);text-align:left;overflow-wrap:anywhere;background:0 0;border:0;align-items:center;gap:9px;padding:0;font-size:14px;line-height:22px;display:inline-flex}.profile-name>span{min-width:0}.profile-mark{flex:none;width:26px;height:26px}.profile-mark text{letter-spacing:0;font-size:9px;font-weight:500}.profile-name:hover{text-underline-offset:4px;text-decoration:underline}.cell-secondary{color:var(--faint);margin-top:3px;font-size:12px;line-height:18px;display:block}.phase{white-space:nowrap;color:var(--muted);align-items:center;gap:7px;font-size:14px;display:inline-flex}.phase-ready{color:var(--text)}.phase-ready .status-dot{background:var(--positive)}.phase-attention .status-dot{background:var(--warning)}.inline-attention{color:var(--warning)}.row-actions .button-row{flex-wrap:nowrap;justify-content:flex-end;gap:4px}.row-actions .button-row>*{flex-shrink:0}.show-window-button{color:var(--muted)}.action-with-reason{flex-direction:column;align-items:flex-start;gap:6px;min-width:0;display:flex}.action-with-reason.compact{display:inline-flex}.section-heading{flex-wrap:wrap;justify-content:space-between;align-items:center;gap:8px 16px;margin-bottom:12px;display:flex}.section-heading .muted{font-size:12px}.detail-view,.page-content{min-width:0}.detail-context{justify-content:space-between;align-items:center;gap:16px;min-height:40px;margin-bottom:16px;display:flex}.detail-context-right{flex-wrap:wrap;justify-content:flex-end;align-items:center;gap:16px;display:flex}.delete-profile{color:var(--muted);font-size:12px}.tabs{border-bottom:1px solid var(--border);align-items:stretch;gap:24px;display:flex;overflow-x:auto}.tabs button{min-height:40px;color:var(--muted);white-space:nowrap;background:0 0;border:0;border-bottom:2px solid #0000;flex:none;align-items:center;gap:6px;padding:8px 0;display:flex}.tabs button[aria-selected=true]{color:var(--text);border-bottom-color:var(--text)}.tabs button:hover{color:var(--text)}.tabs button:focus-visible{outline-offset:-3px}.dirty-dot{background:var(--warning);border-radius:50%;width:5px;height:5px}.tab-panel{padding-top:24px}.tab-panel:focus-visible{outline-offset:6px;border-radius:var(--radius-control)}.detail-view .notice{margin:16px 0}.lifecycle-toolbar{flex-wrap:wrap;align-items:center;gap:8px;margin-bottom:24px;display:flex}.unavailable-actions{margin:-8px 0 24px}.detail-section{border-top:1px solid var(--border);min-width:0;margin-top:28px;padding-top:24px}.detail-section>h2{margin-bottom:12px}.profile-windows h2{align-items:center;gap:10px;display:flex}.window-count,.window-state,.window-page-active{color:var(--muted);font-size:12px;font-weight:400}.browser-window+.browser-window{margin-top:16px}.browser-window-heading{border-bottom:1px solid var(--rule);justify-content:space-between;align-items:center;gap:16px;padding:8px 0;display:flex}.window-state{margin-left:12px}.window-pages{margin:0;padding:0;list-style:none}.window-page{border:0;border-bottom:1px solid var(--rule);width:100%;min-height:60px;color:var(--text);text-align:left;background:0 0;align-items:center;gap:12px;padding:10px 8px;display:flex}.window-page:not(:disabled):hover{background:var(--hover)}.window-page:not(:disabled):active{background:var(--active)}.window-page:disabled{color:var(--muted)}.window-page>.icon{color:var(--muted);flex:none}.window-page-copy{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.window-page-copy>*{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.window-page-copy small{color:var(--muted);font-size:12px}.window-page-active{flex:none}.window-control-note{margin-top:16px}.key-values{min-width:0;margin:0}.key-value{grid-template-columns:minmax(110px,36%) minmax(0,1fr);gap:12px;min-height:32px;padding:6px 0;display:grid}.key-value dt{color:var(--muted)}.key-value dd{overflow-wrap:anywhere;font-variant-numeric:tabular-nums;margin:0;font-size:14px}.key-value dd.mono{font-size:12px}.field-help{color:var(--faint);margin-top:8px;font-size:12px;line-height:19px}.field-help:empty{display:none}.command-wrap{min-width:0}.command{border:1px solid var(--control);border-radius:var(--radius-control);background:var(--surface);align-items:center;min-width:0;display:flex}.command code{white-space:pre-wrap;overflow-wrap:anywhere;-webkit-user-select:text;user-select:text;flex:1;min-width:0;padding:10px 12px;display:block}.command .icon-button{border:0;border-left:1px solid var(--control);border-radius:0 5px 5px 0;align-self:stretch;width:38px;height:auto;min-height:38px}.copy-status{color:var(--faint);margin-top:5px;font-size:12px;display:block}.copy-status:empty{display:none}.recovery-commands{margin:0 0 24px}.recovery-commands .field-help{margin:12px 0 8px}.network-form{max-width:100%}.form-field{margin-top:24px}.form-field label{flex-wrap:wrap;align-items:baseline;gap:8px;margin-bottom:8px;font-size:14px;font-weight:500;display:flex}.label-note{color:var(--faint);font-size:12px;font-weight:400}input,select{border:1px solid var(--control);border-radius:var(--radius-control);background:var(--surface);width:100%;min-height:40px;color:var(--text);caret-color:var(--text);padding:8px 12px;display:block}input::placeholder{color:var(--faint);opacity:1}input:disabled,select:disabled{color:var(--faint);background:var(--raised);border-color:var(--border);cursor:not-allowed;opacity:1}.select-control{min-width:0;position:relative}.select-control select{appearance:none;padding-inline-end:40px}.select-control>.icon{inset-inline-end:12px;color:var(--muted);pointer-events:none;position:absolute;top:50%;transform:translateY(-50%)}.select-control select:disabled+.icon{color:var(--faint)}.form-field .select-control{max-width:320px}.form-actions{justify-content:space-between;align-items:center;gap:16px;margin-top:16px;display:flex}.form-actions .field-help{margin:0}.form-actions .button-row{flex:none;margin-left:auto}.log-section{margin-top:24px}.log-section h3{margin-bottom:8px}.log-output{background:var(--raised);border:1px solid var(--border);border-radius:var(--radius-control);white-space:pre-wrap;overflow-wrap:anywhere;min-height:80px;max-height:400px;color:var(--muted);tab-size:2;margin:0;padding:16px;line-height:20px;overflow:auto}.page-content .notice{margin:16px 0}.diagnostic-profiles{gap:var(--gap);grid-template-columns:repeat(2,minmax(0,1fr));display:grid}.diagnostic-profile{min-width:0;padding-top:8px}.diagnostic-profile .command-wrap{margin-top:16px}.settings-section{border-top:1px solid var(--border);grid-template-columns:160px minmax(0,1fr);gap:32px;margin-top:28px;padding-top:28px;display:grid}.mcp-list{gap:20px;display:grid}.mcp-list h3{margin-bottom:8px}.first-run{background:var(--raised);border-radius:var(--radius-panel);margin:24px 0;padding:24px}.first-run>p{color:var(--muted);margin:8px 0 16px}.first-run .command-wrap{margin-top:12px}.empty-inline,.loading-block{color:var(--muted);padding:24px 0}.empty-inline .button{margin-top:12px}.loading-text{color:var(--faint);padding:16px 0}.loading-console{padding:12px 0}.loading-labels{color:var(--faint);grid-template-columns:2fr 1fr 1fr;padding:12px 0;display:grid}.loading-row{background:var(--raised);border-bottom:1px solid var(--surface);height:60px}.loading-console p{color:var(--faint);margin-top:16px}.modal{width:min(520px,100% - 32px);max-height:calc(100dvh - 32px);color:var(--text);background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-panel);box-shadow:var(--modal-shadow);padding:0;overflow:auto}.modal::backdrop{background:var(--modal-backdrop)}.modal-heading{border-bottom:1px solid var(--border);justify-content:space-between;align-items:center;gap:16px;padding:16px 20px;display:flex}.modal-heading h2{overflow-wrap:anywhere;min-width:0;font-size:16px}.modal-body{overflow-wrap:anywhere;min-width:0;padding:20px}.modal-body p{color:var(--muted)}.modal-body .notice{margin:16px 0 0}.modal-body .muted{margin-top:16px}.modal-actions{border-top:1px solid var(--border);flex-wrap:wrap;justify-content:flex-end;gap:8px;padding:16px 20px;display:flex}.navigation-modal nav{gap:4px;padding:16px;display:grid}.navigation-modal .field-help{margin:0 20px 24px}.ui-ended{background:var(--surface);place-items:center;min-height:100dvh;padding:32px 20px;display:grid}.ui-ended-content{width:min(100%,480px)}.ui-ended-content h1{letter-spacing:-.025em;margin:20px 0 12px;font-size:24px;line-height:32px}.ui-ended-content p{color:var(--muted);margin:8px 0}.ui-ended-content .command-wrap{margin-top:20px}.page-heading-actions{flex:none;align-items:center;gap:8px;display:flex}.profile-table-wrap{width:calc(100% + 32px);min-width:0;margin-inline:-16px}.profile-table{border-collapse:collapse;table-layout:fixed;text-align:left;width:100%}.profile-table th,.profile-table td{text-align:left;vertical-align:middle;overflow-wrap:anywhere;padding:16px 10px;font-weight:400}.profile-table th:first-child,.profile-table td:first-child{padding-left:16px}.profile-table th:last-child,.profile-table td:last-child{padding-right:16px}.profile-table thead th{color:var(--faint);border-bottom:1px solid var(--border);padding-top:0;padding-bottom:12px;font-size:12px}.profile-table thead th:first-child{width:32%}.profile-table thead th:nth-child(2){width:28%}.profile-table thead th:nth-child(4){width:144px}.profile-table tbody tr{border-bottom:1px solid var(--rule)}.profile-row{cursor:pointer}.profile-row:hover,.profile-row:focus-within{background:var(--raised)}.profile-issue{-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.profile-table .row-actions{text-align:right}.profile-connection{color:var(--muted)}.disclosure{margin-top:24px}.disclosure>summary{cursor:pointer;color:var(--muted);width:fit-content}.disclosure[open]>summary{color:var(--text);margin-bottom:16px}.disclosure>summary .label-note{margin-left:8px}.network-form>.form-field:first-child,.profile-create-fields>.form-field:first-child{margin-top:0}.network-fields{grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:20px 16px;display:grid}.network-fields .form-field,.typing-section .form-field{margin-top:0}.network-section{margin-top:20px;padding-top:20px}.settings-section:first-child{border:0;margin-top:0;padding-top:0}.log-tools{justify-content:flex-end;display:flex}.theme-select{max-width:240px}.check-label{cursor:pointer;align-items:center;gap:8px;min-height:34px;display:inline-flex}:is(.check-label:has(input:disabled),.profile-export-check:has(input:disabled)){cursor:not-allowed;color:var(--faint)}.check-label input[type=checkbox],.profile-export-check input{width:16px;height:16px;min-height:16px;accent-color:var(--text);flex:none;margin:0;padding:0;display:inline-block}.export-selection{flex-wrap:wrap;justify-content:space-between;align-items:center;gap:8px 16px;margin-bottom:16px;display:flex}.export-selection .button-row{gap:16px;margin-left:auto}.profile-export-check{cursor:pointer;justify-content:center;align-items:center;min-height:34px;display:flex}.profile-table.has-selection thead th:first-child{width:40px}.profile-table.has-selection thead th:nth-child(2){width:30%}.profile-table.has-selection thead th:nth-child(3){width:26%}.profile-table.has-selection thead th:nth-child(4){width:auto}.profile-table.has-selection thead th:nth-child(5){width:144px}.profile-table.has-selection .profile-select-cell{padding-inline:10px}.profile-export-shortcut{color:var(--muted);font-size:12px}.transfer-modal{width:min(600px,100% - 32px);overflow:hidden}.transfer-modal[open]{flex-direction:column;display:flex}.transfer-modal>.modal-heading,.transfer-modal>.modal-actions{flex:none}.transfer-modal .button[aria-disabled=true]{background:var(--raised);color:var(--faint);border-color:var(--border);cursor:not-allowed}.transfer-intro{flex:none;padding-top:12px;padding-bottom:0}.transfer-intro .field-help{margin:0}.transfer-status{padding-top:16px;overflow:auto}.transfer-filename{white-space:nowrap;text-overflow:ellipsis;font-size:12px;overflow:hidden}.transfer-status .transfer-phase{color:var(--text);margin-top:8px}.transfer-status .transfer-phase:first-child{margin-top:0}.transfer-progress{appearance:none;width:100%;height:6px;color:var(--text);background:var(--rule);border:0;border-radius:3px;margin-top:16px;display:block;overflow:hidden}.transfer-progress::-webkit-progress-bar{background:var(--rule)}.transfer-progress::-webkit-progress-value{background:var(--text);border-radius:3px}.transfer-progress::-moz-progress-bar{background:var(--text);border-radius:3px}.transfer-counts{font-variant-numeric:tabular-nums}.transfer-preview{flex-direction:column;min-height:0;display:flex;overflow:hidden}.transfer-preview-body{min-height:0;padding-top:12px;overflow:auto}.transfer-preview-actions{flex:none;align-items:center}.transfer-preview-actions>.field-help{font-variant-numeric:tabular-nums;margin:0 auto 0 0}.transfer-selection{justify-content:space-between;align-items:center;gap:16px;margin-bottom:8px;display:flex}.transfer-selection>.field-help{margin:0}.transfer-profile-list{border-top:1px solid var(--rule)}.transfer-profile{border-bottom:1px solid var(--rule);min-width:0;padding:14px 0}.transfer-profile-title{gap:10px;width:100%}.transfer-profile-title>span{overflow-wrap:anywhere;min-width:0}.transfer-profile-title .profile-mark{width:24px;height:24px}.transfer-profile-title .cell-secondary{margin-top:1px}.transfer-profile-meta{color:var(--muted);flex-wrap:wrap;gap:2px 12px;margin:6px 0 12px 26px;font-size:12px;display:flex}.transfer-fields{border:0;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:12px;min-width:0;margin:0 0 0 26px;padding:0;display:grid}.transfer-fields .form-field{min-width:0;margin:0}.transfer-fields label{color:var(--muted);margin-bottom:4px;font-size:12px;font-weight:400}.transfer-fields input{min-height:34px;padding:5px 8px}.transfer-fields input[aria-invalid=true]{border-color:var(--warning)}.transfer-profile>.field-help,.transfer-profile>.transfer-issues{margin:8px 0 0 26px}.transfer-profile .inline-attention{color:var(--warning)}.transfer-issues{margin:0;padding:0;font-size:12px;list-style:none}.transfer-issues li+li{margin-top:4px}.transfer-preview-body>.notice:first-child{margin-top:0;margin-bottom:12px}.transfer-results{gap:12px;margin:16px 0 0;padding:0;list-style:none;display:grid}.transfer-results li{align-items:center;gap:10px;display:flex}.transfer-results li>span{min-width:0}@media (width<=900px){.topbar{gap:16px;padding:0 12px}.topbar-navigation{gap:20px}.main-content{padding-top:36px}.row-actions .button{padding-left:8px;padding-right:8px}.settings-section{grid-template-columns:160px minmax(0,1fr);gap:24px}}@media (width<=640px){.app-shell{padding:0}.topbar{height:56px;padding:0 16px}.topbar-navigation{gap:12px}.brand{font-size:16px}.brand-mark{width:18px}.desktop-navigation{display:none}.menu-toggle{order:-1;margin-left:-8px;display:inline-flex!important}.workspace{border:0;border-top:1px solid var(--border);border-radius:0;min-height:calc(100dvh - 56px)}.main-content{padding:24px 20px}.page-heading{gap:16px}.page-heading h1{font-size:24px}.page-heading-profiles{flex-wrap:wrap}.page-heading-profiles .page-heading-title{flex-basis:100%}.page-heading-profiles .page-heading-actions{margin-left:auto}.button,.icon-button,.text-button{min-height:44px}.icon-button{width:44px}.profile-name-editor-row input{min-height:44px}.button{padding-left:12px;padding-right:12px}.ui-power-button{flex:none}.notice{flex-direction:column;align-items:flex-start;gap:8px;padding:12px}.notice .command-wrap{width:100%}.cell-secondary{margin-top:3px}.detail-context{align-items:flex-start;gap:12px;margin-bottom:12px}.detail-context-right{gap:4px 12px}.detail-context-right .delete-profile{min-height:44px}.tabs{gap:24px}.tabs button{min-height:44px;font-size:14px}.tab-panel{padding-top:20px}.key-value{grid-template-columns:minmax(100px,38%) minmax(0,1fr);gap:12px}.form-field .select-control{max-width:none}.network-fields{grid-template-columns:minmax(0,1fr);gap:20px}.form-actions{flex-direction:column;align-items:flex-start}.form-actions .button-row{flex-wrap:wrap;justify-content:flex-end;width:100%}.command code{padding:10px;font-size:12px}.command .icon-button{width:44px;min-height:44px}.settings-section{grid-template-columns:minmax(0,1fr);gap:16px}.diagnostic-profiles{grid-template-columns:minmax(0,1fr)}.disclosure{margin-top:12px}.disclosure>summary,.create-options>summary{min-height:44px;padding:10px 0}.first-run{padding:20px 16px}.modal-heading{padding:12px 16px}.modal-body{padding:16px}.modal-actions{padding:12px 16px}.check-label,.profile-export-check{min-height:44px}.transfer-intro{padding-top:12px;padding-bottom:0}.transfer-fields{grid-template-columns:minmax(0,1fr);gap:10px}.transfer-fields input{min-height:40px}.transfer-preview-actions{gap:8px}.navigation-modal{border:0;border-radius:0;width:100%;max-width:none;height:100dvh;max-height:100dvh;margin:0}.navigation-modal .nav-item{min-height:48px;font-size:14px}}@media (prefers-reduced-motion:reduce){*,:before,:after{scroll-behavior:auto!important;transition:none!important}}@media (width<=640px){.profile-table,.profile-table tbody{display:block}.profile-table thead{clip:rect(0,0,0,0);white-space:nowrap;width:1px;height:1px;margin:-1px;position:absolute;overflow:hidden}.profile-table tbody tr{grid-template-columns:minmax(0,1fr) auto;gap:4px 12px;padding:16px;display:grid}.profile-table th,.profile-table td,.profile-table th:first-child,.profile-table td:last-child{min-width:0;padding:0}.profile-table th[scope=row]{grid-area:1/1}.profile-name{min-height:44px}.profile-table .browser-phase{flex-wrap:wrap;grid-area:2/1;align-items:baseline;gap:2px 8px;display:flex}.profile-table .browser-phase .cell-secondary{margin:0}.profile-table .profile-connection{grid-area:3/1;font-size:12px}.profile-table .row-actions{grid-area:1/2/4;align-self:center}.page-heading{gap:12px;margin-bottom:24px}.page-heading-actions{gap:4px}.profile-table.has-selection tbody tr{grid-template-columns:28px minmax(0,1fr) auto}.profile-table.has-selection .profile-select-cell{grid-area:1/1/4;align-self:center;padding:0}.profile-table.has-selection th[scope=row],.profile-table.has-selection .browser-phase,.profile-table.has-selection .profile-connection{grid-column:2}.profile-table.has-selection .row-actions{grid-column:3}}
|
package/dist/ui/index.html
CHANGED
|
@@ -5,9 +5,10 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
6
|
<meta name="color-scheme" content="light dark" />
|
|
7
7
|
<meta name="referrer" content="no-referrer" />
|
|
8
|
-
<title>stelz · Local service</title><script src="./theme-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
<title>stelz · Local service</title><script src="./theme-fqsa3r76.js"></script>
|
|
9
|
+
<script type="module" crossorigin src="./assets/index-7xWId3LL.js"></script>
|
|
10
|
+
<link rel="stylesheet" crossorigin href="./assets/index-By17r8AD.css">
|
|
11
|
+
</head>
|
|
11
12
|
<body>
|
|
12
13
|
<div id="root"><p class="initial-loading">Connecting to stelz…</p></div>
|
|
13
14
|
<noscript>Enable JavaScript to use the local stelz console. Browser lifetimes are controlled by the service.</noscript>
|
package/docs/README.md
CHANGED
|
@@ -11,25 +11,28 @@ A profile has a stable browser ID. A controller is one MCP client with exclusive
|
|
|
11
11
|
|
|
12
12
|
## Install
|
|
13
13
|
|
|
14
|
+
For installation through a local coding agent, use [Bootstrap](bootstrap.md).
|
|
15
|
+
|
|
14
16
|
1. Run `npm install --global stelz`.
|
|
15
17
|
2. Run `stelz init`.
|
|
16
18
|
3. Run `stelz setup`.
|
|
17
19
|
4. Run `stelz ui --open`.
|
|
18
20
|
5. Create a profile. Configure a proxy if necessary, then start it.
|
|
19
21
|
|
|
20
|
-
For a release candidate, install its archive with `npm install --global ./stelz-0.2.
|
|
22
|
+
For a release candidate, install its archive with `npm install --global ./stelz-0.2.1.tgz`.
|
|
21
23
|
|
|
22
24
|
The release archive contains the prepared Camofox and camoufox-js dependencies.
|
|
23
25
|
Setup copies them into the service directory and checks the prepared source without rewriting it.
|
|
24
26
|
Setup does not clone a repository or apply patches.
|
|
25
27
|
Setup does not change the installed Camoufox app.
|
|
26
28
|
Stop all profiles before setup after a code update.
|
|
29
|
+
Start refuses an outdated browser plugin. Run `stelz setup` to install the current package's plugin before starting a new browser.
|
|
27
30
|
Setup stages and checks the complete runtime before it replaces the active runtime.
|
|
28
31
|
See [Camofox adapter patches](camofox-patches.md) for the eight pinned compatibility changes.
|
|
29
32
|
|
|
30
33
|
For a source installation, run `bun install --frozen-lockfile --ignore-scripts` and `bun run build` at the workspace root.
|
|
31
|
-
Run `bun run pack` to
|
|
32
|
-
|
|
34
|
+
Run `bun run pack` to save the release archive in `release-artifacts/`.
|
|
35
|
+
The root package includes the compiled service and bundled UI.
|
|
33
36
|
See [Distribution](distribution.md) for archive verification and the manual workflow.
|
|
34
37
|
|
|
35
38
|
The default service directory is `~/.local/share/stelz`.
|
|
@@ -40,12 +43,16 @@ The global CLI ignores automatic project `.env` files.
|
|
|
40
43
|
## Configuration
|
|
41
44
|
|
|
42
45
|
`profiles.json` contains a `profiles` array.
|
|
43
|
-
Each profile specifies its ID, loopback port,
|
|
46
|
+
Each profile specifies its ID, loopback port, and storage mode.
|
|
47
|
+
A profile uses its optional proxy reference to select the network route.
|
|
44
48
|
See [profiles.json](../examples/profiles.json) for an empty configuration.
|
|
45
49
|
`secrets.env` contains proxy credentials. Keep this file private.
|
|
46
50
|
|
|
47
51
|
Init creates an empty profile list. It never overwrites existing entries.
|
|
48
52
|
Use **New profile** in the UI to create a named profile with an optional proxy.
|
|
53
|
+
Agents can use `stelz profile create work --json`.
|
|
54
|
+
This command reuses a compatible profile without rewriting it. Conflicting network settings fail without changing the profile.
|
|
55
|
+
See [Bootstrap](bootstrap.md#3-initialize-and-create-or-reuse-the-profile) for proxy and expected-IP inputs.
|
|
49
56
|
The service assigns a free loopback port. New profiles use `storage: "native"`.
|
|
50
57
|
A profile uses a direct connection unless you supply a proxy.
|
|
51
58
|
There is no saved-profile count limit or global active-browser limit.
|
|
@@ -53,8 +60,8 @@ Each profile has at most one browser instance. That browser can have multiple wi
|
|
|
53
60
|
Available memory, disk, and loopback ports constrain practical capacity. The service does not impose a CPU budget.
|
|
54
61
|
Catalogs and their transaction journals have no fixed byte ceiling. Secret files, state files, and HTTP requests retain their size protections.
|
|
55
62
|
Existing entries without a `storage` field keep `checkpoint` mode. Init never overwrites them.
|
|
56
|
-
|
|
57
|
-
For manual proxy configuration on a new profile, set `
|
|
63
|
+
Enter a proxy URL in Overview to configure a proxy for a stopped profile. Clear the field to remove it.
|
|
64
|
+
For manual proxy configuration on a new profile, set `proxyEnv: "PROFILE_01_PROXY_URL"`.
|
|
58
65
|
Set `PROFILE_01_PROXY_URL` in `secrets.env`.
|
|
59
66
|
Optionally set `expectedIPEnv: "PROFILE_01_EXPECTED_IP"` and its value in `secrets.env` to require a specific exit IP.
|
|
60
67
|
Camofox supports HTTP(S) proxy authentication and unauthenticated SOCKS5.
|
|
@@ -66,6 +73,10 @@ Only loopback hosts bypass a configured proxy. Proxied profiles disable WebRTC.
|
|
|
66
73
|
Current browser policy overrides saved device data. A legacy direct-mode pin cannot re-enable WebRTC in proxy mode.
|
|
67
74
|
Proxy policy disables direct failover and enables DNS resolution through SOCKS proxies.
|
|
68
75
|
Browser-side IP checks reject failed proxies and unexpected IP addresses.
|
|
76
|
+
Proxy profiles use the current GeoIP country's default language from Unicode CLDR.
|
|
77
|
+
This policy keeps the language stable across restarts.
|
|
78
|
+
The current country's language policy, timezone, and geolocation remain independent of saved device pins.
|
|
79
|
+
An explicit upstream locale list takes precedence over this default.
|
|
69
80
|
Checks use ipify, with Cloudflare trace as an independent fallback for unavailable or invalid responses.
|
|
70
81
|
A valid unexpected IP fails immediately. The service does not try another provider after an IP mismatch.
|
|
71
82
|
All checks run inside the selected browser through its configured route.
|
|
@@ -106,6 +117,8 @@ Existing `maxActive` values are ignored and preserved during edits and recovery.
|
|
|
106
117
|
|
|
107
118
|
Existing IDs, such as `identity-01`, remain unchanged. Keep configured secret references unchanged.
|
|
108
119
|
The `profile-01` IDs and `PROFILE_01_*` secret names in examples are suggestions for new configuration.
|
|
120
|
+
Legacy `mode` fields remain readable. New profiles infer proxy use from their optional `proxyEnv` reference.
|
|
121
|
+
A missing proxy secret blocks startup. It never enables a direct fallback.
|
|
109
122
|
|
|
110
123
|
## Typing
|
|
111
124
|
|
|
@@ -118,7 +131,7 @@ The `camofox_type` tool accepts an optional `mode` for each call:
|
|
|
118
131
|
|
|
119
132
|
The default is `auto`. Open a profile's Overview tab in the UI to change its **Default typing mode**.
|
|
120
133
|
The UI saves the profile's `typingMode` in `profiles.json`. Changes apply to future calls without a browser restart.
|
|
121
|
-
|
|
134
|
+
The UI shows one of three effective modes. Profiles without an override inherit the service setting until you choose another mode.
|
|
122
135
|
A call's explicit `mode` overrides the profile default. The override applies only to that call.
|
|
123
136
|
If the profile has no default, the service uses `STELZ_TYPING_MODE` from its environment or `secrets.env`, then `auto`.
|
|
124
137
|
The legacy service value `paced` selects `auto`. Service environment changes still require a stop and start.
|
|
@@ -135,6 +148,9 @@ If typing stops with incomplete input, read a fresh snapshot before another acti
|
|
|
135
148
|
| Command | Effect |
|
|
136
149
|
| --- | --- |
|
|
137
150
|
| `stelz ui [--port PORT] [--open]` | Serve the local profile UI. The default port is 9380. |
|
|
151
|
+
| `stelz profile create ID [--direct] [--json]` | Create a native profile or reuse a compatible profile. Run `stelz profile create --help` for network options. |
|
|
152
|
+
| `stelz profile export ID... --output FILE [--json]` | Export cleanly stopped profiles as a ZIP archive. Use `--all` instead of IDs to export the full catalog. |
|
|
153
|
+
| `stelz profile import FILE [--json]` | Import profiles from a ZIP archive. Existing IDs produce copies. |
|
|
138
154
|
| `stelz start profile-02` | Start one visible browser. |
|
|
139
155
|
| `stelz start all` | Start configured profiles sequentially. Reuse an existing safe lifetime for each profile. |
|
|
140
156
|
| `stelz status` | Read state and current controller information. |
|
|
@@ -148,6 +164,7 @@ If typing stops with incomplete input, read a fresh snapshot before another acti
|
|
|
148
164
|
| `stelz recover profile-02` | Archive an unclean lifetime after its recorded processes exit. |
|
|
149
165
|
|
|
150
166
|
See [Use the local UI](ui.md) for UI sessions, lifecycle controls, and network edits.
|
|
167
|
+
See [Import and export profiles](profile-transfer.md) for selection, compatibility, and archive limits.
|
|
151
168
|
|
|
152
169
|
A profile can have several native windows. Their title prefixes, colors, and toolbar badges identify the profile.
|
|
153
170
|
The UI can show a window without changing its controller.
|
package/docs/architecture.md
CHANGED
|
@@ -84,6 +84,25 @@ A changed executable or invalid fingerprint record blocks startup.
|
|
|
84
84
|
Saved fingerprint configuration does not guarantee identical observable output. Earlier acceptance tests recorded varying canvas hashes.
|
|
85
85
|
See [persistent state](README.md#persistent-state) for the file layout and migration restrictions.
|
|
86
86
|
|
|
87
|
+
## Profile transfers
|
|
88
|
+
|
|
89
|
+
The CLI and local UI transfer profiles through versioned ZIP archives.
|
|
90
|
+
The manifest records profile settings, source compatibility, file sizes, and SHA-256 hashes.
|
|
91
|
+
Streaming reads and writes support ZIP64 without loading browser data into memory.
|
|
92
|
+
|
|
93
|
+
Export snapshots cleanly stopped profiles under the admission lock and selected lifecycle locks, acquired in profile ID order.
|
|
94
|
+
It releases those locks before compression. Export never stops a browser automatically.
|
|
95
|
+
|
|
96
|
+
Import checks private staging data before it changes the catalog.
|
|
97
|
+
It assigns unused IDs, ports, and secret references, then installs the selected batch through a durable journal.
|
|
98
|
+
One catalog replacement publishes the complete batch. Configuration changes and explicit starts complete pending recovery first.
|
|
99
|
+
Imported profiles remain stopped. Existing profile data and secret references stay unchanged.
|
|
100
|
+
|
|
101
|
+
The UI uses background transfer jobs with its existing session and origin checks.
|
|
102
|
+
Uploads and downloads stream through separate endpoints. An active transfer prevents UI shutdown.
|
|
103
|
+
Profile transfer adds no MCP tools.
|
|
104
|
+
See [Import and export profiles](profile-transfer.md) for compatibility, content, limits, and recovery.
|
|
105
|
+
|
|
87
106
|
## MCP tool contracts
|
|
88
107
|
|
|
89
108
|
Camofox's HTTP routes and MCP tools are separate interfaces.
|
|
@@ -104,6 +123,38 @@ New browser controls must pass through the same controller, action queue, networ
|
|
|
104
123
|
An upstream HTTP endpoint alone does not establish Stelz MCP support.
|
|
105
124
|
Extensions need checks for their contract and browser behavior while preserving existing tool calls.
|
|
106
125
|
|
|
126
|
+
### Planned browser controls
|
|
127
|
+
|
|
128
|
+
Status: planned for later implementation. These controls are not currently available through Stelz MCP.
|
|
129
|
+
The inventory uses the [pinned Camofox 1.18.1 server](https://github.com/jo-inc/camofox-browser/blob/39c82094013480b373df6600d44c7f036f58356e/server.js).
|
|
130
|
+
Each addition still requires Stelz integration and browser checks. Final tool names and arguments remain undecided.
|
|
131
|
+
|
|
132
|
+
| Planned capability | Existing upstream handler |
|
|
133
|
+
| --- | --- |
|
|
134
|
+
| Double-click | `POST /act` with `kind: "click"` and `doubleClick: true`. The current MCP click route ignores this argument. |
|
|
135
|
+
| Hover | `POST /act` with `kind: "hover"`. |
|
|
136
|
+
| Keyboard keys and shortcuts | `POST /tabs/:tabId/press`. |
|
|
137
|
+
| Native dropdown selection | `POST /tabs/:tabId/select`. |
|
|
138
|
+
| File upload | `POST /tabs/:tabId/upload`, using files inside the configured upload directory. |
|
|
139
|
+
| Download retrieval | `GET /tabs/:tabId/downloads`, with optional file contents. |
|
|
140
|
+
| Save the current PDF | `POST /tabs/:tabId/fetch-current-resource`. |
|
|
141
|
+
| Back, forward, and reload | `POST /tabs/:tabId/back`, `POST /tabs/:tabId/forward`, and `POST /tabs/:tabId/refresh`. |
|
|
142
|
+
| Wait for page readiness, text, or load state | `POST /tabs/:tabId/wait` and `POST /act` with `kind: "wait"`. |
|
|
143
|
+
| Scroll an element into view | `POST /act` with `kind: "scrollIntoView"`. |
|
|
144
|
+
| Viewport resizing | `POST /tabs/:tabId/viewport`. |
|
|
145
|
+
| Read links and images | `GET /tabs/:tabId/links` and `GET /tabs/:tabId/images`. |
|
|
146
|
+
| Structured extraction from snapshot references | `POST /tabs/:tabId/extract`. |
|
|
147
|
+
| Read tab statistics and session traces | `GET /tabs/:tabId/stats` and the session trace routes. |
|
|
148
|
+
|
|
149
|
+
Right-click and drag/drop are also planned. Camofox 1.18.1 has no handlers for these actions.
|
|
150
|
+
They require server implementation and MCP support.
|
|
151
|
+
|
|
152
|
+
Reuse existing upstream handlers where available. Preserve existing tool names, arguments, and behavior when adding optional controls.
|
|
153
|
+
All additions must use the controller, action queue, network checks, and time limit described above.
|
|
154
|
+
File operations must enforce configured path boundaries, profile ownership, and transfer size limits.
|
|
155
|
+
Before release, check MCP contracts, controller isolation, pause/resume, timeout behavior, and actions in a headed browser.
|
|
156
|
+
This plan keeps JavaScript evaluation and cookie import excluded. Human authentication continues in the same browser window.
|
|
157
|
+
|
|
107
158
|
## Failure handling and network policy
|
|
108
159
|
|
|
109
160
|
The service limits browser operations to 60 seconds.
|
|
@@ -133,23 +184,23 @@ Showing a browser window preserves its controller. Human takeover still requires
|
|
|
133
184
|
Closing the UI server preserves active browsers.
|
|
134
185
|
See [UI operations](ui.md).
|
|
135
186
|
|
|
136
|
-
|
|
137
|
-
The
|
|
187
|
+
The root manifest defines the release package. `ui/` contains the bundled React application.
|
|
188
|
+
The archive includes canonical documentation and examples without build-time copies.
|
|
138
189
|
The package includes prepared Camofox and `camoufox-js` dependencies with committed compatibility patches.
|
|
139
190
|
Setup checks and stages the runtime before activation. It preserves the installed Camoufox app and existing profile data.
|
|
140
191
|
Pinned dependencies make compatibility changes reproducible and reviewable.
|
|
141
192
|
See [adapter patches](camofox-patches.md) and [distribution](distribution.md).
|
|
142
193
|
|
|
143
|
-
In the source workspace, `
|
|
194
|
+
In the source workspace, `src/` separates responsibilities by directory:
|
|
144
195
|
|
|
145
196
|
| Directory | Responsibility |
|
|
146
197
|
| --- | --- |
|
|
147
198
|
| `cli/` | Command parsing and user-facing operations. |
|
|
148
|
-
| `profiles/` | Configuration,
|
|
199
|
+
| `profiles/` | Configuration, profile archives, catalog transactions, compatibility, and secret references. |
|
|
149
200
|
| `runtime/` | Process ownership, locks, lifecycle operations, and supervision. |
|
|
150
201
|
| `mcp/` | MCP transport, tool policy, and controller ownership. |
|
|
151
202
|
| `browser/` | Camofox integration, persistent contexts, fingerprints, typing, and IP checks. |
|
|
152
|
-
| `api/` | Local UI endpoints and
|
|
203
|
+
| `api/` | Local UI endpoints, service models, and transfer jobs. |
|
|
153
204
|
|
|
154
205
|
Offline tests check contracts and state transitions. Headed acceptance tests check actual browser behavior.
|
|
155
206
|
A build or mock test alone cannot establish persistence, proxy routing, or human takeover behavior.
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# Set up Stelz from an agent
|
|
2
|
+
|
|
3
|
+
Give a local coding agent this prompt:
|
|
4
|
+
|
|
5
|
+
> Read https://github.com/souljorje/stelz/blob/main/docs/bootstrap.md. Set up Stelz, create or reuse the persistent profile `work`, and connect it to your browser tools. Preserve existing state and settings. Report each readiness state.
|
|
6
|
+
|
|
7
|
+
This procedure supports local macOS on Apple Silicon. Stelz runs without an agent or model credentials.
|
|
8
|
+
Complete the steps you can perform. Request intervention only for permissions, missing credentials, human authentication, or a required client restart.
|
|
9
|
+
Do not disable approvals, sandboxing, workspace trust, or authentication checks.
|
|
10
|
+
|
|
11
|
+
## 1. Discover before installing
|
|
12
|
+
|
|
13
|
+
Read this document before making changes. Keep a short checkpoint of completed steps, absolute paths, and the next required action.
|
|
14
|
+
Never include credentials in that checkpoint.
|
|
15
|
+
|
|
16
|
+
Check `uname -s` and `uname -m`. Require `Darwin` and `arm64`.
|
|
17
|
+
For another result, stop with: `Unsupported onboarding environment: expected local macOS arm64; observed OS/ARCH.`
|
|
18
|
+
If the shell runs through Rosetta, request a native ARM64 terminal. Do not attempt a different platform's installation.
|
|
19
|
+
|
|
20
|
+
Find `stelz`, `bun`, `node`, and `npm` on PATH. Check their versions.
|
|
21
|
+
Stelz requires Bun 1.4.4 or later and Node.js 24 or later.
|
|
22
|
+
Select one absolute `STELZ_HOME`, using the existing environment value or `~/.local/share/stelz`.
|
|
23
|
+
Keep that value for every CLI command and MCP connection. Do not infer it from the chat or project directory.
|
|
24
|
+
|
|
25
|
+
If Stelz exists, run `stelz --help`, `stelz doctor`, and `stelz status`.
|
|
26
|
+
Check that help lists `profile create`. Reuse a working installation and compatible runtime.
|
|
27
|
+
Inspect existing profile IDs before creating one. A display name is not an ID.
|
|
28
|
+
Do not replace an existing catalog, `secrets.env`, skill directory, or client configuration file.
|
|
29
|
+
|
|
30
|
+
## 2. Supply missing dependencies and Stelz
|
|
31
|
+
|
|
32
|
+
Reuse compatible dependencies. Do not upgrade or replace a browser that holds existing profile data.
|
|
33
|
+
|
|
34
|
+
- If Node is missing or older than version 24, use the existing Node version manager or Homebrew's `node@24` package.
|
|
35
|
+
If neither is available, install an official macOS ARM64 archive from [Node.js downloads](https://nodejs.org/en/download).
|
|
36
|
+
Verify its checksum against the release's `SHASUMS256.txt` and extract it into a new user-owned directory.
|
|
37
|
+
Add its `bin` directory to this session's PATH. Preserve other Node installations.
|
|
38
|
+
- If Bun is missing, use the [official Bun installer](https://bun.sh/docs/installation).
|
|
39
|
+
Download and inspect the installer before running it. Add its `bin` directory to this session's PATH.
|
|
40
|
+
If an older Bun is present, install the required version in a separate directory instead of overwriting it.
|
|
41
|
+
- Install Stelz with `CAMOFOX_SKIP_DOWNLOAD=1 PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm install --global stelz`.
|
|
42
|
+
For development, replace `stelz` with the supplied release archive's absolute path.
|
|
43
|
+
Do not use a registry staging placeholder as a release. If no release is available, request a release archive.
|
|
44
|
+
Keep npm lifecycle scripts enabled: native dependencies can need them.
|
|
45
|
+
If the global prefix is not writable, use `--prefix` with a new user-owned directory and its absolute CLI path.
|
|
46
|
+
Do not use `sudo` or replace an existing installation without the necessary permission.
|
|
47
|
+
|
|
48
|
+
Record the selected executable as `STELZ_CLI`. Resolve symlinks to locate its package directory, `STELZ_PACKAGE`.
|
|
49
|
+
For npm installations, the resolved CLI is `<package>/dist/cli.js`.
|
|
50
|
+
Use the selected absolute executable in place of `stelz` in every command below.
|
|
51
|
+
Use absolute paths in client configuration. Include the selected Bun and Node directories in the MCP process's PATH.
|
|
52
|
+
|
|
53
|
+
Find Camoufox in the existing `CAMOUFOX_EXECUTABLE` setting or the default path:
|
|
54
|
+
`~/Library/Caches/camoufox/Camoufox.app/Contents/MacOS/camoufox`.
|
|
55
|
+
Use `file` to check the executable's architecture. Setup and browser startup provide the final compatibility check.
|
|
56
|
+
|
|
57
|
+
If no compatible installation exists, use the `camoufox-js` version bundled with the selected Stelz package:
|
|
58
|
+
|
|
59
|
+
```sh
|
|
60
|
+
CAMOUFOX_INSTALL_DIR="/absolute/new/camoufox-directory" node "$STELZ_PACKAGE/node_modules/camoufox-js/dist/__main__.js" fetch
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Use a new directory outside any existing browser installation. Do not run `fetch` against an occupied browser directory.
|
|
64
|
+
The macOS executable inside it is `Camoufox.app/Contents/MacOS/camoufox`.
|
|
65
|
+
Set `CAMOUFOX_EXECUTABLE` to that absolute path for setup, lifecycle commands, and the MCP connection.
|
|
66
|
+
For persistence, add only that setting to the service's existing `secrets.env` after initialization, preserving all other assignments and private permissions.
|
|
67
|
+
If an existing browser is incompatible, preserve it and its profiles. Report the compatibility failure instead of migrating browser data.
|
|
68
|
+
|
|
69
|
+
## 3. Initialize and create or reuse the profile
|
|
70
|
+
|
|
71
|
+
Run `stelz init` with the selected `STELZ_HOME`. Initialization preserves existing entries and credentials.
|
|
72
|
+
Run `stelz doctor` again. If the runtime is missing, run `stelz setup`.
|
|
73
|
+
If the installed runtime already works, reuse it. Setup requires every existing profile to be stopped safely.
|
|
74
|
+
Do not stop unrelated browsers to complete onboarding. Report an explicit runtime update as pending when necessary.
|
|
75
|
+
|
|
76
|
+
```sh
|
|
77
|
+
stelz profile create work --json
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Use the requested ID instead of `work` when supplied. New profiles use native storage and a free loopback port.
|
|
81
|
+
An existing ID is reused without rewriting it. Omitted network options retain its existing route and expected IP.
|
|
82
|
+
An unspecified route on a new profile is direct. Use `--direct` to require direct networking explicitly.
|
|
83
|
+
Existing checkpoint profiles stay in checkpoint mode. This command does not migrate them.
|
|
84
|
+
|
|
85
|
+
For a proxy, supply one of `--proxy-url URL` or `--proxy-env NAME`.
|
|
86
|
+
For an expected IP, supply one of `--expected-ip IP` or `--expected-ip-env NAME`.
|
|
87
|
+
Environment input reads the named variable from this process, then stores the value through the catalog's existing private-secret transaction.
|
|
88
|
+
It is a one-time import, not a dependency on the client's future environment.
|
|
89
|
+
On reuse, existing secret references remain unchanged. Conflicting values produce an error without changing the profile.
|
|
90
|
+
An absent or empty proxy variable fails. It never selects direct networking.
|
|
91
|
+
Do not place credentials in client configuration or repeat them in reports. Prefer environment input over literal credentials in shell history.
|
|
92
|
+
|
|
93
|
+
`--json` writes a success object to stdout with `ok`, `created`, `home`, and a profile summary.
|
|
94
|
+
Errors go to stderr as `{ "ok": false, "error": { "code": "...", "message": "..." } }` with exit status 1.
|
|
95
|
+
Use the error's requested recovery action. Do not delete state and retry with another identity.
|
|
96
|
+
|
|
97
|
+
Run `stelz start work`, then `stelz doctor work`. Repeated starts reuse the same safe browser lifetime.
|
|
98
|
+
If startup fails, preserve the profile and inspect its diagnostics.
|
|
99
|
+
Ownership failures require inspection and explicit recovery. Proxy failures require the correct credentials or route.
|
|
100
|
+
|
|
101
|
+
## 4. Install the canonical skill and connect the client
|
|
102
|
+
|
|
103
|
+
The canonical skill ships at `$STELZ_PACKAGE/skills/stelz-browser`.
|
|
104
|
+
Install a directory symlink to it in the selected client's supported skill location.
|
|
105
|
+
Create a missing parent directory, then use `ln -s` only when the destination is absent, including absence of a dangling symlink.
|
|
106
|
+
Reuse an existing matching link. Preserve any different installation and report the conflict.
|
|
107
|
+
Do not create separate edited skill variants for different clients.
|
|
108
|
+
|
|
109
|
+
The examples below use `stelz-work` as the connection name.
|
|
110
|
+
First inspect an existing entry with that name. Reuse an exact match of command, arguments, service home, and relevant environment.
|
|
111
|
+
If it differs, preserve it and request a distinct name or an explicit update. Do not remove another server to make room.
|
|
112
|
+
|
|
113
|
+
### Codex
|
|
114
|
+
|
|
115
|
+
Use `~/.agents/skills/stelz-browser`, or `.agents/skills/stelz-browser` for a project-scoped installation.
|
|
116
|
+
Inspect `codex mcp get stelz-work --json` before adding an absent entry:
|
|
117
|
+
|
|
118
|
+
```sh
|
|
119
|
+
codex mcp add stelz-work --env "STELZ_HOME=$STELZ_HOME" --env "PATH=$PATH" -- "$STELZ_CLI" mcp --profile work
|
|
120
|
+
codex mcp get stelz-work --json
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Include `CAMOUFOX_EXECUTABLE` if it is an environment-only override.
|
|
124
|
+
Codex supports skill symlinks. Check the current tool inventory after registration.
|
|
125
|
+
For project scope, merge the same `mcp_servers` fields into `.codex/config.toml` in a trusted project.
|
|
126
|
+
Preserve existing fields. Complete any required project-trust prompt through the normal client flow.
|
|
127
|
+
If the tools are absent, start a new Codex session or restart the client, then resume at verification.
|
|
128
|
+
Keep existing approval and trust settings. [Codex MCP](https://developers.openai.com/codex/mcp/) and [skills](https://developers.openai.com/codex/skills/) describe these supported mechanisms.
|
|
129
|
+
|
|
130
|
+
### Claude Code
|
|
131
|
+
|
|
132
|
+
Use `~/.claude/skills/stelz-browser`, or `.claude/skills/stelz-browser` for project scope.
|
|
133
|
+
Inspect `claude mcp get stelz-work`, then add only an absent entry:
|
|
134
|
+
|
|
135
|
+
```sh
|
|
136
|
+
claude mcp add --env "STELZ_HOME=$STELZ_HOME" --env "PATH=$PATH" --transport stdio --scope user stelz-work -- "$STELZ_CLI" mcp --profile work
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Run `/mcp` in the target session and check its actual tools. Accept required trust prompts through the normal client flow.
|
|
140
|
+
Reconnect or restart if necessary. See [Claude MCP](https://code.claude.com/docs/en/mcp) and [skills](https://code.claude.com/docs/en/skills).
|
|
141
|
+
|
|
142
|
+
### Hermes
|
|
143
|
+
|
|
144
|
+
Use the active Hermes profile's `skills/stelz-browser` directory, normally `~/.hermes/skills/stelz-browser`.
|
|
145
|
+
Read the active configuration, normally `~/.hermes/config.yaml`. Preserve every unrelated mapping and setting.
|
|
146
|
+
Add only the absent `mcp_servers.stelz-work` entry with absolute paths:
|
|
147
|
+
|
|
148
|
+
```yaml
|
|
149
|
+
mcp_servers:
|
|
150
|
+
stelz-work:
|
|
151
|
+
command: /absolute/path/to/stelz
|
|
152
|
+
args: [mcp, --profile, work]
|
|
153
|
+
env:
|
|
154
|
+
STELZ_HOME: /absolute/service/home
|
|
155
|
+
PATH: /absolute/bun/bin:/absolute/node/bin:/usr/bin:/bin
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Merge this mapping. Preserve the rest of the YAML file. Include an environment-only browser override if used.
|
|
159
|
+
Run `/reload-mcp` if the installed version supports it, otherwise start a new Hermes session.
|
|
160
|
+
Verify the tools associated with `stelz-work` in that session.
|
|
161
|
+
See [Hermes MCP](https://hermes-agent.nousresearch.com/docs/user-guide/features/mcp) and [skills](https://hermes-agent.nousresearch.com/docs/user-guide/features/skills).
|
|
162
|
+
|
|
163
|
+
## 5. Verify from the target agent
|
|
164
|
+
|
|
165
|
+
A saved entry or successful `tools/list` does not establish end-to-end readiness.
|
|
166
|
+
Use the target agent's registered tools for the following check. A separate SDK probe establishes browser control only.
|
|
167
|
+
|
|
168
|
+
1. Start a temporary HTTP fixture on `127.0.0.1`, with a free port. Serve a page with a button and an observable result.
|
|
169
|
+
The installed package includes `examples/onboarding-fixture.html`. Bun can serve it with `Bun.serve` and `Bun.file`.
|
|
170
|
+
2. Call `profile_status`, then `profile_acquire`. A busy controller requires deliberate handoff, not a new profile.
|
|
171
|
+
3. Call `camofox_list_tabs`. Create a tab for the local fixture.
|
|
172
|
+
4. Read a fresh `camofox_snapshot`. Find **Verify Stelz**, then click its returned element reference.
|
|
173
|
+
5. Read another snapshot. Require **Stelz verified** and the incremented persistent check count.
|
|
174
|
+
6. Call `profile_release`. Check status again. The browser must remain ready, with no active controller.
|
|
175
|
+
7. Acquire again, list tabs, and inspect the same page. Confirm its result remains, then release again.
|
|
176
|
+
8. Stop only the temporary fixture server. Leave the browser and its pages available.
|
|
177
|
+
|
|
178
|
+
For an actual website's authentication challenge, pause and request human action in the same window.
|
|
179
|
+
Never automate authentication challenges as part of this check.
|
|
180
|
+
|
|
181
|
+
## 6. Report and resume
|
|
182
|
+
|
|
183
|
+
Return this table with evidence and any pending action:
|
|
184
|
+
|
|
185
|
+
| State | Required evidence |
|
|
186
|
+
| --- | --- |
|
|
187
|
+
| Installed | Compatible dependencies, selected Stelz version, and prepared runtime |
|
|
188
|
+
| Browser ready | Selected profile started and browser-control interface responded |
|
|
189
|
+
| Client configured | Canonical skill installed and the intended MCP entry saved |
|
|
190
|
+
| Verified | The target agent completed the local-page interaction and release check |
|
|
191
|
+
|
|
192
|
+
Mark untested stages as pending. If a restart is required, give the client, profile ID, service home, and exact verification step to resume.
|
|
193
|
+
Do not claim **Verified** from configuration alone. A failed run can resume with the same prompt and profile.
|
|
194
|
+
|
|
195
|
+
The [onboarding acceptance report](onboarding-acceptance.md) records test coverage and required interventions.
|
package/docs/clients.md
CHANGED
|
@@ -4,6 +4,10 @@ Start the selected profile first. Then configure its MCP connection.
|
|
|
4
4
|
All clients use the same `stelz mcp --profile ID` command.
|
|
5
5
|
None require a separate browser-control implementation.
|
|
6
6
|
|
|
7
|
+
For dependency installation, profile creation, and canonical skill installation, follow [Bootstrap](bootstrap.md).
|
|
8
|
+
Check the tools in the target agent session after registration. Start a new session if the client cannot reload MCP.
|
|
9
|
+
Report **Verified** only after the agent completes the local-page interaction and releases control with the browser still ready.
|
|
10
|
+
|
|
7
11
|
The examples configure two servers. Each server selects one profile.
|
|
8
12
|
Replace example IDs with your configured IDs. Existing IDs do not change.
|
|
9
13
|
Use an absolute `stelz` path if the client cannot find the global command.
|
|
@@ -12,7 +16,7 @@ If you set `STELZ_HOME`, pass the same value to the client and the lifecycle com
|
|
|
12
16
|
## Codex
|
|
13
17
|
|
|
14
18
|
Copy the entries from [codex.toml](../examples/codex.toml) into the appropriate MCP configuration.
|
|
15
|
-
Preserve existing configuration entries.
|
|
19
|
+
Preserve existing configuration entries. Start a new session if its MCP tools are absent after the change.
|
|
16
20
|
|
|
17
21
|
The example uses documented `mcp_servers`, `command`, and `args` fields.
|
|
18
22
|
See the [official Codex MCP documentation](https://learn.chatgpt.com/docs/extend/mcp?surface=cli).
|
package/docs/distribution.md
CHANGED
|
@@ -1,21 +1,23 @@
|
|
|
1
1
|
# Distribution
|
|
2
2
|
|
|
3
|
-
The
|
|
4
|
-
The package remains `stelz` version `0.2.
|
|
3
|
+
The repository contains one package. Its root manifest defines the release archive and development dependencies.
|
|
4
|
+
The package remains `stelz` version `0.2.1`, with the MIT license.
|
|
5
5
|
Release preparation and npm publication use separate workflows.
|
|
6
6
|
|
|
7
7
|
1. Run `bun install --frozen-lockfile --ignore-scripts` in a clean workspace.
|
|
8
|
-
2. Run `bun run
|
|
9
|
-
3. Run `bun run
|
|
10
|
-
4. Run `bun run
|
|
11
|
-
5. Run `bun run
|
|
12
|
-
6. Run `bun run verify:release --archive .state/release-candidate/stelz-0.2.0.tgz`.
|
|
8
|
+
2. Run `bun run check`.
|
|
9
|
+
3. Run `bun run pack` once.
|
|
10
|
+
4. Run `bun run verify:release`.
|
|
11
|
+
5. Run `bun run verify:release --native`.
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
The
|
|
13
|
+
`pack` builds once and saves the archive, hash, and source metadata in `release-artifacts/`.
|
|
14
|
+
Bun resolves dependency links into a temporary archive. npm packs the extracted release directory after native dependency preparation.
|
|
15
|
+
The preparation steps disable lifecycle scripts. There is no implicit prepack build.
|
|
16
|
+
Verification uses the saved archive. It does not build or pack another archive.
|
|
17
|
+
Use `--destination DIRECTORY` for another output directory. Verification then requires `--archive FILE`.
|
|
17
18
|
Packing requires the source workspace and its development dependencies. Installing the archive does not require that workspace.
|
|
18
|
-
|
|
19
|
+
The archive uses canonical documentation and examples directly.
|
|
20
|
+
For profile data archives, see [Import and export profiles](profile-transfer.md).
|
|
19
21
|
The archive includes the optional browser skill, third-party notices, and UI font and library licenses.
|
|
20
22
|
It excludes Stelz source, tests, browser state, and credentials.
|
|
21
23
|
It bundles the prepared Camofox and camoufox-js packages, including transitive JavaScript sources and licenses.
|
|
@@ -27,37 +29,44 @@ The native packages `better-sqlite3` and `impit` remain separate direct dependen
|
|
|
27
29
|
The temporary release tree moves their declarations from the bundled manifests to Stelz's manifest.
|
|
28
30
|
This prevents npm from treating missing native packages as bundled dependencies.
|
|
29
31
|
Their JavaScript and native binaries come from ordinary npm dependency installation on the target machine.
|
|
32
|
+
The ZIP libraries `yazl` and `yauzl` and checkpoint parser `stream-json` also install as ordinary runtime dependencies.
|
|
30
33
|
Setup links these native packages from the installed Stelz package into the staged runtime.
|
|
31
34
|
Native addon execution requires separate checks after ordinary package installation.
|
|
32
35
|
The packaging check does not establish browser execution with lifecycle scripts disabled.
|
|
36
|
+
The browser-free `--native` check uses ordinary installation and the staged runtime.
|
|
37
|
+
It executes SQLite queries and constructs Impit clients through each relevant dependency resolution path.
|
|
38
|
+
Release preparation requires both installation modes on Linux and macOS against the same archive.
|
|
33
39
|
Run `bun run test:package` on every supported target before release.
|
|
34
40
|
|
|
35
41
|
## Prepare the release candidate
|
|
36
42
|
|
|
37
43
|
Run the **Prepare release candidate** workflow on the release source commit.
|
|
38
44
|
Its Linux and macOS checks must pass before it builds an archive.
|
|
39
|
-
The workflow builds one candidate
|
|
45
|
+
The workflow builds one candidate and uploads `stelz-release-candidate`.
|
|
46
|
+
Linux and macOS download and check that archive. Both installation checks must pass before acceptance can proceed.
|
|
40
47
|
The artifact contains the tarball, its SHA-256 file, and `candidate.json` with the source commit.
|
|
41
48
|
Preparation uses read-only repository permissions and requires no publication secret.
|
|
42
49
|
|
|
43
50
|
Download the complete artifact from that run. Use the same tarball for all acceptance checks:
|
|
44
51
|
|
|
45
52
|
```sh
|
|
46
|
-
bun run verify:release --archive /path/to/stelz-0.2.
|
|
53
|
+
bun run verify:release --archive /path/to/stelz-0.2.1.tgz
|
|
47
54
|
PROXY_TEST_ENV=/private/path/proxies.env STELZ_RELEASE_CANDIDATE_RUN=RUN_ID \
|
|
48
|
-
bun run test:package --archive /path/to/stelz-0.2.
|
|
55
|
+
bun run test:package --archive /path/to/stelz-0.2.1.tgz --native --proxy --manual
|
|
49
56
|
```
|
|
50
57
|
|
|
51
58
|
The second command uses ordinary npm installation outside the repository.
|
|
52
|
-
It checks native addons, the bundled UI, MCP control, native persistence, proxy routing, and human takeover.
|
|
59
|
+
It checks native addons, the bundled UI, MCP control, native persistence, profile transfers, proxy routing, and human takeover.
|
|
53
60
|
Each suite controls the installed CLI. No suite rebuilds the supplied archive.
|
|
54
61
|
Supply two distinct private proxy routes as described in [testing](tests.md#proxy-acceptance).
|
|
55
62
|
Complete the human action in the paused browser when prompted.
|
|
63
|
+
For `0.2.1`, the release owner waived this check. Use `--waive-manual` instead of `--manual` for that release.
|
|
64
|
+
The acceptance record keeps `manual: false` and records the owner-approved waiver. Other versions still require the human check.
|
|
56
65
|
|
|
57
|
-
Successful complete acceptance writes `release/acceptance-0.2.
|
|
66
|
+
Successful complete acceptance writes `release/acceptance-0.2.1.json`.
|
|
58
67
|
This public record contains the archive hash, workflow run, source commit, platform, and check results.
|
|
59
68
|
It omits proxy credentials, profile data, and local paths. Private detailed reports stay under `.state/`.
|
|
60
|
-
Commit the acceptance record without changing release source. Tag that commit `v0.2.
|
|
69
|
+
Commit the acceptance record without changing release source. Tag that commit `v0.2.1`.
|
|
61
70
|
|
|
62
71
|
## Publish the tested archive
|
|
63
72
|
|