@ours.network/fleet 0.10.2 → 0.10.4

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 (70) hide show
  1. package/README.md +66 -0
  2. package/dist/application/capabilities.d.ts +6 -0
  3. package/dist/application/capabilities.js +37 -0
  4. package/dist/application/errors.d.ts +31 -0
  5. package/dist/application/errors.js +51 -0
  6. package/dist/application/fleet-query-service.d.ts +31 -0
  7. package/dist/application/fleet-query-service.js +180 -0
  8. package/dist/application/log-service.d.ts +28 -0
  9. package/dist/application/log-service.js +146 -0
  10. package/dist/application/role-command-service.d.ts +37 -0
  11. package/dist/application/role-command-service.js +82 -0
  12. package/dist/application/role-creation-service.d.ts +142 -0
  13. package/dist/application/role-creation-service.js +374 -0
  14. package/dist/application/role-repository.d.ts +20 -0
  15. package/dist/application/role-repository.js +168 -0
  16. package/dist/application/session-control.d.ts +55 -0
  17. package/dist/application/session-control.js +115 -0
  18. package/dist/application/types.d.ts +156 -0
  19. package/dist/application/types.js +1 -0
  20. package/dist/cli.js +141 -0
  21. package/dist/config.d.ts +7 -2
  22. package/dist/config.js +18 -4
  23. package/dist/creation.d.ts +11 -0
  24. package/dist/creation.js +22 -5
  25. package/dist/docs.d.ts +1 -1
  26. package/dist/docs.js +34 -0
  27. package/dist/index.d.ts +10 -1
  28. package/dist/index.js +9 -1
  29. package/dist/runner.js +10 -2
  30. package/dist/session/acp.js +5 -1
  31. package/dist/session/control.d.ts +4 -2
  32. package/dist/session/control.js +45 -13
  33. package/dist/spawn.d.ts +20 -2
  34. package/dist/spawn.js +94 -24
  35. package/dist/supervisor/launchd.js +17 -0
  36. package/dist/supervisor/none.js +17 -0
  37. package/dist/supervisor/systemd.js +4 -0
  38. package/dist/supervisor/types.d.ts +6 -0
  39. package/dist/tmux.d.ts +2 -0
  40. package/dist/tmux.js +8 -0
  41. package/dist/web/audit.d.ts +22 -0
  42. package/dist/web/audit.js +54 -0
  43. package/dist/web/auth.d.ts +61 -0
  44. package/dist/web/auth.js +186 -0
  45. package/dist/web/control.d.ts +14 -0
  46. package/dist/web/control.js +110 -0
  47. package/dist/web/device-store.d.ts +27 -0
  48. package/dist/web/device-store.js +155 -0
  49. package/dist/web/events.d.ts +15 -0
  50. package/dist/web/events.js +34 -0
  51. package/dist/web/lock.d.ts +5 -0
  52. package/dist/web/lock.js +69 -0
  53. package/dist/web/runtime.d.ts +12 -0
  54. package/dist/web/runtime.js +170 -0
  55. package/dist/web/server.d.ts +35 -0
  56. package/dist/web/server.js +261 -0
  57. package/dist/web/service.d.ts +42 -0
  58. package/dist/web/service.js +180 -0
  59. package/dist/web/terminal/bridge.d.ts +27 -0
  60. package/dist/web/terminal/bridge.js +317 -0
  61. package/dist/web-app/assets/TerminalView-DcImdrI1.js +9 -0
  62. package/dist/web-app/assets/index-BokQN1Ao.js +9 -0
  63. package/dist/web-app/assets/index-lAXzaOZM.css +1 -0
  64. package/dist/web-app/icons/ours-fleet-maskable.svg +4 -0
  65. package/dist/web-app/icons/ours-fleet.svg +4 -0
  66. package/dist/web-app/index.html +17 -0
  67. package/dist/web-app/manifest.webmanifest +15 -0
  68. package/dist/web-app/offline.html +18 -0
  69. package/dist/web-app/sw.js +51 -0
  70. package/package.json +26 -3
