@integrity-labs/agt-cli 0.28.678 → 0.28.680

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.
@@ -17,7 +17,7 @@ import {
17
17
  rotateDailySession,
18
18
  sessionFileExists,
19
19
  todayLocalIso
20
- } from "./chunk-5DHJE2G7.js";
20
+ } from "./chunk-OOFJUWMT.js";
21
21
  import {
22
22
  reapOrphanChannelMcps
23
23
  } from "./chunk-XWVM4KPK.js";
@@ -4531,4 +4531,4 @@ export {
4531
4531
  stopAllSessionsAndWait,
4532
4532
  getProjectDir
4533
4533
  };
4534
- //# sourceMappingURL=chunk-LTOGVWUR.js.map
4534
+ //# sourceMappingURL=chunk-ZKNKHAHX.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-EZEYH3PM.js");
103
+ const { resolveClaudeBinary } = await import("./persistent-session-OQ7MFVEH.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-X6CWJNW2.js.map
376
+ //# sourceMappingURL=claude-pair-runtime-HPCXQDVY.js.map
@@ -55,7 +55,7 @@ import {
55
55
  setConfigHash,
56
56
  setSecretFileTmpfsBacking,
57
57
  tripClass
58
- } from "../chunk-3PCP5NT2.js";
58
+ } from "../chunk-4JTDWOBW.js";
59
59
  import {
60
60
  getProjectDir as getProjectDir2,
61
61
  getReadyTasks,
@@ -113,7 +113,7 @@ import {
113
113
  takeZombieDetection,
114
114
  toOpencodeModel,
115
115
  writeEgressAllowlist
116
- } from "../chunk-LTOGVWUR.js";
116
+ } from "../chunk-ZKNKHAHX.js";
117
117
  import {
118
118
  ACCOUNT_ENFORCEMENT_MARKER_FILENAME,
119
119
  AnchorSessionClient,
@@ -194,7 +194,7 @@ import {
194
194
  subagentActivityAgeSeconds,
195
195
  sumTranscriptUsageInWindow,
196
196
  transcriptActivityAgeSeconds
197
- } from "../chunk-5DHJE2G7.js";
197
+ } from "../chunk-OOFJUWMT.js";
198
198
  import {
199
199
  reapOrphanChannelMcps
200
200
  } from "../chunk-XWVM4KPK.js";
@@ -11712,7 +11712,7 @@ var pendingDayRolloverReset = /* @__PURE__ */ new Set();
11712
11712
  var dayRolloverInboundHold = /* @__PURE__ */ new Map();
11713
11713
  var INBOUND_HOLD_EPISODE_GAP_MS = 12e4;
