secure-agents 0.7.0 → 0.7.2
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/dist/config.js +9 -1
- package/dist/ui.js +22 -5
- package/dist/waker.js +2 -1
- package/package.json +4 -9
package/dist/config.js
CHANGED
|
@@ -18,7 +18,15 @@ export async function moveOldHome() {
|
|
|
18
18
|
const running = await fetch(`http://127.0.0.1:${port}/ui`, { signal: AbortSignal.timeout(1500) }).then(() => true, () => false);
|
|
19
19
|
if (running)
|
|
20
20
|
throw new Error('The old Securee is still running. Close its window (or stop it), then run this again: your data moves to ~/.secure.');
|
|
21
|
-
|
|
21
|
+
try {
|
|
22
|
+
fs.renameSync(old, HOME);
|
|
23
|
+
}
|
|
24
|
+
catch (e) {
|
|
25
|
+
const code = e.code;
|
|
26
|
+
if (code !== 'EPERM' && code !== 'EBUSY' && code !== 'EACCES')
|
|
27
|
+
throw e;
|
|
28
|
+
throw new Error(`Could not move ${old}: something still uses it, usually Claude Code or Codex running the old Securee tools. Close Claude Code and Codex completely (or restart the computer), then run this again.`);
|
|
29
|
+
}
|
|
22
30
|
return `Moved your data from ${old} to ${HOME}: same keys, pairings and passphrase.`;
|
|
23
31
|
}
|
|
24
32
|
export const DEFAULT_LIMITS = { messagesPerMinute: 60, maxPendingPerPeer: 20, maxItems: 2000, maxLoginFailures: 5, lockoutSeconds: 60, sessionHours: 12, pendingHours: 24, updateCheckHours: 6, updateCheckOnOpenMinutes: 60, minFreeDiskMB: 1024, precheckSeconds: 120, historyLogBytes: 16384, notifyGroupSeconds: 3, fileLimitMaxMB: 51200, wakeMinutes: 240 };
|
package/dist/ui.js
CHANGED
|
@@ -69,9 +69,12 @@ button:focus-visible,input:focus-visible,select:focus-visible,summary:focus-visi
|
|
|
69
69
|
.toasts{position:fixed;right:20px;bottom:20px;z-index:20;display:grid;gap:8px;max-width:min(420px,calc(100vw - 40px))}
|
|
70
70
|
.toast{background:var(--inv);color:var(--inv-ink);border-radius:12px;padding:12px 16px;font-size:13.5px;box-shadow:0 12px 32px -8px rgba(0,0,0,.35);animation:rise .2s ease-out} .toast.err{background:var(--bad);color:#fff}
|
|
71
71
|
@keyframes rise{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
|
|
72
|
-
dialog{border:1px solid var(--line);border-radius:16px;padding:0;background:var(--surface);color:var(--ink);width:min(520px,calc(100vw - 32px));box-shadow:0 30px 80px -20px rgba(0,0,0,.45)}
|
|
72
|
+
dialog{border:1px solid var(--line);border-radius:16px;padding:0;max-height:calc(100dvh - 32px);overflow:auto;background:var(--surface);color:var(--ink);width:min(520px,calc(100vw - 32px));box-shadow:0 30px 80px -20px rgba(0,0,0,.45)}
|
|
73
73
|
dialog::backdrop{background:rgba(0,0,0,.45);backdrop-filter:blur(3px)}
|
|
74
74
|
.dlg{padding:24px;display:grid;gap:16px}
|
|
75
|
+
.flow{display:grid;grid-template-columns:repeat(5,1fr);gap:8px;counter-reset:step} .flow>div{border:1px solid var(--line);border-radius:10px;padding:10px;display:grid;gap:4px;align-content:start;position:relative} .flow>div::before{counter-increment:step;content:counter(step);font-size:11px;color:var(--ink2)} .flow b{font-size:13px} .flow span{font-size:12px;color:var(--ink2)}
|
|
76
|
+
.opts{display:grid;gap:8px;margin:0;padding:0;list-style:none} .opts li{display:grid;grid-template-columns:150px 1fr;gap:12px;font-size:13px} .opts li b{font-weight:600}
|
|
77
|
+
@media (max-width:640px){.flow{grid-template-columns:1fr}.opts li{grid-template-columns:1fr;gap:2px}}
|
|
75
78
|
.notes{margin:0;padding-left:18px;display:grid;gap:6px;color:var(--ink2)}
|
|
76
79
|
.progress{height:4px;border-radius:4px;background:var(--sunk);overflow:hidden} .progress i{display:block;height:100%;width:35%;background:var(--ink);border-radius:4px;animation:slide 1.2s ease-in-out infinite}
|
|
77
80
|
@keyframes slide{0%{transform:translateX(-100%)}100%{transform:translateX(300%)}}
|
|
@@ -99,7 +102,7 @@ dialog::backdrop{background:rgba(0,0,0,.45);backdrop-filter:blur(3px)}
|
|
|
99
102
|
<section class="page" data-page="brain" hidden><div class="head"><h2>Brain</h2><p class="muted">Decisions your agent saved, with why and sources. Shared ones can be searched by paired computers, even while this one is off.</p></div><div id="brain" class="page" style="padding:0"></div></section>
|
|
100
103
|
|
|
101
104
|
<section class="page" data-page="settings" hidden><div class="head"><h2>Settings</h2><p class="muted">How your agent is started, updates, and your passkeys.</p></div>
|
|
102
|
-
<div class="card"><div><h3>Wake your agent</h3><p class="muted small">Starts your agent by itself for a question or task you approved, so it answers without you opening it. Questions never change files.</p></div>
|
|
105
|
+
<div class="card"><div class="row"><div class="grow"><h3>Wake your agent</h3><p class="muted small">Starts your agent by itself for a question or task you approved, so it answers without you opening it. Questions never change files.</p></div><button class="ghost" id="wake-help">How this works</button></div>
|
|
103
106
|
<p id="wake"></p>
|
|
104
107
|
<div class="row"><select id="wake-preset" aria-label="Agent to wake"><option value="off">Off: I tell my agent myself</option><option value="claude">Claude Code</option><option value="codex">Codex</option><option value="custom">Other agent (type its command)</option></select>
|
|
105
108
|
<input id="wake-cwd" class="field" placeholder="Folder where tasks may make changes, e.g. /Users/me/project" aria-label="Folder where tasks may make changes"></div>
|
|
@@ -116,6 +119,16 @@ dialog::backdrop{background:rgba(0,0,0,.45);backdrop-filter:blur(3px)}
|
|
|
116
119
|
</div>
|
|
117
120
|
</main>
|
|
118
121
|
<div class="toasts" id="toasts" aria-live="polite"></div>
|
|
122
|
+
<dialog id="wake-dlg" style="width:min(760px,calc(100vw - 32px))"><div class="dlg"><div class="row"><div class="mark">${lock()}</div><div class="grow"><h3>How waking your agent works</h3><p class="muted small">What happens when another computer asks your agent something.</p></div></div>
|
|
123
|
+
<div class="flow"><div><b>Request arrives</b><span>A question or a task from a paired computer.</span></div><div><b>You approve</b><span>With your passkey. Automatic questions skip this unless Secure flags them.</span></div><div><b>Secure starts your agent</b><span>Claude Code or Codex, in the background, inside its sandbox.</span></div><div><b>It does the work</b><span>Questions only read. Tasks change files only inside your folder.</span></div><div><b>Result goes back</b><span>An answer with sources, or a signed task result.</span></div></div>
|
|
124
|
+
<p class="sub" style="margin:0">The settings</p>
|
|
125
|
+
<ul class="opts"><li><b>Off</b><span>Nothing starts by itself. Approved requests wait until you open your agent and say "check Secure".</span></li>
|
|
126
|
+
<li><b>Claude Code / Codex</b><span>Secure starts that agent for you. What it may read is set per computer (Computers, then Reach).</span></li>
|
|
127
|
+
<li><b>Folder</b><span>Where tasks may change files, including every folder inside it. Nothing outside it can be changed. Questions never change files.</span></li>
|
|
128
|
+
<li><b>Tasks may run commands</b><span>Lets a task run tests, builds and scripts. Off: it can only read and edit files.</span></li>
|
|
129
|
+
<li><b>Tasks may use the internet</b><span>Lets a task open web pages and call online services.</span></li>
|
|
130
|
+
<li><b>Stop a run after</b><span>The longest one run may take before Secure stops it.</span></li></ul>
|
|
131
|
+
<div class="row"><span class="grow"></span><button class="primary" id="wake-dlg-close">Got it</button></div></div></dialog>
|
|
119
132
|
<dialog id="update-dlg"><div class="dlg"><div class="row"><div class="mark">${lock()}</div><div class="grow"><h3 id="dlg-title">Update</h3><p class="muted small" id="dlg-sub"></p></div></div>
|
|
120
133
|
<div id="dlg-notes-wrap"><p class="sub" style="margin-bottom:8px">What's new</p><ul class="notes" id="dlg-notes"></ul></div>
|
|
121
134
|
<p class="small"><a id="dlg-link" target="_blank" rel="noopener">See the exact code changes on npm</a></p>
|
|
@@ -136,8 +149,10 @@ $('out').onclick = () => api('/human/logout', {}).then(load);
|
|
|
136
149
|
// Tabs
|
|
137
150
|
let tab = 'inbox';
|
|
138
151
|
try { tab = localStorage.getItem('secure-tab') || 'inbox'; } catch (e) {}
|
|
139
|
-
function show(t) { tab = t; try { localStorage.setItem('secure-tab', t); } catch (e) {}
|
|
152
|
+
function show(t) { tab = t; try { localStorage.setItem('secure-tab', t); } catch (e) {}
|
|
153
|
+
if (t === 'settings' && !app.hidden) { let seen = true; try { seen = !!localStorage.getItem('secure-wake-explained'); localStorage.setItem('secure-wake-explained', '1'); } catch (e) {} if (!seen) $('wake-dlg').showModal(); } for (const b of document.querySelectorAll('nav.tabs button')) b.setAttribute('aria-selected', String(b.dataset.tab === t)); for (const s of document.querySelectorAll('[data-page]')) s.hidden = s.dataset.page !== t; if (t === 'history') loadHistory(); }
|
|
140
154
|
for (const b of document.querySelectorAll('nav.tabs button')) b.onclick = () => show(b.dataset.tab);
|
|
155
|
+
$('wake-help').onclick = () => $('wake-dlg').showModal(); $('wake-dlg-close').onclick = () => $('wake-dlg').close();
|
|
141
156
|
|
|
142
157
|
// Passkeys: the server fixes exactly what will happen, then your touch confirms it.
|
|
143
158
|
const b64 = (s) => Uint8Array.from(atob(s.replace(/-/g, '+').replace(/_/g, '/') + '==='.slice((s.length + 3) % 4)), c => c.charCodeAt(0));
|
|
@@ -303,7 +318,7 @@ function brainCards(list) {
|
|
|
303
318
|
el('p', { textContent: d.decision }), d.why ? el('p', { className: 'muted small', textContent: 'Why: ' + d.why }) : null, (d.sources || []).length ? el('p', { className: 'mono muted', textContent: d.sources.join(' · ') }) : null));
|
|
304
319
|
}
|
|
305
320
|
|
|
306
|
-
let pendingSig = '', peersSig = '', brainSig = '', lastState = {}, announced = '';
|
|
321
|
+
let pendingSig = '', peersSig = '', brainSig = '', wakeSig = '', lastState = {}, announced = '';
|
|
307
322
|
async function load(force) {
|
|
308
323
|
const s = await api('/human/state');
|
|
309
324
|
signin.hidden = s.error !== 'signin';
|
|
@@ -323,7 +338,9 @@ async function load(force) {
|
|
|
323
338
|
if (s.wakeLast) { wl.textContent = 'Last run ' + new Date(s.wakeLast.at).toLocaleTimeString() + ': ' + s.wakeLast.message; wl.style.color = s.wakeLast.ok ? '' : 'var(--bad)'; }
|
|
324
339
|
$('wake').textContent = s.wake ? 'Wakes ' + s.wake + '.' : 'Off. Approved requests wait until you tell your agent "check Secure".';
|
|
325
340
|
if (document.activeElement !== $('wake-preset') && document.activeElement !== $('wake-cwd') && !$('wake-cwd').value && s.wakePreset) $('wake-preset').value = s.wakePreset;
|
|
326
|
-
|
|
341
|
+
// Refill only when the saved values change, so a box you just ticked isn't reset before you save.
|
|
342
|
+
const ws = JSON.stringify([s.wakeMinutes, s.wakeInternet, s.wakeCommands]);
|
|
343
|
+
if (ws !== wakeSig) { wakeSig = ws; $('wake-min').value = s.wakeMinutes; $('wake-net').checked = s.wakeInternet; $('wake-cmds').checked = s.wakeCommands; }
|
|
327
344
|
$('fl-mb').max = s.fileLimitMaxMB; $('fl-now').textContent = 'Now ' + Math.round(s.maxFileBytes / 1048576) + ' MB';
|
|
328
345
|
// Redraw only what changed, so a half-read card or a typed path isn't reset every refresh.
|
|
329
346
|
// Questions your agent is still checking stay out of the Inbox; they show up only if they need you.
|
package/dist/waker.js
CHANGED
|
@@ -29,8 +29,9 @@ export function describeWake(w) {
|
|
|
29
29
|
if (w.preset === 'custom')
|
|
30
30
|
return `"${w.line}" (not sandboxed by Secure, so "Shared folders" can't be enforced); tasks change files in ${w.cwd}`;
|
|
31
31
|
const old = w.preset === 'claude' && !claudeCanRestrict(w.question.command);
|
|
32
|
+
const cmds = commandsAllowed(w) ? '; tasks may run commands' : '; tasks may not run commands';
|
|
32
33
|
const net = w.internet ? (w.preset === 'codex' ? '; tasks may use the internet when reach is the whole computer' : '; tasks may use the internet') : '';
|
|
33
|
-
return `${w.preset === 'codex' ? 'Codex' : 'Claude Code'}; tasks change files in ${w.cwd}${net}${old ? '. This Claude Code is too old to limit reading to shared folders: update it' : ''}`;
|
|
34
|
+
return `${w.preset === 'codex' ? 'Codex' : 'Claude Code'}; tasks change files in ${w.cwd}${cmds}${net}${old ? '. This Claude Code is too old to limit reading to shared folders: update it' : ''}`;
|
|
34
35
|
}
|
|
35
36
|
/** Older saved wakes kept the task flags in their arguments. */
|
|
36
37
|
const commandsAllowed = (w) => w.allowCommands ?? w.task.args.some((a) => a === 'workspace-write' || a === 'Bash');
|
package/package.json
CHANGED
|
@@ -1,16 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "secure-agents",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.2",
|
|
4
4
|
"description": "Let AI agents on different computers and platforms talk to each other over a direct encrypted link, with both people's consent.",
|
|
5
5
|
"changes": [
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"Questions your agent is still checking no longer flash up in the Inbox.",
|
|
10
|
-
"Clearer reasons when a file isn't found, and whoami now says its rules are what this computer allows others.",
|
|
11
|
-
"Settings: set the largest file this computer sends or accepts. Paired computers are told, and files move up to the smaller of the two limits.",
|
|
12
|
-
"Task conversations: the agent doing a task can ask the asker a question and carry on with the answer, and follow-up questions about a task resume the same agent session.",
|
|
13
|
-
"Settings: choose how long your agent may run (default now 4 hours, was 30 minutes), and whether tasks may use the internet."
|
|
6
|
+
"Fix: ticking \"Tasks may run commands\" or \"Tasks may use the internet\" in Settings no longer un-ticks itself before you save.",
|
|
7
|
+
"Settings shows whether tasks may run commands.",
|
|
8
|
+
"Settings: a \"How this works\" pop-up for Wake your agent, shown the first time you open Settings."
|
|
14
9
|
],
|
|
15
10
|
"homepage": "https://www.npmjs.com/package/secure-agents",
|
|
16
11
|
"type": "module",
|