@integrity-labs/agt-cli 0.28.521 → 0.28.522
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/bin/agt.js +4 -4
- package/dist/{chunk-STNEJC5S.js → chunk-4GTDD2I5.js} +161 -1
- package/dist/chunk-4GTDD2I5.js.map +1 -0
- package/dist/{chunk-UAHIRLPO.js → chunk-WIQCLSZY.js} +3 -3
- package/dist/{claude-pair-runtime-PFMWZ66R.js → claude-pair-runtime-7W7LSW73.js} +2 -2
- package/dist/lib/manager-worker.js +10 -10
- package/dist/mcp/direct-chat-channel.js +160 -0
- package/dist/mcp/origami.js +160 -0
- package/dist/mcp/slack-channel.js +160 -0
- package/dist/mcp/telegram-channel.js +160 -0
- package/dist/{persistent-session-DNENZXT4.js → persistent-session-5GMZKV37.js} +2 -2
- package/dist/{responsiveness-probe-V7CP5ML3.js → responsiveness-probe-52IZOP2M.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-STNEJC5S.js.map +0 -1
- /package/dist/{chunk-UAHIRLPO.js.map → chunk-WIQCLSZY.js.map} +0 -0
- /package/dist/{claude-pair-runtime-PFMWZ66R.js.map → claude-pair-runtime-7W7LSW73.js.map} +0 -0
- /package/dist/{persistent-session-DNENZXT4.js.map → persistent-session-5GMZKV37.js.map} +0 -0
- /package/dist/{responsiveness-probe-V7CP5ML3.js.map → responsiveness-probe-52IZOP2M.js.map} +0 -0
|
@@ -42,7 +42,7 @@ import {
|
|
|
42
42
|
resolveConnectivityProbe,
|
|
43
43
|
worseConnectivityOutcome,
|
|
44
44
|
wrapScheduledTaskPrompt
|
|
45
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-4GTDD2I5.js";
|
|
46
46
|
import {
|
|
47
47
|
parsePsRows
|
|
48
48
|
} from "./chunk-XWVM4KPK.js";
|
|
@@ -5317,7 +5317,7 @@ function exchangeFailureKind(err) {
|
|
|
5317
5317
|
}
|
|
5318
5318
|
|
|
5319
5319
|
// src/lib/api-client.ts
|
|
5320
|
-
var agtCliVersion = true ? "0.28.
|
|
5320
|
+
var agtCliVersion = true ? "0.28.522" : "dev";
|
|
5321
5321
|
var lastConfigHash = null;
|
|
5322
5322
|
function setConfigHash(hash) {
|
|
5323
5323
|
lastConfigHash = hash && hash.length > 0 ? hash : null;
|
|
@@ -8629,4 +8629,4 @@ export {
|
|
|
8629
8629
|
managerInstallSystemUnitCommand,
|
|
8630
8630
|
managerUninstallSystemUnitCommand
|
|
8631
8631
|
};
|
|
8632
|
-
//# sourceMappingURL=chunk-
|
|
8632
|
+
//# sourceMappingURL=chunk-WIQCLSZY.js.map
|
|
@@ -100,7 +100,7 @@ async function spawnPairSession(session) {
|
|
|
100
100
|
return { ok: true };
|
|
101
101
|
} catch {
|
|
102
102
|
}
|
|
103
|
-
const { resolveClaudeBinary } = await import("./persistent-session-
|
|
103
|
+
const { resolveClaudeBinary } = await import("./persistent-session-5GMZKV37.js");
|
|
104
104
|
const claudeBin = resolveClaudeBinary();
|
|
105
105
|
const pairEnv = {
|
|
106
106
|
...process.env,
|
|
@@ -373,4 +373,4 @@ export {
|
|
|
373
373
|
startClaudePair,
|
|
374
374
|
submitClaudePairCode
|
|
375
375
|
};
|
|
376
|
-
//# sourceMappingURL=claude-pair-runtime-
|
|
376
|
+
//# sourceMappingURL=claude-pair-runtime-7W7LSW73.js.map
|
|
@@ -53,7 +53,7 @@ import {
|
|
|
53
53
|
safeWriteJsonAtomic,
|
|
54
54
|
setConfigHash,
|
|
55
55
|
tripClass
|
|
56
|
-
} from "../chunk-
|
|
56
|
+
} from "../chunk-WIQCLSZY.js";
|
|
57
57
|
import {
|
|
58
58
|
getProjectDir as getProjectDir2,
|
|
59
59
|
getReadyTasks,
|
|
@@ -177,7 +177,7 @@ import {
|
|
|
177
177
|
toOpencodeModel,
|
|
178
178
|
transcriptActivityAgeSeconds,
|
|
179
179
|
writeEgressAllowlist
|
|
180
|
-
} from "../chunk-
|
|
180
|
+
} from "../chunk-4GTDD2I5.js";
|
|
181
181
|
import {
|
|
182
182
|
reapOrphanChannelMcps
|
|
183
183
|
} from "../chunk-XWVM4KPK.js";
|
|
@@ -10106,7 +10106,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
|
|
|
10106
10106
|
var lastVersionCheckAt = 0;
|
|
10107
10107
|
var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
|
|
10108
10108
|
var lastResponsivenessProbeAt = 0;
|
|
10109
|
-
var agtCliVersion = true ? "0.28.
|
|
10109
|
+
var agtCliVersion = true ? "0.28.522" : "dev";
|
|
10110
10110
|
function resolveBrewPath(execFileSync2) {
|
|
10111
10111
|
try {
|
|
10112
10112
|
const out = execFileSync2("which", ["brew"], { timeout: 5e3 }).toString().trim();
|
|
@@ -11314,7 +11314,7 @@ function flushRestartedAgentDiagnostics(hostId, codeNames) {
|
|
|
11314
11314
|
if (codeNames.length === 0) return;
|
|
11315
11315
|
void (async () => {
|
|
11316
11316
|
try {
|
|
11317
|
-
const { collectDiagnostics } = await import("../persistent-session-
|
|
11317
|
+
const { collectDiagnostics } = await import("../persistent-session-5GMZKV37.js");
|
|
11318
11318
|
await api.post("/host/heartbeat", {
|
|
11319
11319
|
host_id: hostId,
|
|
11320
11320
|
agent_diagnostics: collectDiagnostics(codeNames, quarantineEntriesFor, claudeMdSizeFor)
|
|
@@ -11421,7 +11421,7 @@ async function pollCycle() {
|
|
|
11421
11421
|
}
|
|
11422
11422
|
try {
|
|
11423
11423
|
const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
|
|
11424
|
-
const { collectDiagnostics } = await import("../persistent-session-
|
|
11424
|
+
const { collectDiagnostics } = await import("../persistent-session-5GMZKV37.js");
|
|
11425
11425
|
const diagCodeNames = [...agentState.persistentSessionAgents];
|
|
11426
11426
|
const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames, quarantineEntriesFor, claudeMdSizeFor) : void 0;
|
|
11427
11427
|
let tailscaleHostname;
|
|
@@ -11536,7 +11536,7 @@ async function pollCycle() {
|
|
|
11536
11536
|
collectResponsivenessProbes,
|
|
11537
11537
|
collectPanelessActivityProbes,
|
|
11538
11538
|
getResponsivenessIntervalMs
|
|
11539
|
-
} = await import("../responsiveness-probe-
|
|
11539
|
+
} = await import("../responsiveness-probe-52IZOP2M.js");
|
|
11540
11540
|
const probeIntervalMs = getResponsivenessIntervalMs();
|
|
11541
11541
|
if (now - lastResponsivenessProbeAt > probeIntervalMs) {
|
|
11542
11542
|
const probeCodeNames = [...agentState.persistentSessionAgents];
|
|
@@ -11600,7 +11600,7 @@ async function pollCycle() {
|
|
|
11600
11600
|
collectResponsivenessProbes,
|
|
11601
11601
|
livePendingInboundOldestAgeSeconds,
|
|
11602
11602
|
parkPendingInbound
|
|
11603
|
-
} = await import("../responsiveness-probe-
|
|
11603
|
+
} = await import("../responsiveness-probe-52IZOP2M.js");
|
|
11604
11604
|
const { getProjectDir: wedgeProjectDir } = await import("../scheduler-engine-NDP36U7O.js");
|
|
11605
11605
|
const wedgeNow = /* @__PURE__ */ new Date();
|
|
11606
11606
|
const liveAgents = agentState.persistentSessionAgents;
|
|
@@ -15108,7 +15108,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
|
|
|
15108
15108
|
void api.post("/host/restart-ack", { host_id: hostId, agent_id: agentId, restart_requested_at: requestedAt }).catch((err) => log(`[restart-lane] ack failed for '${codeName}': ${err.message}`));
|
|
15109
15109
|
void (async () => {
|
|
15110
15110
|
try {
|
|
15111
|
-
const { collectDiagnostics } = await import("../persistent-session-
|
|
15111
|
+
const { collectDiagnostics } = await import("../persistent-session-5GMZKV37.js");
|
|
15112
15112
|
await api.post("/host/heartbeat", {
|
|
15113
15113
|
host_id: hostId,
|
|
15114
15114
|
agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor)
|
|
@@ -15158,7 +15158,7 @@ async function respawnAgentAfterMcpStop(codeName, reason) {
|
|
|
15158
15158
|
}
|
|
15159
15159
|
try {
|
|
15160
15160
|
const hostId = await getHostId();
|
|
15161
|
-
const { collectDiagnostics } = await import("../persistent-session-
|
|
15161
|
+
const { collectDiagnostics } = await import("../persistent-session-5GMZKV37.js");
|
|
15162
15162
|
await api.post("/host/heartbeat", {
|
|
15163
15163
|
host_id: hostId,
|
|
15164
15164
|
agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor)
|
|
@@ -15676,7 +15676,7 @@ async function processClaudePairSessions(agents) {
|
|
|
15676
15676
|
killPairSession,
|
|
15677
15677
|
pairTmuxSession,
|
|
15678
15678
|
finalizeClaudePairOnboarding
|
|
15679
|
-
} = await import("../claude-pair-runtime-
|
|
15679
|
+
} = await import("../claude-pair-runtime-7W7LSW73.js");
|
|
15680
15680
|
for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
|
|
15681
15681
|
log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
|
|
15682
15682
|
const killed = await killPairSession(pairTmuxSession(pairId));
|
|
@@ -32140,6 +32140,11 @@ var MARKUP_BRIDGE_SCRIPT = `<script>(function(){
|
|
|
32140
32140
|
var commentEnabled = false; // armed when the viewer may comment (ENG-6847 right-click)
|
|
32141
32141
|
var editing = null; // the element currently in edit mode
|
|
32142
32142
|
var bar = null; // the Save/Cancel toolbar
|
|
32143
|
+
// ENG-8477: the viewer has explicitly turned editing ON from the shell. Only
|
|
32144
|
+
// then does the bridge look underneath the artefact's own overlays. See the
|
|
32145
|
+
// long note on the window-capture click handler for why this is a mode and
|
|
32146
|
+
// not just always-on.
|
|
32147
|
+
var editMode = false;
|
|
32143
32148
|
|
|
32144
32149
|
// Element-child indices from <body> down to el. Counts ELEMENT children only
|
|
32145
32150
|
// (children, not childNodes), matching how the server walks source_html; our
|
|
@@ -32194,6 +32199,55 @@ var MARKUP_BRIDGE_SCRIPT = `<script>(function(){
|
|
|
32194
32199
|
return null;
|
|
32195
32200
|
}catch(e){ return null; }
|
|
32196
32201
|
}
|
|
32202
|
+
// ENG-8477: the topmost element under the pointer that we could actually edit,
|
|
32203
|
+
// looking THROUGH anything the artefact has laid over its own content.
|
|
32204
|
+
//
|
|
32205
|
+
// elementsFromPoint returns the full hit stack, front to back. We walk it from
|
|
32206
|
+
// the front and take the first genuinely editable element, skipping our own
|
|
32207
|
+
// injected UI. An artefact overlay is skipped for free: it is an empty div, so
|
|
32208
|
+
// editable() rejects it on the text check and we keep walking.
|
|
32209
|
+
//
|
|
32210
|
+
// Returns null when there is nothing editable under the pointer at all, which
|
|
32211
|
+
// is the signal to leave the click completely alone.
|
|
32212
|
+
function editableAtPoint(x,y){
|
|
32213
|
+
var stack;
|
|
32214
|
+
try{ stack=document.elementsFromPoint(x,y)||[]; }catch(e){ return null; }
|
|
32215
|
+
for(var i=0;i<stack.length;i++){
|
|
32216
|
+
var el=stack[i];
|
|
32217
|
+
if(!el || el.nodeType!==1) continue;
|
|
32218
|
+
if(el.closest && el.closest('[data-al-noedit]')) continue; // our toolbar, not content
|
|
32219
|
+
if(editable(el)||inlineOnlyEditable(el)) return el;
|
|
32220
|
+
}
|
|
32221
|
+
return null;
|
|
32222
|
+
}
|
|
32223
|
+
// The caret probe (caretRangeFromPoint) reports on the TOPMOST element at the
|
|
32224
|
+
// point, so an overlay swallows it exactly as it swallows the click - it hands
|
|
32225
|
+
// back the overlay div, not the text underneath. Neutralise everything stacked
|
|
32226
|
+
// above the target for the length of the probe, then put it back. The restore
|
|
32227
|
+
// is in a finally and runs before the browser can paint, so nothing flickers
|
|
32228
|
+
// and no artefact state is left modified.
|
|
32229
|
+
// This re-queries elementsFromPoint rather than reusing the caller's stack, so
|
|
32230
|
+
// target is NOT guaranteed to still be in it. Find target's index first and
|
|
32231
|
+
// mute only the prefix in front of it: a not-found target must fall back to the
|
|
32232
|
+
// plain probe, because muting the whole stack would neutralise target and its
|
|
32233
|
+
// ancestors too - a wider style mutation than intended, for a probe whose
|
|
32234
|
+
// result the caller then rejects anyway.
|
|
32235
|
+
function textNodeAtPointThrough(x,y,target){
|
|
32236
|
+
var stack;
|
|
32237
|
+
try{ stack=document.elementsFromPoint(x,y)||[]; }catch(e){ return textNodeAtPoint(x,y); }
|
|
32238
|
+
var cut=-1, i;
|
|
32239
|
+
for(i=0;i<stack.length;i++){ if(stack[i]===target){ cut=i; break; } }
|
|
32240
|
+
if(cut<0) return textNodeAtPoint(x,y);
|
|
32241
|
+
var muted=[];
|
|
32242
|
+
for(i=0;i<cut;i++){
|
|
32243
|
+
muted.push([stack[i], stack[i].style ? stack[i].style.pointerEvents : '']);
|
|
32244
|
+
try{ stack[i].style.pointerEvents='none'; }catch(e){}
|
|
32245
|
+
}
|
|
32246
|
+
try{ return textNodeAtPoint(x,y); }
|
|
32247
|
+
finally{
|
|
32248
|
+
for(i=0;i<muted.length;i++){ try{ muted[i][0].style.pointerEvents=muted[i][1]||''; }catch(e){} }
|
|
32249
|
+
}
|
|
32250
|
+
}
|
|
32197
32251
|
// Index of a text node among its parent's child TEXT nodes, in order - the same
|
|
32198
32252
|
// counting the server uses to re-locate it in source_html (ENG-6856).
|
|
32199
32253
|
function textIndexOf(container, tn){
|
|
@@ -32303,6 +32357,105 @@ var MARKUP_BRIDGE_SCRIPT = `<script>(function(){
|
|
|
32303
32357
|
e.preventDefault(); e.stopPropagation(); startEditTextNode(tn, el);
|
|
32304
32358
|
}
|
|
32305
32359
|
}, true);
|
|
32360
|
+
// ENG-8477: reach content the artefact covers with its OWN overlay.
|
|
32361
|
+
//
|
|
32362
|
+
// A deck built from the canonical template lays two full-viewport click zones
|
|
32363
|
+
// over its slides (.clickzone, position:fixed, z-index:40) to page forward and
|
|
32364
|
+
// back. The template's own comment says it plainly: "the click zones sit above
|
|
32365
|
+
// slide content by design, so any interactive element inside a slide needs
|
|
32366
|
+
// position:relative + a higher z-index to stay clickable". Slide TEXT is not an
|
|
32367
|
+
// interactive element and never gets one.
|
|
32368
|
+
//
|
|
32369
|
+
// So every click a viewer aimed at a paragraph landed on #zone-prev/#zone-next.
|
|
32370
|
+
// The handler above read e.target, got an empty div, editable() rejected it on
|
|
32371
|
+
// the text check, and no editor opened - while the zone's own handler paged the
|
|
32372
|
+
// deck. A single-page artefact has no zones and the identical bridge works
|
|
32373
|
+
// perfectly on it, which is precisely why editing "works in web page formats
|
|
32374
|
+
// but not decks". Verified on real published content, not just the template.
|
|
32375
|
+
//
|
|
32376
|
+
// Why a MODE rather than always-on. One press cannot mean both "page the deck"
|
|
32377
|
+
// and "edit this text". The zones are the deck's primary navigation, so
|
|
32378
|
+
// silently stealing clicks from them would trade one broken gesture for
|
|
32379
|
+
// another. The shell gives an armed viewer an explicit Edit-text toggle; until
|
|
32380
|
+
// they turn it on, every line below is inert and the artefact behaves exactly
|
|
32381
|
+
// as it does today. Anonymous viewers never arm at all.
|
|
32382
|
+
//
|
|
32383
|
+
// Why window + capture. Same phase argument as ENG-8500: the artefact's script
|
|
32384
|
+
// is appended before the bridge, so registration order cannot be won, but the
|
|
32385
|
+
// capture path runs window -> document -> ... -> target and therefore beats a
|
|
32386
|
+
// handler bound to the zone itself no matter when it was registered.
|
|
32387
|
+
// stopImmediatePropagation then keeps the deck from also paging.
|
|
32388
|
+
//
|
|
32389
|
+
// Deliberately general: nothing here knows about .clickzone or any class name.
|
|
32390
|
+
// It fixes any artefact that covers its own content.
|
|
32391
|
+
window.addEventListener('click', function(e){
|
|
32392
|
+
if(!editEnabled || !editMode || editing) return;
|
|
32393
|
+
var sel=document.getSelection(); if(sel && String(sel).trim()) return; // selection => comment flow
|
|
32394
|
+
var t=e.target;
|
|
32395
|
+
// Our own toolbar (Save/Cancel) must keep its clicks.
|
|
32396
|
+
if(t && t.closest && t.closest('[data-al-noedit]')) return;
|
|
32397
|
+
// Already directly on editable content: the document-level handler above
|
|
32398
|
+
// covers it, and duplicating the work here would start the edit twice.
|
|
32399
|
+
if(editable(t)||inlineOnlyEditable(t)) return;
|
|
32400
|
+
var el=editableAtPoint(e.clientX, e.clientY);
|
|
32401
|
+
// Nothing editable under the pointer - leave the click completely alone so
|
|
32402
|
+
// click-to-page still works while the viewer is moving between slides.
|
|
32403
|
+
if(!el) return;
|
|
32404
|
+
// Suppress ONLY once an edit is actually starting. Suppressing up front left
|
|
32405
|
+
// the inline-only fallback below as a dead click: no editor opened AND the
|
|
32406
|
+
// deck could not page, because the event was already stopped.
|
|
32407
|
+
if(editable(el)){ e.preventDefault(); e.stopImmediatePropagation(); startEdit(el); return; }
|
|
32408
|
+
var tn=textNodeAtPointThrough(e.clientX, e.clientY, el);
|
|
32409
|
+
if(tn && tn.parentElement===el && (tn.nodeValue||'').trim()){
|
|
32410
|
+
e.preventDefault(); e.stopImmediatePropagation(); startEditTextNode(tn, el); return;
|
|
32411
|
+
}
|
|
32412
|
+
// An inline-only container whose exact text run we could not resolve (no
|
|
32413
|
+
// caret API, or the point fell between runs). Editing the whole container
|
|
32414
|
+
// would flatten its nested markup, so leave the click to the artefact and
|
|
32415
|
+
// let it page as it normally would.
|
|
32416
|
+
}, true);
|
|
32417
|
+
// ENG-8477: the same deck template pulls focus back to the document on every
|
|
32418
|
+
// pointer press, to keep its arrow keys working when the iframe loses focus:
|
|
32419
|
+
//
|
|
32420
|
+
// function grabFocus(){ try{ window.focus(); document.body.focus(); }catch(e){} }
|
|
32421
|
+
// addEventListener('pointerdown', grabFocus);
|
|
32422
|
+
//
|
|
32423
|
+
// A bare addEventListener at artefact top level is window + bubble phase, so a
|
|
32424
|
+
// window CAPTURE listener still gets there first. Without this guard, clicking
|
|
32425
|
+
// into an open editor to place the caret hands focus straight to <body> and the
|
|
32426
|
+
// viewer cannot type - a second, independent breaker that would have survived
|
|
32427
|
+
// the overlay fix on its own.
|
|
32428
|
+
//
|
|
32429
|
+
// Scoped as tightly as it can be: only while an edit is open, and only for a
|
|
32430
|
+
// press that lands inside the editor. A press anywhere else is the viewer
|
|
32431
|
+
// leaving, and the artefact keeps it.
|
|
32432
|
+
window.addEventListener('pointerdown', function(e){
|
|
32433
|
+
if(!editing) return;
|
|
32434
|
+
var t=e.target;
|
|
32435
|
+
if(t!==editing && !(editing.contains && t && t.nodeType && editing.contains(t))) return;
|
|
32436
|
+
e.stopImmediatePropagation();
|
|
32437
|
+
}, true);
|
|
32438
|
+
// ENG-8477: the hover affordance has the same blind spot as the click did -
|
|
32439
|
+
// mouseover reports the overlay, so a viewer in edit mode would get no cue that
|
|
32440
|
+
// slide text can be edited at all. Probing the stack on every mousemove would
|
|
32441
|
+
// be wasteful, so this only runs in edit mode, only when the direct target is
|
|
32442
|
+
// not already editable (that case the mouseover handler above still covers),
|
|
32443
|
+
// and no more than once per ~80ms.
|
|
32444
|
+
var hoverProbeAt=0, hoverEl=null;
|
|
32445
|
+
function clearDeepHover(){
|
|
32446
|
+
if(hoverEl && hoverEl!==editing && hoverEl.__alHover){ try{ hoverEl.style.outline=''; }catch(e){} hoverEl.__alHover=0; }
|
|
32447
|
+
hoverEl=null;
|
|
32448
|
+
}
|
|
32449
|
+
document.addEventListener('mousemove', function(e){
|
|
32450
|
+
if(!editEnabled || !editMode || editing){ clearDeepHover(); return; }
|
|
32451
|
+
var t=e.target;
|
|
32452
|
+
if(editable(t)||inlineOnlyEditable(t)){ clearDeepHover(); return; }
|
|
32453
|
+
var now=Date.now(); if(now-hoverProbeAt<80) return; hoverProbeAt=now;
|
|
32454
|
+
var el=editableAtPoint(e.clientX, e.clientY);
|
|
32455
|
+
if(el===hoverEl) return;
|
|
32456
|
+
clearDeepHover();
|
|
32457
|
+
if(el){ try{ el.style.outline=el.style.outline||'1px dashed rgba(110,231,183,.6)'; }catch(e){} el.__alHover=1; hoverEl=el; }
|
|
32458
|
+
});
|
|
32306
32459
|
// ENG-8500: while the inline editor is focused, the artefact's OWN keyboard
|
|
32307
32460
|
// handlers must not see the keystroke.
|
|
32308
32461
|
//
|
|
@@ -32394,6 +32547,13 @@ var MARKUP_BRIDGE_SCRIPT = `<script>(function(){
|
|
|
32394
32547
|
var d=e.data; if(!d || d['${MARKUP_CONTROL_MARKER}']!==true) return;
|
|
32395
32548
|
if(d.type==='enable-edit'){ editEnabled=true; }
|
|
32396
32549
|
else if(d.type==='enable-comment'){ commentEnabled=true; }
|
|
32550
|
+
// ENG-8477: the viewer toggled Edit text in the shell. Turning it OFF must
|
|
32551
|
+
// also close anything open and drop the hover cue, or the artefact is left
|
|
32552
|
+
// wearing our outlines with no way to clear them.
|
|
32553
|
+
else if(d.type==='set-edit-mode'){
|
|
32554
|
+
editMode = !!d.on;
|
|
32555
|
+
if(!editMode){ if(editing) endEdit(false); clearDeepHover(); }
|
|
32556
|
+
}
|
|
32397
32557
|
else if(d.type==='edit-result'){
|
|
32398
32558
|
if(d.ok){ /* republish hot-swaps the iframe; nothing to do */ }
|
|
32399
32559
|
else { /* leave the (now non-editable) text; the published version is the source of truth */ }
|
package/dist/mcp/origami.js
CHANGED
|
@@ -38478,6 +38478,11 @@ var MARKUP_BRIDGE_SCRIPT = `<script>(function(){
|
|
|
38478
38478
|
var commentEnabled = false; // armed when the viewer may comment (ENG-6847 right-click)
|
|
38479
38479
|
var editing = null; // the element currently in edit mode
|
|
38480
38480
|
var bar = null; // the Save/Cancel toolbar
|
|
38481
|
+
// ENG-8477: the viewer has explicitly turned editing ON from the shell. Only
|
|
38482
|
+
// then does the bridge look underneath the artefact's own overlays. See the
|
|
38483
|
+
// long note on the window-capture click handler for why this is a mode and
|
|
38484
|
+
// not just always-on.
|
|
38485
|
+
var editMode = false;
|
|
38481
38486
|
|
|
38482
38487
|
// Element-child indices from <body> down to el. Counts ELEMENT children only
|
|
38483
38488
|
// (children, not childNodes), matching how the server walks source_html; our
|
|
@@ -38532,6 +38537,55 @@ var MARKUP_BRIDGE_SCRIPT = `<script>(function(){
|
|
|
38532
38537
|
return null;
|
|
38533
38538
|
}catch(e){ return null; }
|
|
38534
38539
|
}
|
|
38540
|
+
// ENG-8477: the topmost element under the pointer that we could actually edit,
|
|
38541
|
+
// looking THROUGH anything the artefact has laid over its own content.
|
|
38542
|
+
//
|
|
38543
|
+
// elementsFromPoint returns the full hit stack, front to back. We walk it from
|
|
38544
|
+
// the front and take the first genuinely editable element, skipping our own
|
|
38545
|
+
// injected UI. An artefact overlay is skipped for free: it is an empty div, so
|
|
38546
|
+
// editable() rejects it on the text check and we keep walking.
|
|
38547
|
+
//
|
|
38548
|
+
// Returns null when there is nothing editable under the pointer at all, which
|
|
38549
|
+
// is the signal to leave the click completely alone.
|
|
38550
|
+
function editableAtPoint(x,y){
|
|
38551
|
+
var stack;
|
|
38552
|
+
try{ stack=document.elementsFromPoint(x,y)||[]; }catch(e){ return null; }
|
|
38553
|
+
for(var i=0;i<stack.length;i++){
|
|
38554
|
+
var el=stack[i];
|
|
38555
|
+
if(!el || el.nodeType!==1) continue;
|
|
38556
|
+
if(el.closest && el.closest('[data-al-noedit]')) continue; // our toolbar, not content
|
|
38557
|
+
if(editable(el)||inlineOnlyEditable(el)) return el;
|
|
38558
|
+
}
|
|
38559
|
+
return null;
|
|
38560
|
+
}
|
|
38561
|
+
// The caret probe (caretRangeFromPoint) reports on the TOPMOST element at the
|
|
38562
|
+
// point, so an overlay swallows it exactly as it swallows the click - it hands
|
|
38563
|
+
// back the overlay div, not the text underneath. Neutralise everything stacked
|
|
38564
|
+
// above the target for the length of the probe, then put it back. The restore
|
|
38565
|
+
// is in a finally and runs before the browser can paint, so nothing flickers
|
|
38566
|
+
// and no artefact state is left modified.
|
|
38567
|
+
// This re-queries elementsFromPoint rather than reusing the caller's stack, so
|
|
38568
|
+
// target is NOT guaranteed to still be in it. Find target's index first and
|
|
38569
|
+
// mute only the prefix in front of it: a not-found target must fall back to the
|
|
38570
|
+
// plain probe, because muting the whole stack would neutralise target and its
|
|
38571
|
+
// ancestors too - a wider style mutation than intended, for a probe whose
|
|
38572
|
+
// result the caller then rejects anyway.
|
|
38573
|
+
function textNodeAtPointThrough(x,y,target){
|
|
38574
|
+
var stack;
|
|
38575
|
+
try{ stack=document.elementsFromPoint(x,y)||[]; }catch(e){ return textNodeAtPoint(x,y); }
|
|
38576
|
+
var cut=-1, i;
|
|
38577
|
+
for(i=0;i<stack.length;i++){ if(stack[i]===target){ cut=i; break; } }
|
|
38578
|
+
if(cut<0) return textNodeAtPoint(x,y);
|
|
38579
|
+
var muted=[];
|
|
38580
|
+
for(i=0;i<cut;i++){
|
|
38581
|
+
muted.push([stack[i], stack[i].style ? stack[i].style.pointerEvents : '']);
|
|
38582
|
+
try{ stack[i].style.pointerEvents='none'; }catch(e){}
|
|
38583
|
+
}
|
|
38584
|
+
try{ return textNodeAtPoint(x,y); }
|
|
38585
|
+
finally{
|
|
38586
|
+
for(i=0;i<muted.length;i++){ try{ muted[i][0].style.pointerEvents=muted[i][1]||''; }catch(e){} }
|
|
38587
|
+
}
|
|
38588
|
+
}
|
|
38535
38589
|
// Index of a text node among its parent's child TEXT nodes, in order - the same
|
|
38536
38590
|
// counting the server uses to re-locate it in source_html (ENG-6856).
|
|
38537
38591
|
function textIndexOf(container, tn){
|
|
@@ -38641,6 +38695,105 @@ var MARKUP_BRIDGE_SCRIPT = `<script>(function(){
|
|
|
38641
38695
|
e.preventDefault(); e.stopPropagation(); startEditTextNode(tn, el);
|
|
38642
38696
|
}
|
|
38643
38697
|
}, true);
|
|
38698
|
+
// ENG-8477: reach content the artefact covers with its OWN overlay.
|
|
38699
|
+
//
|
|
38700
|
+
// A deck built from the canonical template lays two full-viewport click zones
|
|
38701
|
+
// over its slides (.clickzone, position:fixed, z-index:40) to page forward and
|
|
38702
|
+
// back. The template's own comment says it plainly: "the click zones sit above
|
|
38703
|
+
// slide content by design, so any interactive element inside a slide needs
|
|
38704
|
+
// position:relative + a higher z-index to stay clickable". Slide TEXT is not an
|
|
38705
|
+
// interactive element and never gets one.
|
|
38706
|
+
//
|
|
38707
|
+
// So every click a viewer aimed at a paragraph landed on #zone-prev/#zone-next.
|
|
38708
|
+
// The handler above read e.target, got an empty div, editable() rejected it on
|
|
38709
|
+
// the text check, and no editor opened - while the zone's own handler paged the
|
|
38710
|
+
// deck. A single-page artefact has no zones and the identical bridge works
|
|
38711
|
+
// perfectly on it, which is precisely why editing "works in web page formats
|
|
38712
|
+
// but not decks". Verified on real published content, not just the template.
|
|
38713
|
+
//
|
|
38714
|
+
// Why a MODE rather than always-on. One press cannot mean both "page the deck"
|
|
38715
|
+
// and "edit this text". The zones are the deck's primary navigation, so
|
|
38716
|
+
// silently stealing clicks from them would trade one broken gesture for
|
|
38717
|
+
// another. The shell gives an armed viewer an explicit Edit-text toggle; until
|
|
38718
|
+
// they turn it on, every line below is inert and the artefact behaves exactly
|
|
38719
|
+
// as it does today. Anonymous viewers never arm at all.
|
|
38720
|
+
//
|
|
38721
|
+
// Why window + capture. Same phase argument as ENG-8500: the artefact's script
|
|
38722
|
+
// is appended before the bridge, so registration order cannot be won, but the
|
|
38723
|
+
// capture path runs window -> document -> ... -> target and therefore beats a
|
|
38724
|
+
// handler bound to the zone itself no matter when it was registered.
|
|
38725
|
+
// stopImmediatePropagation then keeps the deck from also paging.
|
|
38726
|
+
//
|
|
38727
|
+
// Deliberately general: nothing here knows about .clickzone or any class name.
|
|
38728
|
+
// It fixes any artefact that covers its own content.
|
|
38729
|
+
window.addEventListener('click', function(e){
|
|
38730
|
+
if(!editEnabled || !editMode || editing) return;
|
|
38731
|
+
var sel=document.getSelection(); if(sel && String(sel).trim()) return; // selection => comment flow
|
|
38732
|
+
var t=e.target;
|
|
38733
|
+
// Our own toolbar (Save/Cancel) must keep its clicks.
|
|
38734
|
+
if(t && t.closest && t.closest('[data-al-noedit]')) return;
|
|
38735
|
+
// Already directly on editable content: the document-level handler above
|
|
38736
|
+
// covers it, and duplicating the work here would start the edit twice.
|
|
38737
|
+
if(editable(t)||inlineOnlyEditable(t)) return;
|
|
38738
|
+
var el=editableAtPoint(e.clientX, e.clientY);
|
|
38739
|
+
// Nothing editable under the pointer - leave the click completely alone so
|
|
38740
|
+
// click-to-page still works while the viewer is moving between slides.
|
|
38741
|
+
if(!el) return;
|
|
38742
|
+
// Suppress ONLY once an edit is actually starting. Suppressing up front left
|
|
38743
|
+
// the inline-only fallback below as a dead click: no editor opened AND the
|
|
38744
|
+
// deck could not page, because the event was already stopped.
|
|
38745
|
+
if(editable(el)){ e.preventDefault(); e.stopImmediatePropagation(); startEdit(el); return; }
|
|
38746
|
+
var tn=textNodeAtPointThrough(e.clientX, e.clientY, el);
|
|
38747
|
+
if(tn && tn.parentElement===el && (tn.nodeValue||'').trim()){
|
|
38748
|
+
e.preventDefault(); e.stopImmediatePropagation(); startEditTextNode(tn, el); return;
|
|
38749
|
+
}
|
|
38750
|
+
// An inline-only container whose exact text run we could not resolve (no
|
|
38751
|
+
// caret API, or the point fell between runs). Editing the whole container
|
|
38752
|
+
// would flatten its nested markup, so leave the click to the artefact and
|
|
38753
|
+
// let it page as it normally would.
|
|
38754
|
+
}, true);
|
|
38755
|
+
// ENG-8477: the same deck template pulls focus back to the document on every
|
|
38756
|
+
// pointer press, to keep its arrow keys working when the iframe loses focus:
|
|
38757
|
+
//
|
|
38758
|
+
// function grabFocus(){ try{ window.focus(); document.body.focus(); }catch(e){} }
|
|
38759
|
+
// addEventListener('pointerdown', grabFocus);
|
|
38760
|
+
//
|
|
38761
|
+
// A bare addEventListener at artefact top level is window + bubble phase, so a
|
|
38762
|
+
// window CAPTURE listener still gets there first. Without this guard, clicking
|
|
38763
|
+
// into an open editor to place the caret hands focus straight to <body> and the
|
|
38764
|
+
// viewer cannot type - a second, independent breaker that would have survived
|
|
38765
|
+
// the overlay fix on its own.
|
|
38766
|
+
//
|
|
38767
|
+
// Scoped as tightly as it can be: only while an edit is open, and only for a
|
|
38768
|
+
// press that lands inside the editor. A press anywhere else is the viewer
|
|
38769
|
+
// leaving, and the artefact keeps it.
|
|
38770
|
+
window.addEventListener('pointerdown', function(e){
|
|
38771
|
+
if(!editing) return;
|
|
38772
|
+
var t=e.target;
|
|
38773
|
+
if(t!==editing && !(editing.contains && t && t.nodeType && editing.contains(t))) return;
|
|
38774
|
+
e.stopImmediatePropagation();
|
|
38775
|
+
}, true);
|
|
38776
|
+
// ENG-8477: the hover affordance has the same blind spot as the click did -
|
|
38777
|
+
// mouseover reports the overlay, so a viewer in edit mode would get no cue that
|
|
38778
|
+
// slide text can be edited at all. Probing the stack on every mousemove would
|
|
38779
|
+
// be wasteful, so this only runs in edit mode, only when the direct target is
|
|
38780
|
+
// not already editable (that case the mouseover handler above still covers),
|
|
38781
|
+
// and no more than once per ~80ms.
|
|
38782
|
+
var hoverProbeAt=0, hoverEl=null;
|
|
38783
|
+
function clearDeepHover(){
|
|
38784
|
+
if(hoverEl && hoverEl!==editing && hoverEl.__alHover){ try{ hoverEl.style.outline=''; }catch(e){} hoverEl.__alHover=0; }
|
|
38785
|
+
hoverEl=null;
|
|
38786
|
+
}
|
|
38787
|
+
document.addEventListener('mousemove', function(e){
|
|
38788
|
+
if(!editEnabled || !editMode || editing){ clearDeepHover(); return; }
|
|
38789
|
+
var t=e.target;
|
|
38790
|
+
if(editable(t)||inlineOnlyEditable(t)){ clearDeepHover(); return; }
|
|
38791
|
+
var now=Date.now(); if(now-hoverProbeAt<80) return; hoverProbeAt=now;
|
|
38792
|
+
var el=editableAtPoint(e.clientX, e.clientY);
|
|
38793
|
+
if(el===hoverEl) return;
|
|
38794
|
+
clearDeepHover();
|
|
38795
|
+
if(el){ try{ el.style.outline=el.style.outline||'1px dashed rgba(110,231,183,.6)'; }catch(e){} el.__alHover=1; hoverEl=el; }
|
|
38796
|
+
});
|
|
38644
38797
|
// ENG-8500: while the inline editor is focused, the artefact's OWN keyboard
|
|
38645
38798
|
// handlers must not see the keystroke.
|
|
38646
38799
|
//
|
|
@@ -38732,6 +38885,13 @@ var MARKUP_BRIDGE_SCRIPT = `<script>(function(){
|
|
|
38732
38885
|
var d=e.data; if(!d || d['${MARKUP_CONTROL_MARKER}']!==true) return;
|
|
38733
38886
|
if(d.type==='enable-edit'){ editEnabled=true; }
|
|
38734
38887
|
else if(d.type==='enable-comment'){ commentEnabled=true; }
|
|
38888
|
+
// ENG-8477: the viewer toggled Edit text in the shell. Turning it OFF must
|
|
38889
|
+
// also close anything open and drop the hover cue, or the artefact is left
|
|
38890
|
+
// wearing our outlines with no way to clear them.
|
|
38891
|
+
else if(d.type==='set-edit-mode'){
|
|
38892
|
+
editMode = !!d.on;
|
|
38893
|
+
if(!editMode){ if(editing) endEdit(false); clearDeepHover(); }
|
|
38894
|
+
}
|
|
38735
38895
|
else if(d.type==='edit-result'){
|
|
38736
38896
|
if(d.ok){ /* republish hot-swaps the iframe; nothing to do */ }
|
|
38737
38897
|
else { /* leave the (now non-editable) text; the published version is the source of truth */ }
|