wip(13-08): checkpoint before operator session restart — Task 1 GREEN (28/28), Task 2 in progress
Executor stopped deliberately for a session restart (bypass-permissions relaunch). Executor's final report: 'cargo test assistant confirm-gate suite 28/28 green, individual nonce test passes; committing Task 1 next — first verify the tools.rs/grants.rs/backends diffs are formatting-only.' Task 1 (D-07/D-11 confirm gate, backend) is implemented and test-green but this checkpoint is verbatim-uncommitted-state, NOT the reviewed atomic Task 1 commit: continuation executor should verify diffs, then reset --soft or commit-on-top into proper feat(13-08) task commits. Task 2 (ToolConfirmModal.vue trusted chrome, Chat.vue + contextBroker.ts wiring) is partially built, tests written. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
db11c625c8
commit
fc09d7a292
@@ -70,6 +70,21 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 13-08 (D-11): the destructive-tool confirmation dialog — trusted
|
||||
chrome, mounted as a SIBLING of the iframe, never inside it. The
|
||||
component Teleports to body with a full-screen backdrop, so it
|
||||
covers the whole viewport including the area over the iframe, and
|
||||
no ancestor transform can trap its position: fixed. Its text is
|
||||
node-authored, fetched by the ContextBroker over the page's own
|
||||
RPC session — nothing the iframe sends can open or resolve it. -->
|
||||
<ToolConfirmModal
|
||||
:show="!!toolConfirm"
|
||||
:description="toolConfirm?.description ?? ''"
|
||||
@approve="resolveToolConfirm(true)"
|
||||
@deny="resolveToolConfirm(false)"
|
||||
@dismiss="dismissToolConfirm"
|
||||
/>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -78,6 +93,7 @@ import { ref, computed, onActivated, onBeforeUnmount, onDeactivated, onMounted,
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { ContextBroker } from '@/services/contextBroker'
|
||||
import ToolConfirmModal from '@/components/ToolConfirmModal.vue'
|
||||
import { IS_DEMO } from '@/composables/useDemoIntro'
|
||||
|
||||
const { t } = useI18n()
|
||||
@@ -170,6 +186,37 @@ function closeChat() {
|
||||
}
|
||||
}
|
||||
|
||||
// 13-08 (D-11): the pending destructive-tool confirmation the trusted
|
||||
// chrome is currently showing. Set ONLY from the ContextBroker's
|
||||
// aiui:tool-confirm-request CustomEvent, whose payload is node-fetched
|
||||
// over the page's own RPC session — never from anything the iframe posts.
|
||||
const toolConfirm = ref<{ reqId: string; description: string } | null>(null)
|
||||
|
||||
function onToolConfirmRequest(e: Event) {
|
||||
const detail = (e as CustomEvent).detail as { reqId?: string; description?: string }
|
||||
if (!detail?.reqId || typeof detail.description !== 'string') return
|
||||
toolConfirm.value = { reqId: detail.reqId, description: detail.description }
|
||||
}
|
||||
|
||||
function resolveToolConfirm(approved: boolean) {
|
||||
const current = toolConfirm.value
|
||||
toolConfirm.value = null
|
||||
if (!current) return
|
||||
// The decision travels back to the broker (and from there to the node
|
||||
// over the authenticated RPC session) — never through the iframe.
|
||||
window.dispatchEvent(
|
||||
new CustomEvent('aiui:tool-confirm-response', {
|
||||
detail: { reqId: current.reqId, approved },
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
function dismissToolConfirm() {
|
||||
// Closed without a decision: send nothing. The action stays pending on
|
||||
// the node until its own timeout declines it — never silently approved.
|
||||
toolConfirm.value = null
|
||||
}
|
||||
|
||||
function onAiuiMessage(event: MessageEvent) {
|
||||
if (!aiuiUrl.value) return
|
||||
// Validate origin — only accept messages from AIUI
|
||||
@@ -197,6 +244,8 @@ function onAiuiMessage(event: MessageEvent) {
|
||||
function armChatLive() {
|
||||
window.removeEventListener('message', onAiuiMessage)
|
||||
window.addEventListener('message', onAiuiMessage)
|
||||
window.removeEventListener('aiui:tool-confirm-request', onToolConfirmRequest)
|
||||
window.addEventListener('aiui:tool-confirm-request', onToolConfirmRequest)
|
||||
broker?.stop()
|
||||
broker = null
|
||||
if (aiuiUrl.value) {
|
||||
@@ -216,6 +265,7 @@ onActivated(() => armChatLive())
|
||||
|
||||
onDeactivated(() => {
|
||||
window.removeEventListener('message', onAiuiMessage)
|
||||
window.removeEventListener('aiui:tool-confirm-request', onToolConfirmRequest)
|
||||
broker?.stop()
|
||||
broker = null
|
||||
if (loadTimeout) { clearTimeout(loadTimeout); loadTimeout = null }
|
||||
@@ -229,6 +279,7 @@ onMounted(() => armChatLive())
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener('message', onAiuiMessage)
|
||||
window.removeEventListener('aiui:tool-confirm-request', onToolConfirmRequest)
|
||||
broker?.stop()
|
||||
broker = null
|
||||
if (loadTimeout) { clearTimeout(loadTimeout); loadTimeout = null }
|
||||
|
||||
Reference in New Issue
Block a user