@@ -0,0 +1 @@
1
+ .xterm{cursor:text;position:relative;user-select:none;-ms-user-select:none;-webkit-user-select:none}.xterm.focus,.xterm:focus{outline:none}.xterm .xterm-helpers{position:absolute;top:0;z-index:5}.xterm .xterm-helper-textarea{padding:0;border:0;margin:0;position:absolute;opacity:0;left:-9999em;top:0;width:0;height:0;z-index:-5;white-space:nowrap;overflow:hidden;resize:none}.xterm .composition-view{background:#000;color:#fff;display:none;position:absolute;white-space:nowrap;z-index:1}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{background-color:#000;overflow-y:scroll;cursor:default;position:absolute;inset:0}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;left:0;top:0}.xterm .xterm-scroll-area{visibility:hidden}.xterm-char-measure-element{display:inline-block;visibility:hidden;position:absolute;top:0;left:-9999em;line-height:normal}.xterm.enable-mouse-events{cursor:default}.xterm.xterm-cursor-pointer,.xterm .xterm-cursor-pointer{cursor:pointer}.xterm.column-select.focus{cursor:crosshair}.xterm .xterm-accessibility:not(.debug),.xterm .xterm-message{position:absolute;inset:0;z-index:10;color:transparent;pointer-events:none}.xterm .xterm-accessibility-tree:not(.debug) *::selection{color:transparent}.xterm .xterm-accessibility-tree{-webkit-user-select:text;user-select:text;white-space:pre}.xterm .live-region{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}.xterm-dim{opacity:1!important}.xterm-underline-1{text-decoration:underline}.xterm-underline-2{text-decoration:double underline}.xterm-underline-3{text-decoration:wavy underline}.xterm-underline-4{text-decoration:dotted underline}.xterm-underline-5{text-decoration:dashed underline}.xterm-overline{text-decoration:overline}.xterm-overline.xterm-underline-1{text-decoration:overline underline}.xterm-overline.xterm-underline-2{text-decoration:overline double underline}.xterm-overline.xterm-underline-3{text-decoration:overline wavy underline}.xterm-overline.xterm-underline-4{text-decoration:overline dotted underline}.xterm-overline.xterm-underline-5{text-decoration:overline dashed underline}.xterm-strikethrough{text-decoration:line-through}.xterm-screen .xterm-decoration-container .xterm-decoration{z-index:6;position:absolute}.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer{z-index:7}.xterm-decoration-overview-ruler{z-index:8;position:absolute;top:0;right:0;pointer-events:none}.xterm-decoration-top{z-index:2;position:relative}:root{font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;color:#e9eef0;background:#080b0c;font-synthesis:none;--panel: #111617;--line: #222a2c;--muted: #849093;--mint: #7ce7b0;--amber: #f0c66c;--red: #ff827c}*{box-sizing:border-box}body{margin:0;min-width:900px;min-height:100vh;background:radial-gradient(circle at 70% -20%,#183027 0,transparent 35%),#080b0c}button,input,select,textarea{font:inherit}button{color:inherit}button:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible{outline:2px solid var(--mint);outline-offset:2px}.auth-screen{display:grid;place-content:center;text-align:center;min-height:100vh;color:var(--muted)}.auth-screen h1{color:#fff;margin-bottom:0}.brand-wordmark{color:var(--mint);font-size:21px;font-weight:820;letter-spacing:-.02em}.auth-screen .brand-wordmark{justify-self:center;font-size:32px}.shell{display:grid;grid-template-columns:224px 1fr;min-height:100vh}aside{position:fixed;inset:0 auto 0 0;width:224px;display:flex;flex-direction:column;padding:24px 14px;border-right:1px solid #1d2425;background:#080b0ceb;-webkit-backdrop-filter:blur(18px);backdrop-filter:blur(18px)}.brand{display:flex;gap:12px;align-items:center;padding:0 8px 30px}.brand div{display:flex;flex-direction:column}.brand small{color:var(--muted);font-size:11px;text-transform:uppercase;letter-spacing:1.4px}nav{display:grid;gap:5px}nav button{display:grid;grid-template-columns:24px 1fr auto;gap:8px;align-items:center;width:100%;border:0;border-radius:8px;padding:10px 12px;text-align:left;color:#98a3a5;background:transparent;text-transform:capitalize;cursor:pointer}nav button:hover,nav button.active{color:#fff;background:#151b1c}nav button.active{box-shadow:inset 2px 0 var(--mint)}nav b{background:#422f22;color:var(--amber);border-radius:10px;font-size:11px;padding:2px 7px}.sidebar-foot{margin-top:auto;display:grid;grid-template-columns:12px 1fr;align-items:center;padding:12px;color:var(--muted);font-size:12px;text-transform:capitalize}.sidebar-foot i{width:7px;height:7px;border-radius:50%;background:var(--amber)}.sidebar-foot i.live{background:var(--mint);box-shadow:0 0 9px var(--mint)}.sidebar-foot small{grid-column:2;opacity:.6;margin-top:3px}.main{grid-column:2;min-width:0}header{display:flex;justify-content:space-between;align-items:flex-end;height:124px;padding:25px 36px 23px;border-bottom:1px solid var(--line);background:#080b0c8c}h1,h2,h3,p{margin-top:0}header h1{margin:4px 0 0;font-size:29px;letter-spacing:-.8px}.eyebrow{color:var(--mint);text-transform:uppercase;font-size:10px;letter-spacing:1.8px;font-weight:700}.header-actions,.actions{display:flex;gap:9px}button.primary,button.secondary,.actions button,.terminal-toolbar button{border-radius:7px;padding:9px 13px;cursor:pointer}button.primary{border:1px solid #83e9b5;color:#07130d;background:var(--mint);font-weight:700}button.primary:disabled{opacity:.4;cursor:default}button.secondary,.actions button,.terminal-toolbar button{border:1px solid #30393b;background:#141a1b}button.secondary:hover,.actions button:hover{border-color:#526064}.content,.workspace{padding:28px 36px 60px}.toolbar{display:flex;align-items:center;justify-content:space-between;margin-bottom:16px;color:var(--muted);font-size:12px}.toolbar input{width:340px;padding:10px 13px;color:#fff;background:#101516;border:1px solid var(--line);border-radius:8px}.toolbar>div{display:flex;align-items:center;gap:10px}.toolbar button{padding:7px 10px}.role-row.inactive{opacity:.72}.status-guide{display:flex;flex-wrap:wrap;gap:7px;align-items:center;margin-bottom:15px;color:var(--muted);font-size:11px}.status-guide>span,.status-chip{display:inline-flex;align-items:center;gap:5px;border:1px solid #30393b;border-radius:12px;padding:3px 7px;white-space:nowrap}.status-guide b{color:#fff;font-size:11px}.status-guide small{flex-basis:100%;color:var(--muted)}.status-guide .ready,.status-chip.ready{border-color:#315e4a}.status-guide .busy,.status-chip.busy{border-color:#315478}.status-guide .attention,.status-chip.attention,.status-chip.unknown{border-color:#66552f}.status-guide .offline,.status-chip.offline{border-color:#693b38}.role-table{border:1px solid var(--line);border-radius:10px;overflow:hidden;background:#0e1213cc}.role-row{display:grid;grid-template-columns:minmax(260px,1.55fr) repeat(4,minmax(125px,1fr));width:100%;align-items:center;gap:15px;padding:14px 18px;border:0;border-bottom:1px solid var(--line);background:transparent;text-align:left;cursor:pointer}button.role-row:hover{background:#141a1b}.role-row.heading{padding-block:10px;color:#6f7b7e;font-size:10px;letter-spacing:1px;text-transform:uppercase;cursor:default}.role-row:last-child{border-bottom:0}.role-row>span{min-width:0;display:flex;flex-direction:column;gap:3px}.role-row strong{font-size:13px;text-transform:capitalize;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.role-row small{color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.role-name{position:relative;display:grid!important;grid-template-columns:auto 1fr auto;align-items:center}.role-name .mission-summary{display:-webkit-box;max-height:2.5em;line-height:1.25;overflow:hidden;overflow-wrap:anywhere;white-space:normal;-webkit-box-orient:vertical;-webkit-line-clamp:2}.status-chip{color:#c9d1d3;font-size:10px;padding:3px 6px}.status-chip i{width:6px;height:6px;border-radius:50%;background:#667174}.status-chip.ready i{background:var(--mint)}.status-chip.busy i{background:#71b7ff}.status-chip.attention i,.status-chip.unknown i{background:var(--amber)}.status-chip.offline i{background:var(--red)}.state.ready,.hero-state.ready i{background:var(--mint);box-shadow:0 0 7px #69dba0}.state.busy,.hero-state.busy i{background:#71b7ff}.state.attention,.state.unknown,.hero-state.attention i,.hero-state.unknown i{background:var(--amber)}.state.offline,.hero-state.offline i{background:var(--red)}.role-name em{color:#7f8a8d;font-size:10px;font-style:normal;border:1px solid #2e3739;border-radius:10px;padding:3px 6px}.empty{padding:60px;text-align:center;color:var(--muted)}.banner{margin:16px 36px 0;border:1px solid;border-radius:8px;padding:10px 13px;font-size:13px}.banner.error,.error{border-color:#5c302f;background:#271616;color:#ffaaa5}.banner.warning,.warning{border-color:#5a4726;background:#241e12;color:#f1ce83}.banner.info{border-color:#28463b;background:#10231c;color:#9be4bf}.workspace>.banner{margin-inline:0}.back{border:0;background:none;color:var(--muted);padding:0 0 18px;cursor:pointer}.workspace-summary{display:flex;align-items:center;gap:9px;color:var(--muted);font-size:12px}.workspace-summary>span{border:1px solid var(--line);border-radius:12px;padding:4px 8px}.workspace-summary small{margin-left:auto}.hero-state{display:flex;gap:7px;align-items:center;color:#fff;text-transform:capitalize}.hero-state i{width:7px;height:7px;border-radius:50%;background:#788}.tabs{display:flex;gap:22px;margin:26px 0 22px;border-bottom:1px solid var(--line)}.tabs button{border:0;border-bottom:2px solid transparent;padding:10px 2px;background:none;color:var(--muted);text-transform:capitalize;cursor:pointer}.tabs button.active{color:#fff;border-bottom-color:var(--mint)}.tabs button:disabled{opacity:.35;cursor:not-allowed}.dashboard-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px}.panel{border:1px solid var(--line);border-radius:10px;background:#101516db;padding:18px}.panel h2{font-size:15px;letter-spacing:-.2px}.panel.wide{grid-column:1 / -1}.evidence>div:first-child{display:flex;justify-content:space-between}.evidence>div:first-child strong{color:var(--mint);text-transform:capitalize;font-size:12px}dl{margin:0}dl div{display:grid;grid-template-columns:120px 1fr;gap:15px;padding:7px 0;border-top:1px solid #1d2426;font-size:12px}dt{color:var(--muted)}dd{margin:0;word-break:break-word}.danger{color:#ff9e99!important;border-color:#613432!important}.activity-layout{display:grid;grid-template-columns:1fr 290px;gap:14px;align-items:start}.activity{display:grid;gap:9px}.activity-filter{display:flex;align-items:center;justify-content:space-between;gap:12px;color:var(--muted);font-size:11px}.activity-filter button{padding:6px 9px}.event{border-left:2px solid #334044;padding:10px 13px;background:#0d1213}.event.agent_text{border-color:var(--mint)}.event.error,.event.permission{border-color:var(--amber)}.event p{margin:5px 0 0;white-space:pre-wrap}.event small,.muted{color:var(--muted)}.composer{position:sticky;top:16px;display:grid;gap:9px}textarea{min-height:84px;resize:vertical}.composer textarea,fieldset input,fieldset select,fieldset textarea{width:100%;color:#fff;border:1px solid #303a3c;border-radius:6px;background:#0d1112;padding:9px 10px}.composer small{color:var(--muted);line-height:1.45}pre{max-width:100%;overflow:auto;white-space:pre-wrap;word-break:break-word;font:12px/1.55 SFMono-Regular,Consolas,monospace;color:#cbd5d7}.log-panel>pre{margin:0;padding:5px 8px;border-bottom:1px solid #1b2224}.audit-list div{display:grid;grid-template-columns:180px 1fr 120px;padding:10px 0;border-top:1px solid var(--line);font-size:12px}.audit-list time{color:var(--muted)}.modal-backdrop{position:fixed;z-index:10;inset:0;display:grid;place-items:center;padding:30px;background:#000000b8;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px)}.modal{width:min(900px,95vw);max-height:92vh;overflow:auto;border:1px solid #354043;border-radius:13px;background:#0d1112;box-shadow:0 30px 100px #000}.modal-head{position:sticky;z-index:2;top:0;display:flex;justify-content:space-between;align-items:flex-start;padding:22px 26px 18px;border-bottom:1px solid var(--line);background:#0d1112f5}.modal-head h2{margin:4px 0 0}.icon{border:0;background:none;color:var(--muted);font-size:25px;cursor:pointer}.wizard,.progress{padding:22px 26px}fieldset{border:0;border-bottom:1px solid var(--line);padding:0 0 20px;margin:0 0 20px}legend{margin-bottom:13px;color:var(--mint);text-transform:uppercase;font-size:10px;letter-spacing:1.5px;font-weight:700}.form-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:13px}.form-grid.three{grid-template-columns:repeat(3,1fr)}.wake-sources{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:7px 14px}.wake-sources>small{grid-column:1 / -1;color:var(--muted)}.wake-sources label{display:flex;flex-direction:row;align-items:center;gap:7px;color:#c7d0d1;font-size:11px;text-transform:none;letter-spacing:0}.form-grid label{display:grid;gap:6px;color:#b7c0c2;font-size:12px}.form-grid label small{color:var(--muted)}.form-grid .wide{grid-column:1 / -1}.risk{display:flex;align-items:center;gap:8px;margin-top:14px;color:var(--amber);font-size:12px}.review{border:1px solid #2f493f;border-radius:8px;background:#101b17;padding:15px}.review dl{display:grid;grid-template-columns:1fr 1fr;gap:0 20px}.modal-actions{display:flex;justify-content:flex-end;gap:9px;margin-top:20px}.stage{display:flex;gap:12px;min-height:54px;position:relative}.stage:after{position:absolute;left:5px;top:14px;bottom:0;width:1px;background:#34413d;content:""}.stage:last-child:after{display:none}.stage i{z-index:1;width:11px;height:11px;margin-top:2px;border-radius:50%;background:var(--mint);box-shadow:0 0 0 4px #173026}.stage span{display:flex;flex-direction:column;text-transform:capitalize}.stage small{color:var(--muted);margin-top:3px}.terminal-panel{padding:0;overflow:hidden}.terminal-toolbar{display:flex;align-items:center;gap:12px;min-height:48px;padding:8px 12px;border-bottom:1px solid var(--line);color:var(--muted);font-size:11px}.terminal-toolbar button{margin-left:auto;padding-block:6px}.terminal-mode{text-transform:uppercase;letter-spacing:1px;color:var(--amber)}.terminal-mode.controlling{color:var(--mint)}.terminal-host{height:calc(100vh - 310px);min-height:360px;padding:8px;background:#050707}@media(max-width:1050px){.role-row{grid-template-columns:1.5fr repeat(3,1fr)}.role-row>span:nth-child(4){display:none}}@media(prefers-reduced-motion:reduce){*,*:before,*:after{scroll-behavior:auto!important;transition:none!important;animation:none!important}}
@@ -0,0 +1,4 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512">
2
+ <rect width="512" height="512" fill="#111318"/>
3
+ <text x="256" y="289" text-anchor="middle" fill="#8cf0c5" font-family="system-ui, sans-serif" font-size="138" font-weight="800" letter-spacing="-5">Ours</text>
4
+ </svg>
@@ -0,0 +1,4 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="192" height="192" viewBox="0 0 192 192">
2
+ <rect width="192" height="192" rx="42" fill="#111318"/>
3
+ <text x="96" y="108" text-anchor="middle" fill="#8cf0c5" font-family="system-ui, sans-serif" font-size="53" font-weight="800" letter-spacing="-2">Ours</text>
4
+ </svg>
@@ -0,0 +1,17 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <meta name="color-scheme" content="dark" />
7
+ <meta name="theme-color" content="#111318" />
8
+ <link rel="manifest" href="/manifest.webmanifest" />
9
+ <link rel="icon" href="/icons/ours-fleet.svg" type="image/svg+xml" />
10
+ <title>ours fleet console</title>
11
+ <script type="module" crossorigin src="/assets/index-BokQN1Ao.js"></script>
12
+ <link rel="stylesheet" crossorigin href="/assets/index-lAXzaOZM.css">
13
+ </head>
14
+ <body>
15
+ <div id="root"></div>
16
+ </body>
17
+ </html>
@@ -0,0 +1,15 @@
1
+ {
2
+ "id": "/",
3
+ "name": "ours fleet console",
4
+ "short_name": "ours fleet",
5
+ "description": "Secure localhost console for the ours agent fleet",
6
+ "start_url": "/",
7
+ "scope": "/",
8
+ "display": "standalone",
9
+ "background_color": "#111318",
10
+ "theme_color": "#111318",
11
+ "icons": [
12
+ { "src": "/icons/ours-fleet.svg", "sizes": "192x192", "type": "image/svg+xml", "purpose": "any" },
13
+ { "src": "/icons/ours-fleet-maskable.svg", "sizes": "512x512", "type": "image/svg+xml", "purpose": "maskable" }
14
+ ]
15
+ }
@@ -0,0 +1,18 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <meta name="theme-color" content="#111318" />
7
+ <title>ours fleet unavailable</title>
8
+ <style>
9
+ :root { color-scheme: dark; font-family: system-ui, sans-serif; background: #111318; color: #edf5f1; }
10
+ body { min-height: 100vh; margin: 0; display: grid; place-items: center; }
11
+ main { max-width: 32rem; padding: 2rem; text-align: center; }
12
+ b { display: inline-grid; place-items: center; width: 3rem; height: 3rem; border: 5px solid #8cf0c5; border-radius: 50%; color: #8cf0c5; }
13
+ p { color: #aab8b2; line-height: 1.5; }
14
+ </style>
15
+ </head>
16
+ <body><main><b>O</b><h1>Local daemon unavailable</h1>
17
+ <p>No fleet data is available offline. Start the service on this computer, then reconnect.</p></main></body>
18
+ </html>
@@ -0,0 +1,51 @@
1
+ const CACHE = 'ours-fleet-shell-v1';
2
+ const OFFLINE = '/offline.html';
3
+
4
+ export function isForbiddenCacheUrl(input) {
5
+ const localOrigin = globalThis.location?.origin ?? 'http://127.0.0.1';
6
+ const url = new URL(input, localOrigin);
7
+ return url.origin !== localOrigin
8
+ || url.pathname.startsWith('/api/')
9
+ || url.search.length > 0
10
+ || url.hash.length > 0;
11
+ }
12
+
13
+ export function isCacheableAsset(input) {
14
+ if (isForbiddenCacheUrl(input)) return false;
15
+ const url = new URL(input, globalThis.location?.origin ?? 'http://127.0.0.1');
16
+ return /^\/assets\/[A-Za-z0-9_-]+\.(?:js|css)$/.test(url.pathname);
17
+ }
18
+
19
+ if (typeof globalThis.addEventListener === 'function'
20
+ && 'skipWaiting' in globalThis && 'clients' in globalThis) {
21
+ self.addEventListener('install', event => {
22
+ event.waitUntil(caches.open(CACHE).then(cache => cache.add(OFFLINE)).then(() => self.skipWaiting()));
23
+ });
24
+
25
+ self.addEventListener('activate', event => {
26
+ event.waitUntil(caches.keys().then(keys => Promise.all(
27
+ keys.filter(key => key.startsWith('ours-fleet-shell-') && key !== CACHE)
28
+ .map(key => caches.delete(key)),
29
+ )).then(() => self.clients.claim()));
30
+ });
31
+
32
+ self.addEventListener('fetch', event => {
33
+ const request = event.request;
34
+ if (request.method !== 'GET' || isForbiddenCacheUrl(request.url)) return;
35
+ if (request.mode === 'navigate') {
36
+ const offline = async () => (await caches.match(OFFLINE)) ?? Response.error();
37
+ event.respondWith(self.navigator.onLine === false
38
+ ? offline()
39
+ : fetch(request, { cache: 'no-store' }).catch(offline));
40
+ return;
41
+ }
42
+ if (!isCacheableAsset(request.url)) return;
43
+ event.respondWith(caches.match(request).then(async cached => {
44
+ if (cached) return cached;
45
+ const response = await fetch(request);
46
+ if (response.ok && response.type === 'basic')
47
+ await (await caches.open(CACHE)).put(request, response.clone());
48
+ return response;
49
+ }));
50
+ });
51
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ours.network/fleet",
3
- "version": "0.10.2",
3
+ "version": "0.10.4",
4
4
  "description": "Harness-agnostic fleet of persistent, identity-bound AI agents. Declarative fleet.yaml, tmux or ACP sessions, supervision, and ours.network messaging.",
5
5
  "type": "module",
6
6
  "license": "FSL-1.1-Apache-2.0",
@@ -22,22 +22,45 @@
22
22
  "node": ">=20"
23
23
  },
24
24
  "scripts": {
25
- "build": "tsc -p tsconfig.json",
25
+ "clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
26
+ "build": "npm run clean && tsc -p tsconfig.json && vite build",
27
+ "typecheck": "tsc -p tsconfig.json --noEmit && tsc -p web/tsconfig.json --noEmit",
28
+ "lint": "npm run typecheck",
26
29
  "test": "vitest run",
30
+ "test:web": "vitest run test/web",
31
+ "test:e2e": "npm run build && playwright test",
32
+ "dev:web": "vite",
27
33
  "prepublishOnly": "npm run build && npm test"
28
34
  },
29
35
  "dependencies": {
30
36
  "@agentclientprotocol/sdk": "^1.3.0",
37
+ "@fastify/static": "^10.1.2",
38
+ "@fastify/websocket": "^11.2.0",
39
+ "@xterm/addon-fit": "0.10.0",
40
+ "@xterm/addon-serialize": "0.13.0",
41
+ "@xterm/headless": "5.5.0",
42
+ "@xterm/xterm": "5.5.0",
31
43
  "commander": "^12.1.0",
44
+ "fastify": "^5.4.0",
45
+ "react": "^19.1.1",
46
+ "react-dom": "^19.1.1",
47
+ "secure-json-parse": "^4.1.0",
48
+ "ws": "^8.18.3",
32
49
  "yaml": "^2.5.0"
33
50
  },
34
51
  "optionalDependencies": {
35
52
  "@agentclientprotocol/claude-agent-acp": "^0.63.0",
36
- "@agentclientprotocol/codex-acp": "^1.1.7"
53
+ "@agentclientprotocol/codex-acp": "^1.1.7",
54
+ "node-pty": "^1.1.0"
37
55
  },
38
56
  "devDependencies": {
57
+ "@playwright/test": "^1.54.1",
39
58
  "@types/node": "^20.14.0",
59
+ "@types/react": "^19.1.9",
60
+ "@types/react-dom": "^19.1.7",
61
+ "@types/ws": "^8.18.1",
40
62
  "typescript": "^5.5.0",
63
+ "vite": "^7.0.6",
41
64
  "vitest": "^2.0.0"
42
65
  }
43
66
  }