rewritable 0.11.0 → 0.12.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/package.json +1 -1
- package/seeds/rewritable.html +88 -3
package/package.json
CHANGED
package/seeds/rewritable.html
CHANGED
|
@@ -7991,13 +7991,98 @@ function showAgentInstallDialog(envelope) {
|
|
|
7991
7991
|
const ib = card.querySelector('[data-act=install]'); if (ib) ib.onclick = async () => close(await runtimeInstallAgent(envelope));
|
|
7992
7992
|
}));
|
|
7993
7993
|
}
|
|
7994
|
-
// §1.3 / §12 — install trigger: pick a .rwa-skill.json
|
|
7994
|
+
// §1.3 / §12 — install trigger: pick a .rwa-skill.json / .rwa-agent.json envelope OR an
|
|
7995
|
+
// intelligence carrier .html (a rewritable carrying a signed rwa-agent/1 record), then route.
|
|
7995
7996
|
function runtimePromptInstall() {
|
|
7996
|
-
const inp = document.createElement('input'); inp.type = 'file'; inp.accept = '.rwa-skill.json,.rwa-agent.json,application/json,.json';
|
|
7997
|
-
inp.onchange = () => { const f = inp.files && inp.files[0]; if (!f) return; const rd = new FileReader(); rd.onload = () => {
|
|
7997
|
+
const inp = document.createElement('input'); inp.type = 'file'; inp.accept = '.rwa-skill.json,.rwa-agent.json,application/json,.json,.html,.htm,text/html';
|
|
7998
|
+
inp.onchange = () => { const f = inp.files && inp.files[0]; if (!f) return; const rd = new FileReader(); rd.onload = () => { routeInstallFromText(String(rd.result || '')); }; rd.readAsText(f); };
|
|
7998
7999
|
inp.click();
|
|
7999
8000
|
}
|
|
8000
8001
|
|
|
8002
|
+
// ── intelligence/0.2 (docs/specs/rwa-intelligence-spec.md §5) — the file-drop bridge.
|
|
8003
|
+
// An "intelligence" ships as a CARRIER: a (skill-host) rewritable carrying a signed rwa-agent/1
|
|
8004
|
+
// record in its frozen #rwa-agents zone (the overlay half is the v0.9 agent role — see
|
|
8005
|
+
// runtime.agents / buildAgentZone above). Dropping a carrier onto a target extracts that record
|
|
8006
|
+
// and routes it to the existing consent dialog + runtime.agents.install. In a carrier's RAW bytes
|
|
8007
|
+
// the record lives inside INLINE_DOC, so its closing script tag is backslash-escaped (the zone
|
|
8008
|
+
// <div>/</div> delimiters are not). We extract + un-escape INLINE_DOC (the inverse of buildFile's
|
|
8009
|
+
// escapeTL — every escape is one backslash + one char), then parse the zone exactly as
|
|
8010
|
+
// readTrustworthyAgents does. The signature stays the trust anchor: the dialog re-verifies.
|
|
8011
|
+
function _carrierDoc(html) {
|
|
8012
|
+
const marker = 'const INLINE_DOC = `';
|
|
8013
|
+
const i = String(html || '').indexOf(marker);
|
|
8014
|
+
if (i < 0) return String(html || ''); // not a full container — treat the text itself as the doc
|
|
8015
|
+
let j = i + marker.length;
|
|
8016
|
+
for (; j < html.length; j++) { const c = html[j]; if (c === '\\') { j++; continue; } if (c === '`') break; }
|
|
8017
|
+
return html.slice(i + marker.length, j).replace(/\\([\s\S])/g, '$1');
|
|
8018
|
+
}
|
|
8019
|
+
function extractAgentEnvelopesFromCarrier(html) {
|
|
8020
|
+
const zone = _agExtractZone(_carrierDoc(html));
|
|
8021
|
+
if (!zone) return [];
|
|
8022
|
+
const out = [];
|
|
8023
|
+
for (const m of zone.matchAll(/<script\s+type="application\/rwa-agent\+json">([\s\S]*?)<\/script>/g)) {
|
|
8024
|
+
let env; try { env = JSON.parse(new TextDecoder().decode(_skFromB64(m[1].trim()))); } catch (_) { continue; }
|
|
8025
|
+
if (env && env.agent && typeof env.agent.role === 'string') out.push(env);
|
|
8026
|
+
}
|
|
8027
|
+
return out;
|
|
8028
|
+
}
|
|
8029
|
+
// Classify a dropped/picked file's text: a carrier .html, a bare envelope JSON, or nothing.
|
|
8030
|
+
function classifyInstallText(text) {
|
|
8031
|
+
const s = String(text || '');
|
|
8032
|
+
let obj = null; try { obj = JSON.parse(s); } catch (_) {}
|
|
8033
|
+
if (obj && typeof obj === 'object') {
|
|
8034
|
+
if (obj.agent || obj.format === 'rwa-agent/1') return { kind: 'json-agent', envelope: obj };
|
|
8035
|
+
if (obj.skill || obj.format === 'rwa-skill/1') return { kind: 'json-skill', envelope: obj };
|
|
8036
|
+
return { kind: 'none' };
|
|
8037
|
+
}
|
|
8038
|
+
const envelopes = extractAgentEnvelopesFromCarrier(s);
|
|
8039
|
+
if (envelopes.length) return { kind: 'agent-carrier', envelopes };
|
|
8040
|
+
return { kind: 'none' };
|
|
8041
|
+
}
|
|
8042
|
+
// Route extracted content to the right consent dialog. Install stays behind the dialog (the trust
|
|
8043
|
+
// anchor); the dialog is fire-and-forget so the drop handler returns immediately. Multiple records
|
|
8044
|
+
// in one carrier are queued (each dialog awaits the previous close).
|
|
8045
|
+
async function routeInstallFromText(text) {
|
|
8046
|
+
const c = classifyInstallText(text);
|
|
8047
|
+
if (c.kind === 'json-agent') showAgentInstallDialog(c.envelope);
|
|
8048
|
+
else if (c.kind === 'json-skill') showSkillInstallDialog(c.envelope);
|
|
8049
|
+
else if (c.kind === 'agent-carrier') { (async () => { for (const env of c.envelopes) { await showAgentInstallDialog(env); } })(); }
|
|
8050
|
+
else if (typeof setStatus === 'function') setStatus('err', 'no installable skill or intelligence found in that file');
|
|
8051
|
+
return c;
|
|
8052
|
+
}
|
|
8053
|
+
async function _readDroppedText(file) {
|
|
8054
|
+
if (file && typeof file.text === 'function') return file.text();
|
|
8055
|
+
return new Promise((res, rej) => { const rd = new FileReader(); rd.onload = () => res(String(rd.result || '')); rd.onerror = rej; rd.readAsText(file); });
|
|
8056
|
+
}
|
|
8057
|
+
// Drop gesture — capture phase, so a carrier is claimed before the Edit-mode image-mount drop.
|
|
8058
|
+
// Acts only on an .html/.htm file; any other drop flows through untouched to existing handlers.
|
|
8059
|
+
// A carrier is a self-contained .html (seed + doc, ~0.6 MB; larger with embedded images); cap the
|
|
8060
|
+
// read so a wildly oversized drop can't be slurped into memory (mirrors the image-ingest size cap).
|
|
8061
|
+
const CARRIER_MAX_BYTES = 32 * 1024 * 1024;
|
|
8062
|
+
async function handleCarrierDrop(e) {
|
|
8063
|
+
const files = Array.from((e && e.dataTransfer && e.dataTransfer.files) || []);
|
|
8064
|
+
const carrier = files.find(f => /text\/html/i.test(f.type || '') || /\.html?$/i.test(f.name || ''));
|
|
8065
|
+
if (!carrier) return; // not a carrier — let the image/other drop handlers run
|
|
8066
|
+
if (e.preventDefault) e.preventDefault();
|
|
8067
|
+
if (e.stopPropagation) e.stopPropagation();
|
|
8068
|
+
if (carrier.size > CARRIER_MAX_BYTES) { if (typeof setStatus === 'function') setStatus('err', 'that file is too large to be an intelligence carrier (' + Math.round(carrier.size / 1048576) + ' MB)'); return; }
|
|
8069
|
+
try { await routeInstallFromText(await _readDroppedText(carrier)); }
|
|
8070
|
+
catch (_) { if (typeof setStatus === 'function') setStatus('err', 'could not read the dropped file'); }
|
|
8071
|
+
}
|
|
8072
|
+
function handleCarrierDragOver(e) {
|
|
8073
|
+
// Let a file drop fire anywhere on the page (a carrier can be dropped onto the document, not only
|
|
8074
|
+
// the edit mount). Idempotent with the mount's own dragover; the drop handler decides whether to claim it.
|
|
8075
|
+
const t = e && e.dataTransfer;
|
|
8076
|
+
if (t && (Array.from(t.items || []).some(i => i.kind === 'file') || Array.from(t.types || []).includes('Files'))) e.preventDefault();
|
|
8077
|
+
}
|
|
8078
|
+
window.addEventListener('dragover', handleCarrierDragOver, true);
|
|
8079
|
+
window.addEventListener('drop', handleCarrierDrop, true);
|
|
8080
|
+
// Automation/test hooks (mirror window.__ingestImageFile).
|
|
8081
|
+
window.__rwaExtractAgentCarrier = extractAgentEnvelopesFromCarrier;
|
|
8082
|
+
window.__rwaClassifyInstallText = classifyInstallText;
|
|
8083
|
+
window.__rwaInstallFromText = routeInstallFromText;
|
|
8084
|
+
window.__rwaHandleCarrierDrop = handleCarrierDrop;
|
|
8085
|
+
|
|
8001
8086
|
// §4/§5a — does a network: host pattern admit a host? Mirror of cli/src/skill-manifest.mjs
|
|
8002
8087
|
// matchNetworkOrigin (keep in step). The bridge's per-call origin check.
|
|
8003
8088
|
function _skMatchNetworkOrigin(pattern, host) {
|