mirror of
https://github.com/myronblair/jarvis
synced 2026-06-30 17:50:23 -05:00
Phase 9: Clearance Protocol — intercept, approve/deny, HUD, voice commands
- reactor.py v9.0.0: clearance endpoints, watchdog, create_job intercept - arc.php: 7 clearance actions (pending/history/approve/deny/rules/rule_update/create) - chat.php: Tier 0.9j voice commands — approve/deny/status clearance - index.html: clearance banner, CLEARANCE tab with pending requests + rules + history - admin/index.php: CLEARANCE nav + tab with full CRUD for rules and approve/deny UI
This commit is contained in:
@@ -292,6 +292,52 @@ switch ($action) {
|
||||
echo json_encode(arc_request('PUT', "/missions/{$id}", ['enabled' => $enabled]));
|
||||
break;
|
||||
|
||||
// GET /api/arc?action=clearance_pending
|
||||
case 'clearance_pending':
|
||||
echo json_encode(arc_request('GET', '/clearance/pending'));
|
||||
break;
|
||||
|
||||
// GET /api/arc?action=clearance_history
|
||||
case 'clearance_history':
|
||||
$limit = (int)($_GET['limit'] ?? 50);
|
||||
echo json_encode(arc_request('GET', "/clearance/history?limit={$limit}"));
|
||||
break;
|
||||
|
||||
// POST /api/arc?action=clearance_approve&id=123 body: { decided_by: "..." }
|
||||
case 'clearance_approve':
|
||||
$id = (int)($_GET['id'] ?? $data['id'] ?? 0);
|
||||
if (!$id) { http_response_code(400); echo json_encode(['error' => 'Missing id']); break; }
|
||||
$decided_by = $data['decided_by'] ?? 'admin';
|
||||
echo json_encode(arc_request('POST', "/clearance/{$id}/approve", ['decided_by' => $decided_by]));
|
||||
break;
|
||||
|
||||
// POST /api/arc?action=clearance_deny&id=123 body: { decided_by: "...", note: "..." }
|
||||
case 'clearance_deny':
|
||||
$id = (int)($_GET['id'] ?? $data['id'] ?? 0);
|
||||
if (!$id) { http_response_code(400); echo json_encode(['error' => 'Missing id']); break; }
|
||||
$decided_by = $data['decided_by'] ?? 'admin';
|
||||
$note = $data['note'] ?? '';
|
||||
echo json_encode(arc_request('POST', "/clearance/{$id}/deny", ['decided_by' => $decided_by, 'note' => $note]));
|
||||
break;
|
||||
|
||||
// GET /api/arc?action=clearance_rules
|
||||
case 'clearance_rules':
|
||||
echo json_encode(arc_request('GET', '/clearance/rules'));
|
||||
break;
|
||||
|
||||
// PUT /api/arc?action=clearance_rule_update&id=123 body: { require_approval: 0|1, auto_approve_after_min: N, ... }
|
||||
case 'clearance_rule_update':
|
||||
$id = (int)($_GET['id'] ?? $data['id'] ?? 0);
|
||||
if (!$id) { http_response_code(400); echo json_encode(['error' => 'Missing id']); break; }
|
||||
unset($data['id']);
|
||||
echo json_encode(arc_request('PUT', "/clearance/rules/{$id}", $data));
|
||||
break;
|
||||
|
||||
// POST /api/arc?action=clearance_rule_create body: { job_type, risk_level, require_approval, ... }
|
||||
case 'clearance_rule_create':
|
||||
echo json_encode(arc_request('POST', '/clearance/rules', $data));
|
||||
break;
|
||||
|
||||
default:
|
||||
http_response_code(404);
|
||||
echo json_encode(['error' => "Unknown arc action: {$action}"]);
|
||||
|
||||
@@ -1082,6 +1082,33 @@ if (!$reply && preg_match('/\b(news|headlines|latest|what.?s happening|current e
|
||||
$arcJobId = null;
|
||||
|
||||
// Helper: submit job to Arc Reactor
|
||||
function arcPost(string $path, array $body): ?array {
|
||||
$ch = curl_init('http://127.0.0.1:7474' . $path);
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_POST => true,
|
||||
CURLOPT_POSTFIELDS => json_encode($body),
|
||||
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
|
||||
CURLOPT_TIMEOUT => 5,
|
||||
CURLOPT_CONNECTTIMEOUT => 3,
|
||||
]);
|
||||
$res = json_decode(curl_exec($ch), true);
|
||||
curl_close($ch);
|
||||
return $res;
|
||||
}
|
||||
|
||||
function arcGet(string $path): ?array {
|
||||
$ch = curl_init('http://127.0.0.1:7474' . $path);
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_TIMEOUT => 5,
|
||||
CURLOPT_CONNECTTIMEOUT => 3,
|
||||
]);
|
||||
$res = json_decode(curl_exec($ch), true);
|
||||
curl_close($ch);
|
||||
return $res;
|
||||
}
|
||||
|
||||
function arcSubmitJob(string $type, array $payload, string $sessionId): ?array {
|
||||
$ch = curl_init('http://127.0.0.1:7474/job');
|
||||
curl_setopt_array($ch, [
|
||||
@@ -1395,6 +1422,65 @@ if (!$reply) {
|
||||
}
|
||||
}
|
||||
|
||||
// ── Tier 0.9j: Clearance Protocol — approve/deny voice commands ─────────────
|
||||
if (!$reply) {
|
||||
// "approve clearance 5", "authorize clearance", "approve all clearance"
|
||||
if (preg_match('/^(?:jarvis[,\s]+)?(?:approve|authorize|grant)\s+(?:all\s+)?clearance(?:\s+(?:request\s+)?#?(\d+))?/i', $message, $m)) {
|
||||
$crId = isset($m[1]) && $m[1] ? (int)$m[1] : null;
|
||||
if ($crId) {
|
||||
$resp = arcPost('/clearance/' . $crId . '/approve', ['decided_by' => 'voice']);
|
||||
if (isset($resp['ok']) && $resp['ok']) {
|
||||
$reply = "◈ Clearance request #{$crId} authorized, {$userAddr}. Job dispatched.";
|
||||
} else {
|
||||
$reply = "Clearance #{$crId} not found or already decided.";
|
||||
}
|
||||
} else {
|
||||
// Approve all pending
|
||||
$pending = arcGet('/clearance/pending') ?: [];
|
||||
if (empty($pending)) {
|
||||
$reply = "No pending clearance requests, {$userAddr}.";
|
||||
} else {
|
||||
$approved = 0;
|
||||
foreach ($pending as $cr) {
|
||||
$resp = arcPost('/clearance/' . $cr['id'] . '/approve', ['decided_by' => 'voice']);
|
||||
if (isset($resp['ok']) && $resp['ok']) $approved++;
|
||||
}
|
||||
$reply = "◈ Authorized {$approved} clearance request" . ($approved !== 1 ? 's' : '') . ", {$userAddr}.";
|
||||
}
|
||||
}
|
||||
$source = 'arc:clearance_approve';
|
||||
}
|
||||
}
|
||||
if (!$reply) {
|
||||
// "deny clearance 5", "reject clearance 5"
|
||||
if (preg_match('/^(?:jarvis[,\s]+)?(?:deny|reject|refuse)\s+clearance(?:\s+(?:request\s+)?#?(\d+))?/i', $message, $m)) {
|
||||
$crId = isset($m[1]) && $m[1] ? (int)$m[1] : null;
|
||||
if ($crId) {
|
||||
$resp = arcPost('/clearance/' . $crId . '/deny', ['decided_by' => 'voice', 'note' => 'denied by voice command']);
|
||||
$reply = isset($resp['ok']) && $resp['ok']
|
||||
? "Clearance #{$crId} denied, {$userAddr}."
|
||||
: "Clearance #{$crId} not found or already decided.";
|
||||
} else {
|
||||
$reply = "Which clearance request should I deny? Say: deny clearance [number].";
|
||||
}
|
||||
$source = 'arc:clearance_deny';
|
||||
}
|
||||
}
|
||||
if (!$reply) {
|
||||
// "any pending clearance", "clearance status", "show clearance"
|
||||
if (preg_match('/^(?:jarvis[,\s]+)?(?:(?:any\s+|show\s+)?pending\s+clearance|clearance\s+(?:status|requests?|pending|queue))/i', $message)) {
|
||||
$pending = arcGet('/clearance/pending') ?: [];
|
||||
$count = count($pending);
|
||||
if ($count === 0) {
|
||||
$reply = "No pending clearance requests, {$userAddr}. All clear.";
|
||||
} else {
|
||||
$list = array_map(fn($cr) => "#{$cr['id']} {$cr['job_type']} ({$cr['risk_level']})", $pending);
|
||||
$reply = "◈ {$count} pending clearance request" . ($count !== 1 ? 's' : '') . ": " . implode(', ', $list) . ". Say 'approve clearance [number]' to authorize.";
|
||||
}
|
||||
$source = 'arc:clearance_status';
|
||||
}
|
||||
}
|
||||
|
||||
// ── Tier 1: Intent Engine (instant, no LLM) ───────────────────────────────
|
||||
if (!$reply) {
|
||||
$matched = KBEngine::match($message);
|
||||
|
||||
Reference in New Issue
Block a user