11714
11714
  async function channelInboundActivityAgeSecondsFor(codeName) {
11715
- const { newestPendingInboundActivityMtimeMs } = await import("../responsiveness-probe-VS6GODYP.js");
11715
+ const { newestPendingInboundActivityMtimeMs } = await import("../responsiveness-probe-MDL53OT2.js");
11716
11716
  const newest = newestPendingInboundActivityMtimeMs(dirname10(paneLogPath(codeName)));
11717
11717
  if (newest === null) return null;
11718
11718
  return Math.max(0, Math.floor((Date.now() - newest) / 1e3));
@@ -12360,7 +12360,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
12360
12360
  var lastVersionCheckAt = 0;
12361
12361
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
12362
12362
  var lastResponsivenessProbeAt = 0;
12363
- var agtCliVersion = true ? "0.28.678" : "dev";
12363
+ var agtCliVersion = true ? "0.28.680" : "dev";
12364
12364
  function resolveBrewPath(execFileSync3) {
12365
12365
  try {
12366
12366
  const out = execFileSync3("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -13821,7 +13821,7 @@ function flushRestartedAgentDiagnostics(hostId, codeNames) {
13821
13821
  if (codeNames.length === 0) return;
13822
13822
  void (async () => {
13823
13823
  try {
13824
- const { collectDiagnostics } = await import("../persistent-session-EZEYH3PM.js");
13824
+ const { collectDiagnostics } = await import("../persistent-session-OQ7MFVEH.js");
13825
13825
  await api.post("/host/heartbeat", {
13826
13826
  host_id: hostId,
13827
13827
  agent_diagnostics: collectDiagnostics(codeNames, quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor)
@@ -13938,7 +13938,7 @@ async function pollCycleInner() {
13938
13938
  }
13939
13939
  try {
13940
13940
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
13941
- const { collectDiagnostics } = await import("../persistent-session-EZEYH3PM.js");
13941
+ const { collectDiagnostics } = await import("../persistent-session-OQ7MFVEH.js");
13942
13942
  const diagCodeNames = [...agentState.persistentSessionAgents];
13943
13943
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames, quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor) : void 0;
13944
13944
  let tailscaleHostname;
@@ -14090,7 +14090,7 @@ async function pollCycleInner() {
14090
14090
  collectPanelessActivityProbes,
14091
14091
  getResponsivenessIntervalMs,
14092
14092
  occupancyQualificationClassifications
14093
- } = await import("../responsiveness-probe-VS6GODYP.js");
14093
+ } = await import("../responsiveness-probe-MDL53OT2.js");
14094
14094
  const probeIntervalMs = getResponsivenessIntervalMs();
14095
14095
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
14096
14096
  const probeCodeNames = [...agentState.persistentSessionAgents];
@@ -14200,7 +14200,7 @@ async function pollCycleInner() {
14200
14200
  collectResponsivenessProbes,
14201
14201
  livePendingInboundOldestAgeSeconds,
14202
14202
  parkPendingInbound
14203
- } = await import("../responsiveness-probe-VS6GODYP.js");
14203
+ } = await import("../responsiveness-probe-MDL53OT2.js");
14204
14204
  const { getProjectDir: wedgeProjectDir } = await import("../scheduler-engine-NDP36U7O.js");
14205
14205
  const wedgeNow = /* @__PURE__ */ new Date();
14206
14206
  const liveAgents = agentState.persistentSessionAgents;
@@ -14356,7 +14356,7 @@ async function pollCycleInner() {
14356
14356
  }
14357
14357
  try {
14358
14358
  const { scrapeMcpFailedBannerCount } = await import("../pane-mcp-banner-scraper-JA437JIB.js");
14359
- const { probeSessionAuth } = await import("../session-auth-dead-7U24PZZS.js");
14359
+ const { probeSessionAuth } = await import("../session-auth-dead-4OJ2XLH4.js");
14360
14360
  const observations = [];
14361
14361
  const pendingCacheCommits = [];
14362
14362
  const modelApiErrorReportingOn = hostFlagStore().getBoolean("model-api-error-reporting");
@@ -18117,7 +18117,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
18117
18117
  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}`));
18118
18118
  void (async () => {
18119
18119
  try {
18120
- const { collectDiagnostics } = await import("../persistent-session-EZEYH3PM.js");
18120
+ const { collectDiagnostics } = await import("../persistent-session-OQ7MFVEH.js");
18121
18121
  await api.post("/host/heartbeat", {
18122
18122
  host_id: hostId,
18123
18123
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor)
@@ -18168,7 +18168,7 @@ async function respawnAgentAfterMcpStop(codeName, reason) {
18168
18168
  }
18169
18169
  try {
18170
18170
  const hostId = await getHostId();
18171
- const { collectDiagnostics } = await import("../persistent-session-EZEYH3PM.js");
18171
+ const { collectDiagnostics } = await import("../persistent-session-OQ7MFVEH.js");
18172
18172
  await api.post("/host/heartbeat", {
18173
18173
  host_id: hostId,
18174
18174
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor)
@@ -18800,7 +18800,7 @@ async function processClaudePairSessions(agents) {
18800
18800
  killPairSession,
18801
18801
  pairTmuxSession,
18802
18802
  finalizeClaudePairOnboarding
18803
- } = await import("../claude-pair-runtime-X6CWJNW2.js");
18803
+ } = await import("../claude-pair-runtime-HPCXQDVY.js");
18804
18804
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
18805
18805
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
18806
18806
  const killed = await killPairSession(pairTmuxSession(pairId));
@@ -32291,6 +32291,15 @@ var MARKUP_BRIDGE_SCRIPT = `<script>(function(){
32291
32291
  // long note on the window-capture click handler for why this is a mode and
32292
32292
  // not just always-on.
32293
32293
  var editMode = false;
32294
+ // ENG-9383: the ONE gate every edit-entry path asks. It exists because the
32295
+ // last time a path was added, the old ones did not come with it: ENG-8477
32296
+ // introduced editMode for the deep-probe handlers and left the ENG-6821
32297
+ // direct click/hover on an arming-only check, so text stayed editable with
32298
+ // the toggle off and the button gated one of two paths. A funnel is the fix
32299
+ // for that class of bug; adding the term twice is only the fix for this
32300
+ // instance of it. A fifth handler cannot forget the mode.
32301
+ function canEdit(){ return editEnabled && editMode && !editing; }
32302
+ var hoverCued = []; // ENG-9383: elements currently wearing the mouseover cue
32294
32303
 
32295
32304
  // Element-child indices from <body> down to el. Counts ELEMENT children only
32296
32305
  // (children, not childNodes), matching how the server walks source_html; our
@@ -32484,14 +32493,48 @@ var MARKUP_BRIDGE_SCRIPT = `<script>(function(){
32484
32493
  // Hover affordance (only when armed and not mid-edit). Highlight leaves AND
32485
32494
  // inline-only containers (their bare text is per-node editable, ENG-6856).
32486
32495
  document.addEventListener('mouseover', function(e){
32487
- if(!editEnabled||editing) return; var el=e.target;
32488
- if(editable(el)||inlineOnlyEditable(el)){ el.style.cursor='text'; el.style.outline=el.style.outline||'1px dashed rgba(110,231,183,.6)'; el.__alHover=1; }
32496
+ if(!canEdit()) return; var el=e.target;
32497
+ if(editable(el)||inlineOnlyEditable(el)){
32498
+ // ENG-9383: remember what the author's cursor was before we overwrite it.
32499
+ // Blanking it on the way out would delete an inline cursor the artefact
32500
+ // set itself; '' is a legitimate saved value meaning "there was none".
32501
+ if(el.__alCur===undefined) el.__alCur = el.style.cursor || '';
32502
+ el.style.cursor='text'; el.style.outline=el.style.outline||'1px dashed rgba(110,231,183,.6)'; el.__alHover=1; hoverCued.push(el);
32503
+ }
32489
32504
  });
32490
32505
  document.addEventListener('mouseout', function(e){
32491
- var el=e.target; if(el&&el.__alHover&&el!==editing){ el.style.outline=''; el.__alHover=0; }
32506
+ var el=e.target; if(el&&el.__alHover&&el!==editing){ el.style.outline=''; restoreCursor(el); el.__alHover=0; dropHoverCue(el); }
32492
32507
  });
32508
+ // ENG-9383 (CodeRabbit on #4956): the cue is an outline AND an I-beam cursor.
32509
+ // Clearing only the outline leaves the text still saying "you can type here"
32510
+ // on a page that will now refuse the click - the same misdirection this ticket
32511
+ // is about, one property over.
32512
+ function restoreCursor(el){
32513
+ if(el.__alCur!==undefined){ try{ el.style.cursor=el.__alCur; }catch(e){} el.__alCur=undefined; }
32514
+ }
32515
+ // Keep hoverCued bounded. Without this it grows once per hovered element for
32516
+ // the life of the page and pins every one of them against GC - a list that
32517
+ // only ever empties when the viewer toggles the mode off is a leak on any page
32518
+ // nobody toggles.
32519
+ function dropHoverCue(el){
32520
+ var i=hoverCued.indexOf(el); if(i!==-1) hoverCued.splice(i,1);
32521
+ }
32522
+ // ENG-9383: drop every outline the mouseover cue left behind, without waiting
32523
+ // for a mouseout that may never come - the mode can go off while the pointer is
32524
+ // parked on the text, and then the artefact wears a dashed "editable" outline
32525
+ // on a page where you no longer can. Tracked in a list rather than queried back
32526
+ // out of the DOM: more than one element can carry the cue if the pointer moved
32527
+ // between mouseover and mouseout, and the bridge should not depend on a
32528
+ // selector matching an inline style it wrote.
32529
+ function clearHoverCues(){
32530
+ for(var i=0;i<hoverCued.length;i++){
32531
+ var el=hoverCued[i];
32532
+ if(el && el.__alHover && el!==editing){ try{ el.style.outline=''; }catch(e){} restoreCursor(el); el.__alHover=0; }
32533
+ }
32534
+ hoverCued.length=0;
32535
+ }
32493
32536
  document.addEventListener('click', function(e){
32494
- if(!editEnabled||editing) return;
32537
+ if(!canEdit()) return;
32495
32538
  var sel=document.getSelection(); if(sel && String(sel).trim()) return; // a selection => comment flow
32496
32539
  var el=e.target;
32497
32540
  if(editable(el)){ e.preventDefault(); e.stopPropagation(); startEdit(el); return; }
@@ -32535,7 +32578,7 @@ var MARKUP_BRIDGE_SCRIPT = `<script>(function(){
32535
32578
  // Deliberately general: nothing here knows about .clickzone or any class name.
32536
32579
  // It fixes any artefact that covers its own content.
32537
32580
  window.addEventListener('click', function(e){
32538
- if(!editEnabled || !editMode || editing) return;
32581
+ if(!canEdit()) return;
32539
32582
  var sel=document.getSelection(); if(sel && String(sel).trim()) return; // selection => comment flow
32540
32583
  var t=e.target;
32541
32584
  // Our own toolbar (Save/Cancel) must keep its clicks.
@@ -32593,7 +32636,7 @@ var MARKUP_BRIDGE_SCRIPT = `<script>(function(){
32593
32636
  hoverEl=null;
32594
32637
  }
32595
32638
  document.addEventListener('mousemove', function(e){
32596
- if(!editEnabled || !editMode || editing){ clearDeepHover(); return; }
32639
+ if(!canEdit()){ clearDeepHover(); return; }
32597
32640
  var t=e.target;
32598
32641
  if(editable(t)||inlineOnlyEditable(t)){ clearDeepHover(); return; }
32599
32642
  var now=Date.now(); if(now-hoverProbeAt<80) return; hoverProbeAt=now;
@@ -32693,12 +32736,17 @@ var MARKUP_BRIDGE_SCRIPT = `<script>(function(){
32693
32736
  var d=e.data; if(!d || d['${MARKUP_CONTROL_MARKER}']!==true) return;
32694
32737
  if(d.type==='enable-edit'){ editEnabled=true; }
32695
32738
  else if(d.type==='enable-comment'){ commentEnabled=true; }
32696
- // ENG-8477: the viewer toggled Edit text in the shell. Turning it OFF must
32739
+ // ENG-8477: the viewer toggled Edit mode in the shell. Turning it OFF must
32697
32740
  // also close anything open and drop the hover cue, or the artefact is left
32698
32741
  // wearing our outlines with no way to clear them.
32742
+ // ENG-9383: clearDeepHover() only knows the deep-probe path's outline. The
32743
+ // ENG-6821 mouseover path marks its own element with __alHover and relies on
32744
+ // mouseout to undo it - which never fires if the pointer is still sitting on
32745
+ // the text when the mode goes off, leaving a dashed "you can edit this"
32746
+ // outline on a page where you now cannot. Clear both.
32699
32747
  else if(d.type==='set-edit-mode'){
32700
32748
  editMode = !!d.on;
32701
- if(!editMode){ if(editing) endEdit(false); clearDeepHover(); }
32749
+ if(!editMode){ if(editing) endEdit(false); clearDeepHover(); clearHoverCues(); }
32702
32750
  }
32703
32751
  else if(d.type==='edit-result'){
32704
32752
  if(d.ok){ /* republish hot-swaps the iframe; nothing to do */ }
@@ -35909,14 +35957,15 @@ var FLAG_REGISTRY = [
35909
35957
  // hand-written process.env gate) — same posture as memory-extraction /
35910
35958
  // tool-call-audit above. Gives a per-host canary before the DB flag exists.
35911
35959
  envVar: "AGT_SECRET_FILES_TMPFS_ENABLED",
35912
- // Deliberately-unreachable placeholder until this ships: no published CLI
35913
- // carries the manager reader + core writer yet, so reach must report "no
35914
- // host honors" rather than the `honors`-for-everyone that omitting `since`
35915
- // produces. MOVE THIS PIN to the actual auto-published agt-cli version at
35916
- // merge (auto-publish patch-bumps from main; verify against the tarball, the
35917
- // ENG-8575/ENG-9350 lesson) the marker is `setSecretFileTmpfsBacking` in
35918
- // package/dist/lib/manager-worker.js.
35919
- since: "99.0.0"
35960
+ // The real published build that carries the manager reader + core writer,
35961
+ // replacing the deliberately-unreachable `99.0.0` this flag shipped with.
35962
+ // Verified against the tarball (`npm pack @integrity-labs/agt-cli@0.28.678`):
35963
+ // `setSecretFileTmpfsBacking` is present in package/dist/lib/manager-worker.js
35964
+ // and the `secret-files-tmpfs` key ships in the bundle. Auto-publish patch-
35965
+ // bumps from main, so if a CLI-touching PR landed between the ENG-9348 merge
35966
+ // and this one the real cut is higher than 0.28.678 and reach under-reports;
35967
+ // re-verify before flipping the flag on for a canary (ENG-8575/ENG-9350).
35968
+ since: "0.28.678"
35920
35969
  },
35921
35970
  {
35922
35971
  key: "memory-file-tombstones",
@@ -36700,6 +36749,17 @@ var FLAG_REGISTRY = [
36700
36749
  // control that does nothing, which is the ENG-8303 class exactly.
36701
36750
  // enforce arms automated downtime on a customer's production host.
36702
36751
  sensitive: true
36752
+ },
36753
+ {
36754
+ key: "live-meeting-advisor",
36755
+ description: "Live meeting advising in Ninja Notes (ENG-9381). When ON for an org, a person recording a meeting on the Mac may arm an agent to watch it in flight: audio chunks stream to POST /notes/live/:id/chunks, a server-side Haiku vet decides moment by moment whether to escalate, and escalations reach the agent in a server-minted chat thread. Gates the CAPABILITY, not a surface: the refusal is in startLiveAdvisorSession, so a client that ignores the flag still cannot open a session, and GET /notes/destinations reports the same answer as advisor_enabled so the app can skip the arming modal entirely. Boolean gate; ships dark. OFF NEVER COSTS THE RECORDING. An unentitled org \u2014 or a flag read that fails \u2014 costs the advisor only; the microphone still starts and the note is still transcribed and delivered. That direction is deliberate: the user pressed Record and a recording is what they are owed, while arming on a failed read would spend money per minute on a session nobody confirmed. Deliberately NO envVar. This is an org-scoped gate, and an envVar is highest-precedence per ADR-0022 \u2014 a literal in sst.config.ts would pin every stage and make the admin control do nothing, the ENG-8303 class exactly.",
36756
+ flagType: "boolean",
36757
+ defaultValue: false,
36758
+ // Turning it ON arms a per-minute-metered capability AND starts streaming
36759
+ // meeting content to a server-side vet. Both halves are the deliberate,
36760
+ // audited decision ADR-0022 §4 reserves confirmation for — same treatment as
36761
+ // agent-hours-billing-enabled.
36762
+ sensitive: true
36703
36763
  }
36704
36764
  ];
36705
36765
  var REGISTRY_BY_KEY = new Map(FLAG_REGISTRY.map((definition) => [definition.key, definition]));
package/dist/mcp/index.js CHANGED
@@ -37038,6 +37038,30 @@ var BLOCKED_ON_ME_SECTION_NOTE = "_Another agent has PARKED its own work until y
37038
37038
  var HUMAN_ASSIGNED_SECTION_HEADING = "Assigned to a person (not yours to action)";
37039
37039
  var HUMAN_ASSIGNED_SECTION_NOTE = "_These belong to a person, not to you. You cannot move, note or complete them \u2014 every kanban write is refused. If the work is finished (or was never really theirs), use `kanban_recall` to pull the card back onto your board, then close it as normal._";
37040
37040
 
37041
+ // src/kanban-peek-render.ts
37042
+ var PEEK_RENDER_COLUMNS = [
37043
+ ["in_progress", "in progress"],
37044
+ ["todo", "todo"],
37045
+ ["backlog", "backlog"],
37046
+ ["waiting", "waiting"],
37047
+ ["needs_attention", "needs attention"]
37048
+ ];
37049
+ function formatPeekAge(ageHours) {
37050
+ if (!Number.isFinite(ageHours) || ageHours <= 0) return "<1h";
37051
+ if (ageHours < 48) return `${Math.floor(ageHours)}h`;
37052
+ return `${Math.floor(ageHours / 24)}d`;
37053
+ }
37054
+ function renderKanbanPeek(data, fallbackTeam) {
37055
+ const parts = PEEK_RENDER_COLUMNS.map(([key, label]) => {
37056
+ const count = data[key];
37057
+ const oldest = data.oldest?.[key];
37058
+ const age = oldest === void 0 ? "" : ` (oldest ${formatPeekAge(oldest.age_hours)}, id ${oldest.card_id})`;
37059
+ return `${label}: ${count}${age}`;
37060
+ });
37061
+ const where = data.cross_team ? ` on team ${data.target_team ?? fallbackTeam ?? "?"}` : "";
37062
+ return `${data.target_agent}${where} \u2014 ${parts.join(" \xB7 ")}`;
37063
+ }
37064
+
37041
37065
  // src/kanban-person-waiting-kind.ts
37042
37066
  function isPersonWaitingKindMcp(kind) {
37043
37067
  if (kind === void 0 || kind === null || kind === "") return true;
@@ -39667,6 +39691,15 @@ var MARKUP_BRIDGE_SCRIPT = `<script>(function(){
39667
39691
  // long note on the window-capture click handler for why this is a mode and
39668
39692
  // not just always-on.
39669
39693
  var editMode = false;
39694
+ // ENG-9383: the ONE gate every edit-entry path asks. It exists because the
39695
+ // last time a path was added, the old ones did not come with it: ENG-8477
39696
+ // introduced editMode for the deep-probe handlers and left the ENG-6821
39697
+ // direct click/hover on an arming-only check, so text stayed editable with
39698
+ // the toggle off and the button gated one of two paths. A funnel is the fix
39699
+ // for that class of bug; adding the term twice is only the fix for this
39700
+ // instance of it. A fifth handler cannot forget the mode.
39701
+ function canEdit(){ return editEnabled && editMode && !editing; }
39702
+ var hoverCued = []; // ENG-9383: elements currently wearing the mouseover cue
39670
39703
 
39671
39704
  // Element-child indices from <body> down to el. Counts ELEMENT children only
39672
39705
  // (children, not childNodes), matching how the server walks source_html; our
@@ -39860,14 +39893,48 @@ var MARKUP_BRIDGE_SCRIPT = `<script>(function(){
39860
39893
  // Hover affordance (only when armed and not mid-edit). Highlight leaves AND
39861
39894
  // inline-only containers (their bare text is per-node editable, ENG-6856).
39862
39895
  document.addEventListener('mouseover', function(e){
39863
- if(!editEnabled||editing) return; var el=e.target;
39864
- if(editable(el)||inlineOnlyEditable(el)){ el.style.cursor='text'; el.style.outline=el.style.outline||'1px dashed rgba(110,231,183,.6)'; el.__alHover=1; }
39896
+ if(!canEdit()) return; var el=e.target;
39897
+ if(editable(el)||inlineOnlyEditable(el)){
39898
+ // ENG-9383: remember what the author's cursor was before we overwrite it.
39899
+ // Blanking it on the way out would delete an inline cursor the artefact
39900
+ // set itself; '' is a legitimate saved value meaning "there was none".
39901
+ if(el.__alCur===undefined) el.__alCur = el.style.cursor || '';
39902
+ el.style.cursor='text'; el.style.outline=el.style.outline||'1px dashed rgba(110,231,183,.6)'; el.__alHover=1; hoverCued.push(el);
39903
+ }
39865
39904
  });
39866
39905
  document.addEventListener('mouseout', function(e){
39867
- var el=e.target; if(el&&el.__alHover&&el!==editing){ el.style.outline=''; el.__alHover=0; }
39906
+ var el=e.target; if(el&&el.__alHover&&el!==editing){ el.style.outline=''; restoreCursor(el); el.__alHover=0; dropHoverCue(el); }
39868
39907
  });
39908
+ // ENG-9383 (CodeRabbit on #4956): the cue is an outline AND an I-beam cursor.
39909
+ // Clearing only the outline leaves the text still saying "you can type here"
39910
+ // on a page that will now refuse the click - the same misdirection this ticket
39911
+ // is about, one property over.
39912
+ function restoreCursor(el){
39913
+ if(el.__alCur!==undefined){ try{ el.style.cursor=el.__alCur; }catch(e){} el.__alCur=undefined; }
39914
+ }
39915
+ // Keep hoverCued bounded. Without this it grows once per hovered element for
39916
+ // the life of the page and pins every one of them against GC - a list that
39917
+ // only ever empties when the viewer toggles the mode off is a leak on any page
39918
+ // nobody toggles.
39919
+ function dropHoverCue(el){
39920
+ var i=hoverCued.indexOf(el); if(i!==-1) hoverCued.splice(i,1);
39921
+ }
39922
+ // ENG-9383: drop every outline the mouseover cue left behind, without waiting
39923
+ // for a mouseout that may never come - the mode can go off while the pointer is
39924
+ // parked on the text, and then the artefact wears a dashed "editable" outline
39925
+ // on a page where you no longer can. Tracked in a list rather than queried back
39926
+ // out of the DOM: more than one element can carry the cue if the pointer moved
39927
+ // between mouseover and mouseout, and the bridge should not depend on a
39928
+ // selector matching an inline style it wrote.
39929
+ function clearHoverCues(){
39930
+ for(var i=0;i<hoverCued.length;i++){
39931
+ var el=hoverCued[i];
39932
+ if(el && el.__alHover && el!==editing){ try{ el.style.outline=''; }catch(e){} restoreCursor(el); el.__alHover=0; }
39933
+ }
39934
+ hoverCued.length=0;
39935
+ }
39869
39936
  document.addEventListener('click', function(e){
39870
- if(!editEnabled||editing) return;
39937
+ if(!canEdit()) return;
39871
39938
  var sel=document.getSelection(); if(sel && String(sel).trim()) return; // a selection => comment flow
39872
39939
  var el=e.target;
39873
39940
  if(editable(el)){ e.preventDefault(); e.stopPropagation(); startEdit(el); return; }
@@ -39911,7 +39978,7 @@ var MARKUP_BRIDGE_SCRIPT = `<script>(function(){
39911
39978
  // Deliberately general: nothing here knows about .clickzone or any class name.
39912
39979
  // It fixes any artefact that covers its own content.
39913
39980
  window.addEventListener('click', function(e){
39914
- if(!editEnabled || !editMode || editing) return;
39981
+ if(!canEdit()) return;
39915
39982
  var sel=document.getSelection(); if(sel && String(sel).trim()) return; // selection => comment flow
39916
39983
  var t=e.target;
39917
39984
  // Our own toolbar (Save/Cancel) must keep its clicks.
@@ -39969,7 +40036,7 @@ var MARKUP_BRIDGE_SCRIPT = `<script>(function(){
39969
40036
  hoverEl=null;
39970
40037
  }
39971
40038
  document.addEventListener('mousemove', function(e){
39972
- if(!editEnabled || !editMode || editing){ clearDeepHover(); return; }
40039
+ if(!canEdit()){ clearDeepHover(); return; }
39973
40040
  var t=e.target;
39974
40041
  if(editable(t)||inlineOnlyEditable(t)){ clearDeepHover(); return; }
39975
40042
  var now=Date.now(); if(now-hoverProbeAt<80) return; hoverProbeAt=now;
@@ -40069,12 +40136,17 @@ var MARKUP_BRIDGE_SCRIPT = `<script>(function(){
40069
40136
  var d=e.data; if(!d || d['${MARKUP_CONTROL_MARKER}']!==true) return;
40070
40137
  if(d.type==='enable-edit'){ editEnabled=true; }
40071
40138
  else if(d.type==='enable-comment'){ commentEnabled=true; }
40072
- // ENG-8477: the viewer toggled Edit text in the shell. Turning it OFF must
40139
+ // ENG-8477: the viewer toggled Edit mode in the shell. Turning it OFF must
40073
40140
  // also close anything open and drop the hover cue, or the artefact is left
40074
40141
  // wearing our outlines with no way to clear them.
40142
+ // ENG-9383: clearDeepHover() only knows the deep-probe path's outline. The
40143
+ // ENG-6821 mouseover path marks its own element with __alHover and relies on
40144
+ // mouseout to undo it - which never fires if the pointer is still sitting on
40145
+ // the text when the mode goes off, leaving a dashed "you can edit this"
40146
+ // outline on a page where you now cannot. Clear both.
40075
40147
  else if(d.type==='set-edit-mode'){
40076
40148
  editMode = !!d.on;
40077
- if(!editMode){ if(editing) endEdit(false); clearDeepHover(); }
40149
+ if(!editMode){ if(editing) endEdit(false); clearDeepHover(); clearHoverCues(); }
40078
40150
  }
40079
40151
  else if(d.type==='edit-result'){
40080
40152
  if(d.ok){ /* republish hot-swaps the iframe; nothing to do */ }
@@ -42836,14 +42908,15 @@ var FLAG_REGISTRY = [
42836
42908
  // hand-written process.env gate) — same posture as memory-extraction /
42837
42909
  // tool-call-audit above. Gives a per-host canary before the DB flag exists.
42838
42910
  envVar: "AGT_SECRET_FILES_TMPFS_ENABLED",
42839
- // Deliberately-unreachable placeholder until this ships: no published CLI
42840
- // carries the manager reader + core writer yet, so reach must report "no
42841
- // host honors" rather than the `honors`-for-everyone that omitting `since`
42842
- // produces. MOVE THIS PIN to the actual auto-published agt-cli version at
42843
- // merge (auto-publish patch-bumps from main; verify against the tarball, the
42844
- // ENG-8575/ENG-9350 lesson) the marker is `setSecretFileTmpfsBacking` in
42845
- // package/dist/lib/manager-worker.js.
42846
- since: "99.0.0"
42911
+ // The real published build that carries the manager reader + core writer,
42912
+ // replacing the deliberately-unreachable `99.0.0` this flag shipped with.
42913
+ // Verified against the tarball (`npm pack @integrity-labs/agt-cli@0.28.678`):
42914
+ // `setSecretFileTmpfsBacking` is present in package/dist/lib/manager-worker.js
42915
+ // and the `secret-files-tmpfs` key ships in the bundle. Auto-publish patch-
42916
+ // bumps from main, so if a CLI-touching PR landed between the ENG-9348 merge
42917
+ // and this one the real cut is higher than 0.28.678 and reach under-reports;
42918
+ // re-verify before flipping the flag on for a canary (ENG-8575/ENG-9350).
42919
+ since: "0.28.678"
42847
42920
  },
42848
42921
  {
42849
42922
  key: "memory-file-tombstones",
@@ -43627,6 +43700,17 @@ var FLAG_REGISTRY = [
43627
43700
  // control that does nothing, which is the ENG-8303 class exactly.
43628
43701
  // enforce arms automated downtime on a customer's production host.
43629
43702
  sensitive: true
43703
+ },
43704
+ {
43705
+ key: "live-meeting-advisor",
43706
+ description: "Live meeting advising in Ninja Notes (ENG-9381). When ON for an org, a person recording a meeting on the Mac may arm an agent to watch it in flight: audio chunks stream to POST /notes/live/:id/chunks, a server-side Haiku vet decides moment by moment whether to escalate, and escalations reach the agent in a server-minted chat thread. Gates the CAPABILITY, not a surface: the refusal is in startLiveAdvisorSession, so a client that ignores the flag still cannot open a session, and GET /notes/destinations reports the same answer as advisor_enabled so the app can skip the arming modal entirely. Boolean gate; ships dark. OFF NEVER COSTS THE RECORDING. An unentitled org \u2014 or a flag read that fails \u2014 costs the advisor only; the microphone still starts and the note is still transcribed and delivered. That direction is deliberate: the user pressed Record and a recording is what they are owed, while arming on a failed read would spend money per minute on a session nobody confirmed. Deliberately NO envVar. This is an org-scoped gate, and an envVar is highest-precedence per ADR-0022 \u2014 a literal in sst.config.ts would pin every stage and make the admin control do nothing, the ENG-8303 class exactly.",
43707
+ flagType: "boolean",
43708
+ defaultValue: false,
43709
+ // Turning it ON arms a per-minute-metered capability AND starts streaming
43710
+ // meeting content to a server-side vet. Both halves are the deliberate,
43711
+ // audited decision ADR-0022 §4 reserves confirmation for — same treatment as
43712
+ // agent-hours-billing-enabled.
43713
+ sensitive: true
43630
43714
  }
43631
43715
  ];
43632
43716
  var REGISTRY_BY_KEY = new Map(FLAG_REGISTRY.map((definition) => [definition.key, definition]));
@@ -44570,6 +44654,64 @@ server.tool(
44570
44654
  }
44571
44655
  }
44572
44656
  );
44657
+ server.tool(
44658
+ "kanban_peek",
44659
+ "Look at ANOTHER agent's board WITHOUT seeing what is on it: how many cards sit in each column, and how long the oldest card in each column has been sitting there. Use it before routing work with kanban_assign, to tell an agent that is genuinely free from one that is buried, and to spot a board where something has been rotting for days. You get NUMBERS ONLY \u2014 no titles, descriptions, results or notes ever cross between agents, so this tells you the SHAPE of their queue, never its content. A deep board is not automatically a problem and an empty one is not automatically fine: the age of the oldest card is usually the more useful of the two. By default the target must be an agent on your OWN team; pass `target_team` to peek across teams in your organization, which works only where your org has enabled cross-team assignment and a peer grant links the teams \u2014 otherwise it reads as not-found, exactly like kanban_assign. Don't know the agent's code_name? Call directory_lookup first.",
44660
+ {
44661
+ target_agent: external_exports.string().describe(
44662
+ "The agent whose board you want to size up: their agent code_name (kebab-case) or agent UUID. On your own team unless target_team is also set."
44663
+ ),
44664
+ target_team: external_exports.string().trim().min(1).optional().describe(
44665
+ "Optional: the slug (or UUID) of ANOTHER team in your organization, to peek across teams. Omit for a teammate on your own team. Requires the org to have cross-team assignment enabled and a peer grant; otherwise the target reads as not-found."
44666
+ )
44667
+ },
44668
+ async (params) => {
44669
+ try {
44670
+ const data = await apiPost(
44671
+ "/host/kanban/peek",
44672
+ {
44673
+ agent_id: AGT_AGENT_ID,
44674
+ target_agent: params.target_agent,
44675
+ // Only sent when peeking across teams — the route branches on its
44676
+ // presence, so omit it for the same-team path (identical contract to
44677
+ // kanban_assign). The schema rejects empty strings, so a present value
44678
+ // is always meaningful; check presence, not truthiness.
44679
+ ...params.target_team !== void 0 ? { target_team: params.target_team } : {}
44680
+ },
44681
+ false,
44682
+ 15e3,
44683
+ "kanban_peek",
44684
+ // Genuinely read-only: a timeout or transport error here can never have
44685
+ // committed anything, and saying so keeps the retry decision obvious.
44686
+ true
44687
+ );
44688
+ return {
44689
+ content: [
44690
+ {
44691
+ type: "text",
44692
+ // Rendering lives in a sibling module so it is reachable by a test —
44693
+ // importing this file boots the stdio server, so anything inline
44694
+ // here is checked exactly once, on the day it is written.
44695
+ text: renderKanbanPeek(data, params.target_team)
44696
+ }
44697
+ ]
44698
+ };
44699
+ } catch (err) {
44700
+ const msg = err instanceof Error ? err.message : String(err);
44701
+ const notFound = /returned 404/.test(msg);
44702
+ const notFoundText = params.target_team ? `Could not peek: no agent "${params.target_agent}" reachable on team "${params.target_team}". Check the team slug and agent code_name, and note cross-team access only works when your org has enabled it and a peer grant links the teams.` : `Could not peek: no agent "${params.target_agent}" found on your team. Check the code_name and make sure they're a teammate on the same team.`;
44703
+ return {
44704
+ content: [
44705
+ {
44706
+ type: "text",
44707
+ text: notFound ? notFoundText : `Could not peek at ${params.target_agent}: ${msg}`
44708
+ }
44709
+ ],
44710
+ isError: true
44711
+ };
44712
+ }
44713
+ }
44714
+ );
44573
44715
  server.tool(
44574
44716
  "kanban_reassign",
44575
44717
  "Move an EXISTING kanban card to ANOTHER agent\u2019s board, preserving its id, history, comments, priority and status. Use this to re-home a task you already have (e.g. you picked up a card but it\u2019s really another specialist\u2019s job) - it removes the card from the current board and places the same card on the target agent\u2019s board. This is different from kanban_assign, which CREATES a new card. The card must currently live on your team. To move across teams in your organization, also pass `target_team` (same cross-team rules as kanban_assign). Don\u2019t know the agent code_name or team slug? Call directory_lookup first.",
@@ -46357,6 +46499,8 @@ var LOCAL_TOOL_NAMES = /* @__PURE__ */ new Set([
46357
46499
  "kanban_recall",
46358
46500
  // ENG-9050: the return path for delegated work.
46359
46501
  "kanban_reopen",
46502
+ // ENG-9375: the READ path over a teammate's board (counts only).
46503
+ "kanban_peek",
46360
46504
  // ENG-6953: agent + people directory lookup (always registered locally).
46361
46505
  "directory_lookup",
46362
46506
  "status_standup",