#!/usr/bin/env node /** * Prove the /admin configuration loop without Slack network access: * 1. mount the real Hono admin routes against an in-memory SQLite store, * 2. establish an exact Slack-bound Owner and authenticate as that principal, * 3. create two Agents and publish both to one Channel through the additive grant API, * 4. prove the Channel inventory exposes both grants without one replacing the other, * 5. prove the one-body Agent memory contract and optimistic edits while the * retired Channel/file/history memory surfaces remain unavailable. */ import { assertNodeVersion, loadTsModule, } from './lib/offline-harness.mjs'; import { mkdtempSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; const ADMIN_ORIGIN = 'https://admin-ui.example'; const WORKSPACE_ID = 'TADMINUI1'; const CHANNEL_ID = 'C_ADMIN_UI'; const CHANNEL_LABEL = 'eng-releases'; const AGENT_ID = 'agent_admin_ui'; const MODEL_SPECIFIER = 'local-stub/admin-ui-model'; const ROUTINE_ID = 'routine_admin_ui_release'; const results = []; function record(name, passed, detail) { results.push({ name, passed, detail }); console.log(`${passed ? 'PASS' : 'FAIL'} ${name}${detail ? ` - ${detail}` : ''}`); } async function adminJson(app, path, options = {}) { const response = await app.request(path.startsWith('http') ? path : `${ADMIN_ORIGIN}${path}`, { ...options, headers: { origin: ADMIN_ORIGIN, 'sec-fetch-site': 'same-origin', ...(options.headers ?? {}), }, }); const text = await response.text(); let body; try { body = text ? JSON.parse(text) : undefined; } catch { body = text; } return { status: response.status, body }; } async function adminBody(app, method, path, body) { return adminJson(app, path, { method, headers: { 'content-type': 'application/json' }, body: JSON.stringify(body), }); } let store; let settings; let memory; let routines; let usage; let work; let identity; try { console.log(`node ${assertNodeVersion()}`); const { Hono } = await import('hono'); const { createAdminRoutes } = await loadTsModule('src/admin/routes.ts'); const { SqliteConfigStore } = await loadTsModule('src/config/store.ts'); const { SqliteSettingsStore } = await loadTsModule('src/config/settings-store.ts'); const { SqliteMemoryStateStore } = await loadTsModule('src/memory/store.ts'); const { agentRoutineDeletion, SqliteRoutineStore } = await loadTsModule('src/routines/store.ts'); const { RoutineService } = await loadTsModule('src/routines/service.ts'); const { SqliteUsageStore } = await loadTsModule('src/usage/store.ts'); const { SqliteWorkStore } = await loadTsModule('src/work/store.ts'); const { SqliteIdentityStore } = await loadTsModule('src/identity/store.ts'); const statePath = join(mkdtempSync(join(tmpdir(), 'chickpea-admin-ui-')), 'state.db'); store = new SqliteConfigStore(statePath, agentRoutineDeletion, { agents: [], grants: [] }); settings = new SqliteSettingsStore(statePath); memory = new SqliteMemoryStateStore(statePath); routines = new SqliteRoutineStore(statePath); usage = new SqliteUsageStore(statePath); work = new SqliteWorkStore(statePath); identity = new SqliteIdentityStore(statePath); const ownerOperation = await identity.createAuthOperation({ id: 'first_owner_admin_ui', kind: 'first_owner_claim', expectedSlackTeamId: 'TADMINUI1', expectedSlackUserId: 'UADMINUI1', chickpeaRole: 'owner', capabilityHash: 'a'.repeat(64), expiresAt: Date.now() + 60_000, }); await identity.createOwnerClaim({ operationId: ownerOperation.id, slackTeamId: 'TADMINUI1', slackUserId: 'UADMINUI1', }); await identity.advanceAuthOperation({ operationId: ownerOperation.id, capabilityHash: 'a'.repeat(64), step: 1, betterAuthUserId: 'ba_user_admin_ui', betterAuthOrganizationId: '11111111-1111-4111-8111-111111111111', betterAuthMembershipId: 'ba_member_admin_ui', }); const owner = await identity.claimOwner({ operationId: ownerOperation.id, organizationId: 'org_oss', slackTeamId: 'TADMINUI1', slackUserId: 'UADMINUI1', displayName: 'Admin UI Owner', betterAuthUserId: 'ba_user_admin_ui', betterAuthMembershipId: 'ba_member_admin_ui', }); await identity.updateOrganizationAuth({ organizationId: owner.membership.organizationId, authMode: 'slack_active', canonicalAdminOrigin: ADMIN_ORIGIN, }); const authControl = await identity.getAuthControl(); await identity.updateAuthControl({ expectedRevision: authControl.revision, canonicalAdminOrigin: ADMIN_ORIGIN, }); const usageNow = Date.now(); await work.admitShadowRun({ work: { id: 'work_admin_ui_release', kind: 'conversation', maximumSensitivity: 'public', createdAt: usageNow - 10_000, }, binding: { id: 'binding_admin_ui_release', workId: 'work_admin_ui_release', adapterKind: 'slack', externalAccountId: 'account_admin_ui_release', externalConversationId: 'conversation_admin_ui_release', generation: 1, sourceVisibility: 'public', configMode: 'frozen_on_open', orderingKey: 'ordering_admin_ui_release', createdAt: usageNow - 10_000, }, run: { id: 'run_admin_ui_release', workId: 'work_admin_ui_release', bindingId: 'binding_admin_ui_release', kind: 'interactive', triggerKind: 'admin_ui_verifier', triggerRef: 'trigger_admin_ui_release', dedupeKey: 'dedupe_admin_ui_release', actorTrustTier: 'system', effectiveCapabilityDigest: 'b'.repeat(64), executionAuthority: 'legacy', coordinatorKind: 'interactive', authorityEpoch: 1, createdAt: usageNow - 10_000, }, safeConfig: { schemaVersion: 1, profileId: AGENT_ID, configuredModel: MODEL_SPECIFIER, snapshotDigest: 'a'.repeat(64), capabilityDigest: 'b'.repeat(64), skillNames: [], connectionIds: [], repositoryIds: [], memoryMode: 'public', ceilings: { maxModelAttempts: 3, maxToolCalls: 20, maxActionAttempts: 0, timeoutMs: 120_000 }, }, triggerContent: { sensitivity: 'public', body: 'Admin UI Run trigger' }, auditEventId: 'audit_admin_ui_release', auditIdempotencyKey: 'auditkey_admin_ui_release', }); await usage.admitOperation({ operationId: 'usage_admin_ui_release', runId: 'run_admin_ui_release', operationKind: 'interactive_turn', sourceId: 'slack:C_ADMIN_UI:usage', startedAt: usageNow - 10_000, installationId: 'admin-ui-installation', workspaceId: WORKSPACE_ID, agentId: AGENT_ID, agentLabel: 'Admin UI Agent', channelId: CHANNEL_ID, channelLabel: CHANNEL_LABEL, conversationKind: 'named_channel', requestedProvider: 'openai', requestedModel: 'gpt-4.1-mini', credentialRefId: 'cred_openai_admin_ui', credentialVersion: 1, }); await usage.recordTerminal({ operationId: 'usage_admin_ui_release', executionId: 'usage_exec_admin_ui_release', status: 'completed', finishedAt: usageNow - 5_000, observedAt: usageNow - 5_000, providerRoute: 'openai', requestedProvider: 'openai', requestedModel: 'gpt-4.1-mini', returnedProvider: 'openai', returnedModel: 'gpt-4.1-mini', credentialRefId: 'cred_openai_admin_ui', credentialVersion: 1, usageCompleteness: 'complete', inputTokens: 1_000, outputTokens: 250, totalTokens: 1_250, usageUnknownReason: null, estimateCompleteness: 'complete', estimateAmountMicros: 800, estimateCurrency: 'USD', priceVersionId: 'openai_2026-07-28', priceUnknownReason: null, }); const routineService = new RoutineService(routines, { now: Date.now, routineId: () => ROUTINE_ID, }); const routine = await routineService.save({ action: 'create', actorId: 'U_ADMIN_UI_MEMBER', workspaceId: WORKSPACE_ID, channelId: CHANNEL_ID, definition: { name: 'Release readiness check', description: 'Checks launch blockers every weekday.', taskText: 'Review launch blockers and make safe progress.', triggerKind: 'schedule', scheduleInput: '0 9 * * 1-5', scheduleJson: '{"version":1,"kind":"cron","expression":"0 9 * * 1-5"}', timezone: 'America/Los_Angeles', outputPolicy: 'post', authorityMode: 'live_channel_v1', }, nextRunAt: Date.now() + 3_600_000, projectedDailyStarts: 5, reservations: [{ windowStart: Date.now() + 3_600_000, count: 1 }], sourceVisibility: 'public', }, 'admin-ui-routine-create'); await routines.createOccurrence({ runId: 'rrun_admin_ui_release', idempotencyKey: 'admin-ui-routine-run', routineId: routine.id, routineVersion: routine.version, scheduledFor: Date.now(), triggerSource: 'run_now', requestedBy: 'U_ADMIN_UI_MEMBER', queuedAt: Date.now(), deadlineAt: Date.now() + 900_000, }); const app = new Hono(); const userGroups = []; const slackChannel = { id: CHANNEL_ID, name: CHANNEL_LABEL, private: false, member: true, archived: false, }; const slackTransport = { mode: 'direct', async lookupMember(userId) { return { id: userId, teamId: WORKSPACE_ID, deleted: false, bot: false, appUser: false, restricted: false, ultraRestricted: false, stranger: false }; }, async lookupChannel() { return slackChannel; }, async listChannels() { return { channels: [slackChannel], truncated: false }; }, async channelHasMember() { return true; }, async openDirectConversation(userId) { return { ...slackChannel, id: `D_${userId}`, private: true }; }, async joinPublicChannel() { return slackChannel; }, async listUserGroups() { return [...userGroups]; }, async createUserGroup(input) { const group = { id: `S${userGroups.length + 1}`, ...input, disabled: false, updatedAt: Math.floor(Date.now() / 1000) }; userGroups.push(group); return group; }, async updateUserGroup(id, patch) { const group = userGroups.find((candidate) => candidate.id === id); Object.assign(group, patch); return group; }, async disableUserGroup(id) { return this.updateUserGroup(id, { disabled: true }); }, async enableUserGroup(id) { return this.updateUserGroup(id, { disabled: false }); }, async publishAppHome() { return {}; }, async postMessage() { return { channelId: CHANNEL_ID, ts: '1.0' }; }, }; app.route( '/', createAdminRoutes({ store, settings, memory, routines, usage, work, identity, usageAdminUi: true, authService: { async authenticateRequest() { return { userId: owner.user.id, membershipId: owner.membership.id, organizationId: owner.membership.organizationId, role: 'owner', authenticatorKind: 'better_auth', credentialId: 'better_auth_session_admin_ui', correlationId: 'request_admin_ui_verifier', machine: false, }; }, }, knownProviders: new Set(['local-stub']), slackTransport, routineCapability: () => ({ target: 'cloudflare', available: true, enabled: true, reason: 'enabled', }), }), ); const retiredLogin = await app.request(`${ADMIN_ORIGIN}/admin/login`, { method: 'POST' }); const pageResponse = await app.request(`${ADMIN_ORIGIN}/admin`); const pageHtml = await pageResponse.text(); // Follow the production shell's asset references. Inspecting only the HTML // silently lost the client application when it moved out of inline scripts. const scriptPath = pageHtml.match(/