attesso 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/bin/attesso.mjs +3 -1
- package/package.json +4 -4
- package/src/connect.mjs +7 -4
- package/src/ui/static/index.html +22 -2
package/README.md
CHANGED
|
@@ -22,10 +22,10 @@ are appended, and writes mode and path changes to the same files the hook reads:
|
|
|
22
22
|
|
|
23
23
|
```sh
|
|
24
24
|
npx attesso ui
|
|
25
|
-
npx attesso ui --
|
|
25
|
+
npx attesso ui --no-open
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
The server binds `127.0.0.1`, mints a per-process token, and serves the page from
|
|
28
|
+
The server binds `127.0.0.1:8197`, mints a per-process token, and serves the page from
|
|
29
29
|
the installed package. It has no account, no hosted data, and no dependency on a
|
|
30
30
|
snapshot file. `Ctrl-C` stops it.
|
|
31
31
|
|
package/bin/attesso.mjs
CHANGED
|
@@ -78,6 +78,7 @@ const USAGE = `attesso: a local, signed ledger of what your agents attempted
|
|
|
78
78
|
attesso mode [observe|enforce|off] read or set the active hook mode
|
|
79
79
|
attesso paths [--json|--set FILE] read or replace the filesystem scope
|
|
80
80
|
attesso ui [--port N] [--no-open] local control surface for the signed ledger
|
|
81
|
+
(default 127.0.0.1:8197)
|
|
81
82
|
attesso policy pull [--url URL] [--apply] [--json]
|
|
82
83
|
verify the hosted rule bundle and optionally
|
|
83
84
|
write rules.json (key from ATTESSO_API_KEY)
|
|
@@ -697,11 +698,12 @@ switch (command) {
|
|
|
697
698
|
case 'ui': {
|
|
698
699
|
try {
|
|
699
700
|
const options = flags(rest);
|
|
700
|
-
const requested = options.port === undefined ?
|
|
701
|
+
const requested = options.port === undefined ? 8197 : Number(options.port);
|
|
701
702
|
if (!Number.isInteger(requested) || requested < 0 || requested > 65535) {
|
|
702
703
|
console.error('ui: --port must be an integer from 0 to 65535');
|
|
703
704
|
process.exit(2);
|
|
704
705
|
}
|
|
706
|
+
requireLedger();
|
|
705
707
|
const ui = await startUi({
|
|
706
708
|
dir: DIR,
|
|
707
709
|
cwd: process.cwd(),
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "attesso",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Bounds: decide an AI agent's next tool call before it runs, with a signed record. Free and unlimited locally, $0.00085 per synced decision.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
8
|
-
"attesso": "
|
|
9
|
-
"attesso-mcp": "
|
|
10
|
-
"attesso-control-mcp": "
|
|
8
|
+
"attesso": "bin/attesso.mjs",
|
|
9
|
+
"attesso-mcp": "bin/attesso-mcp.mjs",
|
|
10
|
+
"attesso-control-mcp": "bin/attesso-control-mcp.mjs"
|
|
11
11
|
},
|
|
12
12
|
"files": [
|
|
13
13
|
"bin",
|
package/src/connect.mjs
CHANGED
|
@@ -78,12 +78,15 @@ function wiredHarnesses(harnesses, { dir, cwd }) {
|
|
|
78
78
|
});
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
function instructions({ mode, wired, manual }) {
|
|
81
|
+
function instructions({ initialized, mode, wired, manual }) {
|
|
82
|
+
if (!initialized) return ['run `attesso init` first'];
|
|
82
83
|
const next = [];
|
|
83
84
|
if (!mode) next.push('run `attesso connect --write --mode observe` from the agent');
|
|
84
85
|
else if (mode === 'off') next.push('run `attesso mode observe` to start recording');
|
|
85
86
|
if (manual.length) next.push('wire the listed harnesses by hand, or use the generic hook contract');
|
|
86
|
-
if (mode && !wired.length
|
|
87
|
+
if (mode && !wired.length && !manual.length) {
|
|
88
|
+
next.push('no agent harness detected; wire the generic hook contract or run `attesso connect` from an agent project');
|
|
89
|
+
}
|
|
87
90
|
return next;
|
|
88
91
|
}
|
|
89
92
|
|
|
@@ -101,7 +104,7 @@ export function status({ dir, cwd = process.cwd(), home = homedir() } = {}) {
|
|
|
101
104
|
wired: wired.map((harness) => harness.key),
|
|
102
105
|
manual: manual.map((harness) => harness.key),
|
|
103
106
|
connected: initialized && mode !== null && mode !== 'off' && wired.length > 0,
|
|
104
|
-
next: instructions({ mode, wired, manual }),
|
|
107
|
+
next: instructions({ initialized, mode, wired, manual }),
|
|
105
108
|
};
|
|
106
109
|
}
|
|
107
110
|
|
|
@@ -163,6 +166,6 @@ export function connect({
|
|
|
163
166
|
wired: wired.map((result) => result.key),
|
|
164
167
|
manual: results.filter((result) => result.manual || result.error || result.reason?.includes('merge by hand')).map((result) => result.key),
|
|
165
168
|
agent_context: agentContext,
|
|
166
|
-
next: instructions({ mode: effectiveMode, wired, manual: results.filter((result) => result.manual || result.error) }),
|
|
169
|
+
next: instructions({ initialized: isInitialised(ledgerDir), mode: effectiveMode, wired, manual: results.filter((result) => result.manual || result.error) }),
|
|
167
170
|
};
|
|
168
171
|
}
|
package/src/ui/static/index.html
CHANGED
|
@@ -69,6 +69,7 @@
|
|
|
69
69
|
.badge{border:1px solid #ead6b3;background:#fbf5e8;color:#7a4b12;padding:2px 6px;font-size:10px}
|
|
70
70
|
.actions{display:flex;gap:7px;align-items:center}
|
|
71
71
|
.button{border:1px solid #d0d5dd;background:#fff;color:var(--body);padding:7px 11px;font-size:12px;cursor:pointer}
|
|
72
|
+
.button:disabled{opacity:.4;cursor:default}
|
|
72
73
|
.button.primary{border-color:var(--ink);background:var(--ink);color:#fff}
|
|
73
74
|
.button:hover{background:#f2f4f7}
|
|
74
75
|
.page{max-width:1440px;padding:24px 30px 48px}
|
|
@@ -303,7 +304,7 @@
|
|
|
303
304
|
<div class="topbar">
|
|
304
305
|
<div class="crumbs"><span>Bounds</span><span>/</span><span class="current">local</span><span class="badge">ledger</span></div>
|
|
305
306
|
<div class="actions">
|
|
306
|
-
<button class="button" type="button" id="export-draft">Export draft</button>
|
|
307
|
+
<button class="button" type="button" id="export-draft" title="Set a rule on a block first" disabled>Export draft</button>
|
|
307
308
|
<button class="button" type="button" id="all-calls">All calls</button>
|
|
308
309
|
</div>
|
|
309
310
|
</div>
|
|
@@ -687,9 +688,12 @@
|
|
|
687
688
|
el('agent-action').textContent = 'Manage agent';
|
|
688
689
|
} else {
|
|
689
690
|
const wired = Array.isArray(agentData.wired) ? agentData.wired.length : 0;
|
|
691
|
+
const recorded = days.reduce((total, day) => total + summarize(day).calls, 0);
|
|
690
692
|
el('agent-sub').textContent = wired
|
|
691
693
|
? 'Hook is ' + (agentData.mode || 'not configured') + ' - connect any agent to start observing'
|
|
692
|
-
:
|
|
694
|
+
: recorded > 0
|
|
695
|
+
? fmt(recorded) + ' recorded calls; no harness wired'
|
|
696
|
+
: 'No harness wired - connect an agent to start observing';
|
|
693
697
|
el('agent-action').textContent = 'Connect agent';
|
|
694
698
|
}
|
|
695
699
|
renderAgentPanel();
|
|
@@ -1044,6 +1048,7 @@
|
|
|
1044
1048
|
closePopover();
|
|
1045
1049
|
applyFlowFilter();
|
|
1046
1050
|
renderTokens(day);
|
|
1051
|
+
updateExportDraft();
|
|
1047
1052
|
}
|
|
1048
1053
|
|
|
1049
1054
|
function renderV1Flow(day, preserveCenter = null) {
|
|
@@ -1132,6 +1137,7 @@
|
|
|
1132
1137
|
closePopover();
|
|
1133
1138
|
applyFlowFilter();
|
|
1134
1139
|
renderTokens(day);
|
|
1140
|
+
updateExportDraft();
|
|
1135
1141
|
}
|
|
1136
1142
|
|
|
1137
1143
|
function applyFlowFilter() {
|
|
@@ -1328,6 +1334,7 @@
|
|
|
1328
1334
|
if (allOn) drafts.delete(key); else drafts.set(key, state);
|
|
1329
1335
|
}
|
|
1330
1336
|
updateMarkerDraft(marker);
|
|
1337
|
+
updateExportDraft();
|
|
1331
1338
|
const popover = el('flow-popover');
|
|
1332
1339
|
if (popover && !popover.hidden) {
|
|
1333
1340
|
const draft = popover.querySelector('#fp-block-draft');
|
|
@@ -1347,6 +1354,7 @@
|
|
|
1347
1354
|
if (!row) continue;
|
|
1348
1355
|
if (next === 'unset') drafts.delete(String(row[0])); else drafts.set(String(row[0]), next);
|
|
1349
1356
|
}
|
|
1357
|
+
updateExportDraft();
|
|
1350
1358
|
const marker = selectedMarker || markerBySeq.get(key);
|
|
1351
1359
|
if (marker) {
|
|
1352
1360
|
marker.classList.remove('draft-allow', 'draft-deny', 'draft-ask');
|
|
@@ -1382,6 +1390,10 @@
|
|
|
1382
1390
|
async function renderDay(day) {
|
|
1383
1391
|
if (!calls[day] && !v1) return;
|
|
1384
1392
|
const request = ++dayRequest;
|
|
1393
|
+
if (selectedDay !== day && drafts.size > 0) {
|
|
1394
|
+
drafts.clear();
|
|
1395
|
+
updateExportDraft();
|
|
1396
|
+
}
|
|
1385
1397
|
selectedDay = day;
|
|
1386
1398
|
callsDay = day;
|
|
1387
1399
|
callsPage = 0;
|
|
@@ -1414,7 +1426,15 @@
|
|
|
1414
1426
|
renderFlow(selectedDay, centerMinute);
|
|
1415
1427
|
}
|
|
1416
1428
|
|
|
1429
|
+
function updateExportDraft() {
|
|
1430
|
+
const button = el('export-draft');
|
|
1431
|
+
if (!button) return;
|
|
1432
|
+
button.disabled = drafts.size === 0;
|
|
1433
|
+
button.title = drafts.size === 0 ? 'Set a rule on a block first' : '';
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1417
1436
|
function exportDraft() {
|
|
1437
|
+
if (drafts.size === 0) return;
|
|
1418
1438
|
const output = {
|
|
1419
1439
|
generated_at: new Date().toISOString(),
|
|
1420
1440
|
day: selectedDay,
|