2026-08-24 03:08:56 -03:00
/* node:coverage disable */
( function ( root , factory ) {
'use strict' ;
const contract = typeof module === 'object' && module . exports ? require ( './wave_a_contract.js' ) : root . HermesHuxWaveAContract ;
const shellApi = typeof module === 'object' && module . exports ? require ( '../shell.js' ) : root . HermesHuxShell ;
const api = factory ( contract , shellApi ) ;
if ( typeof module === 'object' && module . exports ) module . exports = api ;
else root . HermesHuxAutonomyPrivacy = api ;
} ( typeof globalThis === 'object' ? globalThis : this , function ( contract , shellApi ) {
/* node:coverage enable */
'use strict' ;
const ACCEPT = 'application/vnd.hermes.hux+json; version=1' ;
const ID = /^[a-z]{2,6}_[A-Za-z0-9._-]{4,80}$/ ;
const SLOT = /^slot-[0-9]{1,3}$/ ;
const USER = /^usr_[0-9a-f]{16,64}$/ ;
const UTC = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,6})?Z$/ ;
const CONTROL = /[\u0000-\u001f\u007f]/ ;
const AUTONOMY = new Set ( [ 'ask_first' , 'safe' , 'autonomous' ] ) ;
const DECISIONS = new Set ( [ 'allow' , 'ask' , 'deny' ] ) ;
const CHOICES = new Set ( [ 'once' , 'session' , 'always' , 'deny' ] ) ;
const OUTCOMES = new Set ( [ 'cancelled' , 'already_complete' , 'failed_to_cancel' ] ) ;
const TOPICS = new Set ( [ 'health' , 'finance' , 'legal' , 'relationships' , 'credentials' , 'minors' , 'location' , 'biometric' ] ) ;
const NOTICE _CONTROLS = new Set ( [ 'forget_this_conversation' , 'switch_to_private' , 'disable_memory_here' , 'dismiss' ] ) ;
const CAPABILITIES = new Set ( [ 'read_files' , 'write_files' , 'shell' , 'network' , 'web_search' , 'send_message' , 'memory_write' , 'artifact_write' , 'spend_tokens' , 'delegate' , 'deploy' , 'external_side_effect' ] ) ;
const BUDGETS = [ 'tokens_per_run' , 'tool_calls_per_run' , 'wall_clock_seconds' , 'delegations_per_run' , 'spend_units' , 'subagents_per_run' ] ;
const GENERIC _NOTICE = 'Sensitive-topic protections are active. Details stay scoped to this conversation and are not remembered without approval.' ;
const UNVERIFIED _STOP = 'Model response stopped; tool/side-effect cancellation unverified.' ;
function record ( value ) { return value && typeof value === 'object' && ! Array . isArray ( value ) ? value : null ; }
function exact ( value , required , optional ) {
const allowed = new Set ( required . concat ( optional || [ ] ) ) ;
return required . every ( ( key ) => Object . prototype . hasOwnProperty . call ( value , key ) ) &&
Object . keys ( value ) . every ( ( key ) => allowed . has ( key ) ) ;
}
function id ( value , prefix ) { return typeof value === 'string' && ID . test ( value ) && ( ! prefix || value . startsWith ( ` ${ prefix } _ ` ) ) ; }
function timestamp ( value ) { return typeof value === 'string' && UTC . test ( value ) && ! Number . isNaN ( Date . parse ( value ) ) ; }
function text ( value , max ) { return typeof value === 'string' && value . length > 0 && value . length <= max && ! CONTROL . test ( value ) ; }
function integer ( value , min , max ) { return Number . isSafeInteger ( value ) && value >= min && value <= max ; }
function sameIdentity ( owner , identity ) { return owner === identity . userRef ; }
function safeRun ( value ) { return id ( value , 'run' ) ; }
function normalizeBudgets ( raw ) {
const value = record ( raw ) ;
if ( ! value || ! exact ( value , [ ] , BUDGETS . concat ( [ 'scope' ] ) ) ) return null ;
const result = { } ;
for ( const key of BUDGETS ) {
if ( value [ key ] !== undefined && ! integer ( value [ key ] , 0 , Number . MAX _SAFE _INTEGER ) ) return null ;
if ( value [ key ] !== undefined ) result [ key ] = value [ key ] ;
}
if ( value . scope !== undefined ) {
const scope = record ( value . scope ) ;
if ( ! scope || ! exact ( scope , [ ] , [ 'conversations' , 'paths' ] ) ) return null ;
const conversations = scope . conversations || [ ] ;
const paths = scope . paths || [ ] ;
if ( ! Array . isArray ( conversations ) || conversations . length > 64 || conversations . some ( ( item ) => ! id ( item , 'conv' ) ) ||
! Array . isArray ( paths ) || paths . length > 64 || paths . some ( ( item ) => ! text ( item , 300 ) ) ) return null ;
result . scope = { conversations : conversations . slice ( ) , paths : paths . slice ( ) } ;
}
return result ;
}
function normalizePolicy ( raw , identity , conversationId , etag ) {
const value = record ( raw ) ;
if ( ! value || ! exact ( value , [ 'schema' , 'id' , 'owner' , 'scope' , 'autonomy' , 'grants' , 'budgets' , 'provenance' , 'updated_at' , 'revision' ] ) ||
value . schema !== 'hux.policy.v1' || ! id ( value . id , 'pol' ) || ! sameIdentity ( value . owner , identity ) ||
! AUTONOMY . has ( value . autonomy ) || ! timestamp ( value . updated _at ) || ! integer ( value . revision , 1 , Number . MAX _SAFE _INTEGER ) ||
String ( etag || '' ) . replaceAll ( '"' , '' ) !== String ( value . revision ) ) return null ;
const scope = record ( value . scope ) ;
if ( ! scope || ! exact ( scope , [ 'level' ] , [ 'scope_id' ] ) || ! [ 'global' , 'project' , 'conversation' ] . includes ( scope . level ) ||
( scope . level === 'global' ? scope . scope _id !== undefined : ! id ( scope . scope _id , scope . level === 'project' ? 'prj' : 'conv' ) ) ||
( scope . level === 'global' ? value . id !== 'pol_global' : ! value . id . startsWith ( ` pol_ ${ scope . level } . ` ) ) ||
( scope . level === 'conversation' && scope . scope _id !== conversationId ) ||
! record ( value . provenance ) || ! Array . isArray ( value . grants ) || value . grants . length > 64 ) return null ;
const grants = [ ] ;
for ( const rawGrant of value . grants ) {
const grant = record ( rawGrant ) ;
if ( ! grant || ! exact ( grant , [ 'capability' , 'decision' ] , [ 'expires_at' , 'granted_by' ] ) ||
! CAPABILITIES . has ( grant . capability ) || ! DECISIONS . has ( grant . decision ) ||
( grant . expires _at !== undefined && ! timestamp ( grant . expires _at ) ) ) return null ;
grants . push ( { capability : grant . capability , decision : grant . decision , ... ( grant . expires _at ? { expires _at : grant . expires _at } : { } ) } ) ;
}
const budgets = normalizeBudgets ( value . budgets ) ;
return budgets ? { id : value . id , owner : value . owner , effectiveScope : { ... scope } ,
scope : { level : 'conversation' , scope _id : conversationId } , autonomy : value . autonomy , grants , budgets ,
revision : value . revision , ifMatch : scope . level === 'conversation' ? value . revision : 0 , updatedAt : value . updated _at } : null ;
}
function normalizeApproval ( raw , conversationId , statuses , expectedChoice , identity ) {
const value = record ( raw ) ;
if ( ! value || ! exact ( value , [ 'schema' , 'id' , 'run_id' , 'conversation_id' , 'capability' , 'request' , 'status' , 'requested_at' , 'expires_at' ] , [ 'decision' , 'idempotency_key' ] ) ||
value . schema !== 'hux.approval.v1' || ! id ( value . id , 'apr' ) || ! safeRun ( value . run _id ) ||
value . conversation _id !== conversationId || ! CAPABILITIES . has ( value . capability ) ||
! statuses . has ( value . status ) || ! timestamp ( value . requested _at ) || ! timestamp ( value . expires _at ) ) return null ;
const request = record ( value . request ) ;
if ( ! request || ! exact ( request , [ 'summary' , 'risk' , 'external' ] , [ 'detail' , 'evidence' ] ) || ! text ( request . summary , 280 ) ||
! [ 'low' , 'medium' , 'high' ] . includes ( request . risk ) || typeof request . external !== 'boolean' ) return null ;
if ( expectedChoice !== undefined ) {
const decision = record ( value . decision ) ; const actor = decision && record ( decision . by ) ;
if ( ! decision || ! exact ( decision , [ 'choice' , 'by' , 'at' ] ) || decision . choice !== expectedChoice || ! timestamp ( decision . at ) ||
! identity || ! actor || ! exact ( actor , [ 'type' , 'id' ] , [ 'display' ] ) || actor . type !== 'user' || actor . id !== identity . userRef ) return null ;
} else if ( value . decision !== undefined ) return null ;
return { id : value . id , runId : value . run _id , capability : value . capability , summary : request . summary ,
2026-08-24 13:53:00 -03:00
risk : request . risk , external : request . external , status : value . status ,
requestedAt : value . requested _at , expiresAt : value . expires _at } ;
2026-08-24 03:08:56 -03:00
}
function normalizeApprovalPage ( raw , conversationId ) {
const value = record ( raw ) ;
if ( ! value || ! exact ( value , [ 'items' , 'next' ] ) || ! Array . isArray ( value . items ) || value . items . length > 200 || value . next !== null ) return null ;
const items = value . items . map ( ( item ) => normalizeApproval ( item , conversationId , new Set ( [ 'pending' ] ) ) ) ;
return items . some ( ( item ) => item === null ) || new Set ( items . map ( ( item ) => item . id ) ) . size !== items . length ? null : items ;
}
function normalizeReceipt ( raw , runId , conversationId , identity ) {
const value = record ( raw ) ;
const actor = value && record ( value . requested _by ) ;
const human = identity && [ 'chat' , 'telegram' , 'voice' ] . includes ( identity . surface ) ;
if ( ! value || ! exact ( value , [ 'schema' , 'id' , 'run_id' , 'requested_by' , 'requested_at' , 'outcome' , 'side_effects' ] , [ 'acknowledged_at' , 'completed_at' , 'conversation_id' ] ) ||
value . schema !== 'hux.cancel_receipt.v1' || ! id ( value . id , 'rcpt' ) || value . run _id !== runId || ! actor ||
! exact ( actor , [ 'type' , 'id' ] , [ 'display' ] ) || ! identity ||
( human ? actor . type !== 'user' || actor . id !== identity . userRef : actor . type !== 'system' || actor . id !== identity . surface ) ||
! timestamp ( value . requested _at ) || ! OUTCOMES . has ( value . outcome ) ||
( value . conversation _id !== undefined && value . conversation _id !== conversationId ) || ! Array . isArray ( value . side _effects ) || value . side _effects . length > 64 ) return null ;
const effects = value . side _effects . map ( ( rawEffect ) => {
const effect = record ( rawEffect ) ;
return effect && exact ( effect , [ 'description' , 'reverted' ] , [ 'evidence' ] ) && text ( effect . description , 280 ) && typeof effect . reverted === 'boolean' ?
{ description : effect . description , reverted : effect . reverted } : null ;
} ) ;
return effects . some ( ( item ) => item === null ) ? null : { id : value . id , runId , outcome : value . outcome , sideEffects : effects } ;
}
function normalizePrivacyPolicy ( raw , auditStale ) {
const value = record ( raw ) ;
if ( ! value || ! exact ( value , [ 'schema' , 'version' , 'topics' , 'topic_scoping' , 'retention_audit' ] , [ 'audit_stale' ] ) ||
value . schema !== 'hux.privacy_policy.v1' || ! integer ( value . version , 1 , Number . MAX _SAFE _INTEGER ) ||
! Array . isArray ( value . topics ) || value . topics . length !== TOPICS . size ) return null ;
const names = new Set ( ) ; let shortest = 366 ; let longest = 0 ;
for ( const rawTopic of value . topics ) {
const topic = record ( rawTopic ) ;
if ( ! topic || ! exact ( topic , [ 'topic' , 'sensitivity' , 'memory_write' , 'decay_days' , 'notice' ] ) || ! TOPICS . has ( topic . topic ) ||
names . has ( topic . topic ) || ! [ 'sensitive' , 'restricted' ] . includes ( topic . sensitivity ) || ! [ 'ask' , 'deny' ] . includes ( topic . memory _write ) ||
! integer ( topic . decay _days , 1 , 365 ) || ! text ( topic . notice , 280 ) ) return null ;
names . add ( topic . topic ) ; shortest = Math . min ( shortest , topic . decay _days ) ; longest = Math . max ( longest , topic . decay _days ) ;
}
const scoping = record ( value . topic _scoping ) ; const audit = record ( value . retention _audit ) ;
if ( ! scoping || ! exact ( scoping , [ 'scope_to_conversation' , 'cross_surface_sharing' ] ) || scoping . scope _to _conversation !== true ||
! [ 'never' , 'same_owner_only' ] . includes ( scoping . cross _surface _sharing ) || ! audit || ! exact ( audit , [ 'interval_days' , 'actions' ] ) ||
! integer ( audit . interval _days , 1 , 30 ) || ! Array . isArray ( audit . actions ) || audit . actions . length < 1 ) return null ;
return { version : value . version , protectedCount : names . size , shortestDecay : shortest , longestDecay : longest ,
crossSurfaceSharing : scoping . cross _surface _sharing , auditIntervalDays : audit . interval _days , auditStale : auditStale === 'true' } ;
}
function normalizeAuditPage ( raw ) {
const value = record ( raw ) ;
if ( ! value || ! exact ( value , [ 'items' , 'next' ] ) || ! Array . isArray ( value . items ) || value . items . length > 200 ) return null ;
const rows = value . items . map ( ( rawItem ) => {
const item = record ( rawItem ) ;
if ( ! item || ! exact ( item , [ 'schema' , 'id' , 'ran_at' , 'policy_version' , 'results' ] ) || item . schema !== 'hux.retention_audit.v1' ||
! id ( item . id , 'aud' ) || ! timestamp ( item . ran _at ) || ! integer ( item . policy _version , 1 , Number . MAX _SAFE _INTEGER ) || ! Array . isArray ( item . results ) ) return null ;
let actions = 0 ; let affected = 0 ;
for ( const rawResult of item . results ) {
const result = record ( rawResult ) ;
if ( ! result || ! exact ( result , [ 'action' , 'count' ] ) || ! [ 'expire_memory' , 'decay_topic_context' , 'purge_forgotten_content' , 'report' ] . includes ( result . action ) ||
! integer ( result . count , 0 , Number . MAX _SAFE _INTEGER ) ) return null ;
actions += 1 ; affected += result . action === 'report' ? 0 : result . count ;
}
return { id : item . id , ranAt : item . ran _at , policyVersion : item . policy _version , actions , affected } ;
} ) ;
return rows . some ( ( item ) => item === null ) ? null : rows ;
}
function normalizeNotice ( raw , conversationId ) {
const value = record ( raw ) ;
if ( ! value || ! exact ( value , [ 'schema' , 'topic' , 'conversation_id' , 'text' , 'controls' , 'shown_at' ] ) || value . schema !== 'hux.privacy_notice.v1' ||
! TOPICS . has ( value . topic ) || value . conversation _id !== conversationId || ! text ( value . text , 280 ) || ! timestamp ( value . shown _at ) ||
! Array . isArray ( value . controls ) || value . controls . length < 1 || value . controls . some ( ( item ) => ! NOTICE _CONTROLS . has ( item ) ) ) return null ;
return { text : GENERIC _NOTICE , controls : [ ... new Set ( value . controls ) ] , shownAt : value . shown _at } ;
}
function normalizeForget ( raw , conversationId ) {
const value = record ( raw ) ;
return value && exact ( value , [ 'conversation_id' , 'forgotten' , 'memory_forgotten' , 'events_redacted' ] ) && value . conversation _id === conversationId &&
value . forgotten === true && integer ( value . memory _forgotten , 0 , Number . MAX _SAFE _INTEGER ) && integer ( value . events _redacted , 0 , Number . MAX _SAFE _INTEGER ) ?
{ forgotten : true , memoryForgotten : value . memory _forgotten , eventsRedacted : value . events _redacted } : null ;
}
function el ( doc , tag , attrs , content ) {
const node = doc . createElement ( tag ) ;
Object . entries ( attrs || { } ) . forEach ( ( [ key , value ] ) => node . setAttribute ( key , value ) ) ;
if ( content !== undefined ) node . textContent = String ( content ) ;
return node ;
}
function status ( doc , message , role ) { return el ( doc , 'p' , { class : 'hux-runtime-status' , role : role || 'status' , 'aria-live' : 'polite' } , message ) ; }
function safeError ( doc ) { return status ( doc , 'This workspace control is temporarily unavailable.' , 'alert' ) ; }
function responseHeader ( response , name ) { return response . headers && typeof response . headers . get === 'function' ? response . headers . get ( name ) : '' ; }
function createRuntime ( options ) {
const settings = options || { } ; const doc = settings . document || ( typeof document === 'object' ? document : null ) ;
if ( ! doc || ! id ( settings . conversationId , 'conv' ) ) throw new TypeError ( 'Runtime needs a document and conversation id' ) ;
if ( settings . runId !== undefined && ! safeRun ( settings . runId ) ) throw new TypeError ( 'Runtime run id is invalid' ) ;
const fetcher = settings . fetcher || ( typeof fetch === 'function' ? fetch . bind ( globalThis ) : null ) ;
if ( ! fetcher ) throw new TypeError ( 'Runtime needs fetch' ) ;
let client = null ; let autonomyRoot = null ; let privacyRoot = null ; let policy = null ; let approvals = [ ] ;
let receipt = null ; let privacyPolicy = null ; let audits = [ ] ; let activeTopic = null ; let privacyNotice = null ;
let noticeShown = false ; let noticePending = false ; let privacyMessage = '' ; let stopMessage = '' ;
2026-08-24 13:53:00 -03:00
let inlineDock = null ; let pollTimer = null ;
2026-08-24 03:08:56 -03:00
const issuedApprovals = new Set ( ) ;
2026-08-24 13:53:00 -03:00
const pollMs = Number . isSafeInteger ( settings . approvalPollMs ) && settings . approvalPollMs >= 1 ? settings . approvalPollMs : 4000 ;
function timers ( ) { return settings . timers || globalThis ; }
2026-08-24 03:08:56 -03:00
function assertClient ( candidate , flag ) {
if ( ! candidate || candidate . apiVersion !== 'hux.v1' || ! candidate . identity ||
! SLOT . test ( candidate . identity . tenantSlot || '' ) || ! USER . test ( candidate . identity . userRef || '' ) ||
! [ 'chat' , 'worker' , 'telegram' , 'voice' , 'api' ] . includes ( candidate . identity . surface ) ||
! [ 'router' , 'relay' , 'worker' ] . includes ( candidate . identity . trust ) ||
! candidate . enabled ( 'hux.foundation' ) || ! candidate . enabled ( flag ) ) throw new Error ( 'HUX capability unavailable' ) ;
return candidate ;
}
async function request ( path , init ) {
const customHeaders = ( init && init . headers ) || { } ;
const response = await fetcher ( client . endpoint ( path ) , { ... ( init || { } ) , cache : 'no-store' , credentials : 'same-origin' ,
headers : { Accept : ACCEPT , ... ( ( init && init . body ) ? { 'Content-Type' : 'application/json' } : { } ) , ... customHeaders } } ) ;
if ( ! response . ok ) throw new Error ( ` HUX request failed ( ${ response . status } ) ` ) ;
return response ;
}
function key ( action , target ) { return ` hux: ${ action } : ${ target } ` . slice ( 0 , 120 ) ; }
async function loadAutonomy ( ) {
const scope = encodeURIComponent ( settings . conversationId ) ;
const [ policyResponse , approvalResponse ] = await Promise . all ( [
request ( ` /policy?scope=conversation&scope_id= ${ scope } ` , { method : 'GET' } ) ,
request ( '/approvals?status=pending' , { method : 'GET' } ) ,
] ) ;
policy = normalizePolicy ( await policyResponse . json ( ) , client . identity , settings . conversationId , responseHeader ( policyResponse , 'ETag' ) ) ;
approvals = normalizeApprovalPage ( await approvalResponse . json ( ) , settings . conversationId ) ;
if ( ! policy || ! approvals ) throw new Error ( 'Invalid autonomy response' ) ;
approvals . forEach ( ( item ) => issuedApprovals . add ( item . id ) ) ; renderAutonomy ( ) ;
}
async function savePolicy ( level ) {
if ( ! policy || ! AUTONOMY . has ( level ) ) throw new TypeError ( 'Policy choice is invalid' ) ;
const body = { scope : policy . scope , autonomy : level , grants : policy . grants , budgets : policy . budgets } ;
const response = await request ( '/policy' , { method : 'PUT' , headers : { 'If-Match' : String ( policy . ifMatch ) } , body : JSON . stringify ( body ) } ) ;
const updated = normalizePolicy ( await response . json ( ) , client . identity , settings . conversationId , responseHeader ( response , 'ETag' ) ) ;
if ( ! updated || updated . effectiveScope . level !== 'conversation' || updated . revision <= policy . ifMatch ) throw new Error ( 'Policy revision did not advance' ) ;
policy = updated ; renderAutonomy ( ) ; return policy ;
}
async function decideApproval ( approvalId , choice ) {
if ( ! issuedApprovals . has ( approvalId ) || ! CHOICES . has ( choice ) ) throw new TypeError ( 'Approval decision was not presented here' ) ;
const response = await request ( ` /approvals/ ${ encodeURIComponent ( approvalId ) } ` , { method : 'POST' ,
headers : { 'Idempotency-Key' : key ( ` approval- ${ choice } ` , approvalId ) } , body : JSON . stringify ( { choice } ) } ) ;
const resolved = normalizeApproval ( await response . json ( ) , settings . conversationId , new Set ( [ 'approved' , 'denied' ] ) , choice , client . identity ) ;
if ( ! resolved || resolved . id !== approvalId ) throw new Error ( 'Approval result is invalid' ) ;
issuedApprovals . delete ( approvalId ) ; approvals = approvals . filter ( ( item ) => item . id !== approvalId ) ; renderAutonomy ( ) ; return resolved ;
}
2026-08-24 13:53:00 -03:00
async function refreshApprovals ( ) {
if ( ! client ) return null ;
try {
const response = await request ( '/approvals?status=pending' , { method : 'GET' } ) ;
const page = normalizeApprovalPage ( await response . json ( ) , settings . conversationId ) ;
if ( ! page ) return null ;
approvals = page ; page . forEach ( ( item ) => issuedApprovals . add ( item . id ) ) ;
renderAutonomy ( ) ; return page ;
} catch ( _ ) { return null ; }
}
function startApprovalPolling ( ) {
if ( pollTimer !== null ) return ;
pollTimer = timers ( ) . setInterval ( ( ) => {
if ( typeof settings . canStopModelResponse === 'function' && ! settings . canStopModelResponse ( ) ) return ;
void refreshApprovals ( ) ;
} , pollMs ) ;
if ( pollTimer && typeof pollTimer . unref === 'function' ) pollTimer . unref ( ) ;
}
function stopApprovalPolling ( ) {
if ( pollTimer === null ) return ;
timers ( ) . clearInterval ( pollTimer ) ; pollTimer = null ;
}
function mountInlineDock ( ) {
const host = settings . inlineHost || doc . body || null ;
if ( inlineDock || ! host ) return ;
inlineDock = el ( doc , 'section' , { class : 'hux-runtime-inline-dock' , role : 'region' ,
'aria-label' : 'Approvals needed' , 'aria-live' : 'polite' } ) ;
inlineDock . hidden = true ; host . appendChild ( inlineDock ) ;
}
function approvalCard ( item , choices , extraClass ) {
const card = el ( doc , 'article' , { class : ` hux-runtime-approval ${ extraClass } risk- ${ item . risk } ` } ) ;
card . appendChild ( el ( doc , 'strong' , { } , item . summary ) ) ;
card . appendChild ( el ( doc , 'p' , { } , ` ${ item . capability . replaceAll ( '_' , ' ' ) } · ${ item . risk } risk ${ item . external ? ' · external' : '' } ` ) ) ;
const actions = el ( doc , 'div' , { class : 'hux-runtime-actions' } ) ;
choices . forEach ( ( [ choice , label ] ) => {
const button = el ( doc , 'button' , { type : 'button' } , label ) ;
button . addEventListener ( 'click' , ( ) => { void decideApproval ( item . id , choice ) . catch ( ( ) => card . appendChild ( safeError ( doc ) ) ) ; } ) ;
actions . appendChild ( button ) ;
} ) ;
card . appendChild ( actions ) ; return card ;
}
function renderInline ( ) {
if ( ! inlineDock ) return ;
inlineDock . replaceChildren ( ) ;
const pending = ( approvals || [ ] ) . slice ( ) . sort ( ( a , b ) => b . requestedAt . localeCompare ( a . requestedAt ) ) ;
inlineDock . hidden = pending . length === 0 ;
if ( ! pending . length ) return ;
inlineDock . appendChild ( el ( doc , 'h2' , { class : 'hux-runtime-inline-title' } , 'Approval needed' ) ) ;
pending . slice ( 0 , 3 ) . forEach ( ( item ) => inlineDock . appendChild ( approvalCard ( item ,
[ [ 'once' , 'Allow once' ] , [ 'always' , 'Always allow' ] , [ 'deny' , 'Deny' ] ] , ' hux-runtime-inline-card' ) ) ) ;
if ( pending . length > 3 ) inlineDock . appendChild ( status ( doc , ` ${ pending . length - 3 } more waiting in the workspace drawer. ` ) ) ;
}
2026-08-24 03:08:56 -03:00
async function stopRun ( ) {
if ( typeof settings . stopModelResponse !== 'function' ) throw new TypeError ( 'No owned model response is bound to this view' ) ;
const model = await settings . stopModelResponse ( ) ;
if ( ! record ( model ) || model . accepted !== true ) {
stopMessage = 'Model response stop could not be verified; tool/side-effect cancellation unverified.' ;
renderAutonomy ( ) ; return { modelStopped : false , verified : false } ;
}
stopMessage = UNVERIFIED _STOP ; receipt = null ; renderAutonomy ( ) ;
if ( ! settings . runId ) return { modelStopped : true , verified : false } ;
try {
const body = { conversation _id : settings . conversationId , process _registry _empty : false } ;
const response = await request ( ` /runs/ ${ encodeURIComponent ( settings . runId ) } /stop ` , { method : 'POST' ,
headers : { 'Idempotency-Key' : key ( 'stop' , settings . runId ) } , body : JSON . stringify ( body ) } ) ;
receipt = normalizeReceipt ( await response . json ( ) , settings . runId , settings . conversationId , client . identity ) ;
const verified = Boolean ( receipt && receipt . outcome === 'cancelled' &&
receipt . sideEffects . every ( ( effect ) => effect . reverted ) ) ;
stopMessage = verified ? 'Model response and recorded side effects stopped.' : UNVERIFIED _STOP ;
renderAutonomy ( ) ; return { modelStopped : true , verified , receipt } ;
} catch ( _ ) {
stopMessage = UNVERIFIED _STOP ; renderAutonomy ( ) ;
return { modelStopped : true , verified : false } ;
}
}
function renderAutonomy ( ) {
2026-08-24 13:53:00 -03:00
renderInline ( ) ;
2026-08-24 03:08:56 -03:00
if ( ! autonomyRoot ) return ; autonomyRoot . replaceChildren ( ) ;
if ( ! policy || ! approvals ) { autonomyRoot . appendChild ( status ( doc , 'Loading autonomy controls…' ) ) ; return ; }
const title = el ( doc , 'h2' , { class : 'hux-runtime-title' } , 'Autonomy and approvals' ) ; autonomyRoot . appendChild ( title ) ;
const picker = el ( doc , 'label' , { class : 'hux-runtime-field' } , 'Autonomy level' ) ;
const select = el ( doc , 'select' , { 'aria-label' : 'Autonomy level' } ) ;
[ [ 'ask_first' , 'Ask first' ] , [ 'safe' , 'Safe actions' ] , [ 'autonomous' , 'Autonomous' ] ] . forEach ( ( [ value , label ] ) => {
const option = el ( doc , 'option' , { value } , label ) ; option . selected = value === policy . autonomy ; select . appendChild ( option ) ;
} ) ;
picker . appendChild ( select ) ; const save = el ( doc , 'button' , { type : 'button' } , 'Save autonomy' ) ;
save . addEventListener ( 'click' , ( ) => { void savePolicy ( select . value ) . catch ( ( ) => autonomyRoot . appendChild ( safeError ( doc ) ) ) ; } ) ;
picker . appendChild ( save ) ; autonomyRoot . appendChild ( picker ) ;
const queue = el ( doc , 'section' , { 'aria-labelledby' : 'hux-runtime-approvals' } ) ;
queue . appendChild ( el ( doc , 'h3' , { id : 'hux-runtime-approvals' } , ` Pending approvals ( ${ approvals . length } ) ` ) ) ;
2026-08-24 13:53:00 -03:00
approvals . forEach ( ( item ) => queue . appendChild ( approvalCard ( item ,
[ [ 'once' , 'Allow once' ] , [ 'session' , 'Allow this session' ] , [ 'always' , 'Always allow' ] , [ 'deny' , 'Deny' ] ] , '' ) ) ) ;
2026-08-24 03:08:56 -03:00
autonomyRoot . appendChild ( queue ) ;
const canStop = typeof settings . canStopModelResponse === 'function' && settings . canStopModelResponse ( ) ;
if ( canStop ) { const stop = el ( doc , 'button' , { type : 'button' , class : 'hux-runtime-stop' } , 'Stop model response' ) ;
stop . addEventListener ( 'click' , ( ) => { void stopRun ( ) ; } ) ; autonomyRoot . appendChild ( stop ) ; }
if ( stopMessage ) autonomyRoot . appendChild ( status ( doc , stopMessage ,
stopMessage === 'Model response and recorded side effects stopped.' ? 'status' : 'alert' ) ) ;
if ( receipt ) { const box = el ( doc , 'section' , { class : 'hux-runtime-receipt' , role : 'status' , 'aria-live' : 'polite' } ) ;
box . appendChild ( el ( doc , 'h3' , { } , 'Stop receipt' ) ) ; box . appendChild ( el ( doc , 'p' , { } , ` Outcome: ${ receipt . outcome . replaceAll ( '_' , ' ' ) } ` ) ) ;
const list = el ( doc , 'ul' ) ; receipt . sideEffects . forEach ( ( effect ) => list . appendChild ( el ( doc , 'li' , { } , ` ${ effect . reverted ? 'Reverted' : 'Not reverted' } : ${ effect . description } ` ) ) ) ;
box . appendChild ( list ) ; autonomyRoot . appendChild ( box ) ; }
}
async function loadPrivacy ( ) {
const [ policyResponse , auditResponse ] = await Promise . all ( [
request ( '/privacy/policy' , { method : 'GET' } ) , request ( '/privacy/audit' , { method : 'GET' } ) ,
] ) ;
privacyPolicy = normalizePrivacyPolicy ( await policyResponse . json ( ) , responseHeader ( policyResponse , 'HUX-Audit-Stale' ) ) ;
audits = normalizeAuditPage ( await auditResponse . json ( ) ) ;
if ( ! privacyPolicy || ! audits ) throw new Error ( 'Invalid privacy response' ) ; renderPrivacy ( ) ;
}
async function showPrivacyNotice ( topic ) {
if ( noticeShown || noticePending || ! TOPICS . has ( topic ) || ! client ) return null ;
noticePending = true ; activeTopic = topic ;
try {
const response = await request ( '/privacy/notices' , { method : 'POST' , headers : { 'Idempotency-Key' : key ( 'privacy-notice' , settings . conversationId ) } ,
body : JSON . stringify ( { topic , conversation _id : settings . conversationId } ) } ) ;
privacyNotice = normalizeNotice ( await response . json ( ) , settings . conversationId ) ;
if ( ! privacyNotice ) throw new Error ( 'Invalid privacy notice' ) ; noticeShown = true ; renderPrivacy ( ) ; return privacyNotice ;
} catch ( error ) { activeTopic = null ; privacyNotice = null ; renderPrivacy ( ) ; throw error ; }
finally { noticePending = false ; }
}
async function privacyChoice ( choice ) {
if ( ! privacyNotice || ! privacyNotice . controls . includes ( choice ) ) throw new TypeError ( 'Privacy control was not presented here' ) ;
if ( choice === 'dismiss' ) { activeTopic = null ; privacyNotice = null ; privacyMessage = 'Privacy notice dismissed.' ; renderPrivacy ( ) ; return null ; }
if ( choice === 'forget_this_conversation' ) {
const response = await request ( ` /conversations/ ${ encodeURIComponent ( settings . conversationId ) } /forget ` , { method : 'POST' ,
headers : { 'Idempotency-Key' : key ( 'forget' , settings . conversationId ) } , body : JSON . stringify ( { } ) } ) ;
const result = normalizeForget ( await response . json ( ) , settings . conversationId ) ;
if ( ! result ) throw new Error ( 'Forget result is invalid' ) ; privacyMessage = ` Conversation forgotten; ${ result . memoryForgotten } memory entries removed. ` ;
} else {
const response = await request ( '/privacy/notices' , { method : 'POST' , headers : { 'Idempotency-Key' : key ( ` privacy- ${ choice } ` , settings . conversationId ) } ,
body : JSON . stringify ( { topic : activeTopic , conversation _id : settings . conversationId , chosen : choice } ) } ) ;
if ( ! normalizeNotice ( await response . json ( ) , settings . conversationId ) ) throw new Error ( 'Privacy choice is invalid' ) ;
if ( choice === 'switch_to_private' && typeof settings . onPrivateMode === 'function' ) await settings . onPrivateMode ( ) ;
privacyMessage = choice === 'disable_memory_here' ? 'Memory is disabled for this conversation.' : 'Private mode was requested.' ;
}
activeTopic = null ; privacyNotice = null ; renderPrivacy ( ) ; return true ;
}
function renderPrivacy ( ) {
if ( ! privacyRoot ) return ; privacyRoot . replaceChildren ( ) ;
if ( ! privacyPolicy || ! audits ) { privacyRoot . appendChild ( status ( doc , 'Loading privacy controls…' ) ) ; return ; }
privacyRoot . appendChild ( el ( doc , 'h2' , { class : 'hux-runtime-title' } , 'Privacy and retention' ) ) ;
const summary = el ( doc , 'dl' , { class : 'hux-runtime-summary' , 'aria-label' : 'Privacy policy summary' } ) ;
[ [ 'Sensitive categories' , ` ${ privacyPolicy . protectedCount } protected ` ] , [ 'Context minimization' , ` ${ privacyPolicy . shortestDecay } – ${ privacyPolicy . longestDecay } days ` ] ,
[ 'Cross-surface sharing' , privacyPolicy . crossSurfaceSharing === 'never' ? 'Never' : 'Same owner only' ] , [ 'Retention audit' , privacyPolicy . auditStale ? 'Overdue' : ` Every ${ privacyPolicy . auditIntervalDays } days ` ] ] . forEach ( ( [ term , value ] ) => {
const row = el ( doc , 'div' ) ; row . appendChild ( el ( doc , 'dt' , { } , term ) ) ; row . appendChild ( el ( doc , 'dd' , { } , value ) ) ; summary . appendChild ( row ) ;
} ) ;
privacyRoot . appendChild ( summary ) ;
privacyRoot . appendChild ( el ( doc , 'p' , { class : 'hux-runtime-minimize' } , 'When the topic changes, prior sensitive details are not repeated.' ) ) ;
if ( privacyNotice ) { const notice = el ( doc , 'aside' , { class : 'hux-runtime-notice' , 'aria-labelledby' : 'hux-runtime-privacy-notice' } ) ;
notice . appendChild ( el ( doc , 'h3' , { id : 'hux-runtime-privacy-notice' } , 'Sensitive-topic protection' ) ) ; notice . appendChild ( el ( doc , 'p' , { } , privacyNotice . text ) ) ;
const actions = el ( doc , 'div' , { class : 'hux-runtime-actions' } ) ; privacyNotice . controls . forEach ( ( choice ) => { const button = el ( doc , 'button' , { type : 'button' } , choice . replaceAll ( '_' , ' ' ) ) ;
button . addEventListener ( 'click' , ( ) => { void privacyChoice ( choice ) . catch ( ( ) => notice . appendChild ( safeError ( doc ) ) ) ; } ) ; actions . appendChild ( button ) ; } ) ; notice . appendChild ( actions ) ; privacyRoot . appendChild ( notice ) ; }
const latest = audits [ 0 ] ; privacyRoot . appendChild ( status ( doc , latest ? ` Last retention audit: ${ latest . ranAt } ; ${ latest . affected } records affected. ` : 'No retention audit has been recorded.' ) ) ;
if ( privacyMessage ) privacyRoot . appendChild ( status ( doc , privacyMessage ) ) ;
}
const autonomyExtension = { id : 'autonomy-controls' , flag : 'hux.autonomy' , label : 'Autonomy' , order : 30 , render ( context ) {
2026-08-24 13:53:00 -03:00
client = assertClient ( context . client , 'hux.autonomy' ) ; autonomyRoot = context . container ;
mountInlineDock ( ) ; renderAutonomy ( ) ;
2026-08-24 03:08:56 -03:00
const target = autonomyRoot ;
void loadAutonomy ( ) . catch ( ( ) => { if ( autonomyRoot === target ) target . replaceChildren ( safeError ( doc ) ) ; } ) ;
2026-08-24 13:53:00 -03:00
startApprovalPolling ( ) ;
2026-08-24 03:08:56 -03:00
} } ;
const privacyExtension = { id : 'privacy-controls' , flag : 'hux.privacy' , label : 'Privacy' , order : 40 , render ( context ) {
client = assertClient ( context . client , 'hux.privacy' ) ; privacyRoot = context . container ; renderPrivacy ( ) ;
const target = privacyRoot ;
void loadPrivacy ( ) . catch ( ( ) => { if ( privacyRoot === target ) target . replaceChildren ( safeError ( doc ) ) ; } ) ;
} } ;
function register ( shell ) { if ( ! shell || typeof shell . register !== 'function' ) throw new TypeError ( 'HUX shell is required' ) ;
const removeAutonomy = shell . register ( autonomyExtension ) ; const removePrivacy = shell . register ( privacyExtension ) ;
return ( ) => { removePrivacy ( ) ; removeAutonomy ( ) ; } ; }
function destroy ( ) {
2026-08-24 13:53:00 -03:00
stopApprovalPolling ( ) ;
if ( inlineDock && inlineDock . parentNode ) inlineDock . parentNode . removeChild ( inlineDock ) ;
inlineDock = null ;
2026-08-24 03:08:56 -03:00
client = null ; autonomyRoot = null ; privacyRoot = null ; policy = null ; approvals = [ ] ;
receipt = null ; privacyPolicy = null ; audits = [ ] ; activeTopic = null ; privacyNotice = null ;
stopMessage = '' ; issuedApprovals . clear ( ) ;
}
return Object . freeze ( { extensions : Object . freeze ( [ autonomyExtension , privacyExtension ] ) , register , destroy ,
showPrivacyNotice , clearPrivacyNotice ( ) { activeTopic = null ; privacyNotice = null ; if ( privacyRoot ) renderPrivacy ( ) ; } ,
2026-08-24 13:53:00 -03:00
savePolicy , decideApproval , refreshApprovals , stopRun , privacyChoice } ) ;
2026-08-24 03:08:56 -03:00
}
function createAutonomyPrivacyRuntime ( options ) {
const settings = options || { } ;
const doc = settings . document || ( typeof document === 'object' ? document : null ) ;
if ( ! doc ) throw new TypeError ( 'Autonomy/privacy runtime requires a document' ) ;
const client = contract . createCanonicalClient ( settings ) ;
const shell = shellApi . createShell ( { client , document : doc ,
instanceId : settings . instanceId || 'governance' } ) ;
const runtime = createRuntime ( settings ) ;
const removers = runtime . extensions . map ( ( extension ) => shell . register ( extension ) ) ;
let mounted = false ; let destroyed = false ;
return Object . freeze ( { client ,
async mount ( target ) {
if ( destroyed ) throw new Error ( 'Autonomy/privacy runtime was destroyed' ) ;
if ( mounted ) throw new Error ( 'Autonomy/privacy runtime is already mounted' ) ;
mounted = true ; shell . mount ( target ) ; await client . negotiate ( ) ;
} ,
destroy ( ) {
if ( destroyed ) return ;
destroyed = true ; shell . destroy ( ) ;
removers . slice ( ) . reverse ( ) . forEach ( ( remove ) => remove ( ) ) ;
runtime . destroy ( ) ; mounted = false ;
} ,
} ) ;
}
return Object . freeze ( { GENERIC _NOTICE , UNVERIFIED _STOP , createAutonomyPrivacyRuntime , createRuntime ,
normalizeApproval , normalizeApprovalPage , normalizeAuditPage ,
normalizeForget , normalizeNotice , normalizePolicy , normalizePrivacyPolicy , normalizeReceipt } ) ;
} ) ) ;