2026-08-04 02:46:53 -07:00
|
|
|
using System.Text.Encodings.Web;
|
|
|
|
|
using System.Text.Json;
|
|
|
|
|
|
|
|
|
|
namespace NucleicProtocol.Interop;
|
|
|
|
|
|
|
|
|
|
/// Small typed constructors for the renderer's first intents. Swift remains the decoder and
|
|
|
|
|
/// source of truth; these helpers only keep hand-written UI JSON out of call sites.
|
|
|
|
|
public static class ClientIntents
|
|
|
|
|
{
|
|
|
|
|
public static string ListSessions() => TagOnly("listSessions");
|
|
|
|
|
public static string ListDashboard() => TagOnly("listDashboard");
|
|
|
|
|
public static string ListPeers() => TagOnly("listPeers");
|
|
|
|
|
public static string Ping() => TagOnly("ping");
|
|
|
|
|
|
|
|
|
|
public static string Subscribe(string sessionId, ulong? sinceSequence = null, string verbosity = "full") =>
|
|
|
|
|
Write(writer =>
|
|
|
|
|
{
|
|
|
|
|
writer.WriteString("sessionID", sessionId);
|
|
|
|
|
if (sinceSequence is { } sequence) writer.WriteNumber("sinceSeq", sequence);
|
|
|
|
|
writer.WriteString("t", "subscribe");
|
|
|
|
|
writer.WriteString("verbosity", verbosity);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
public static string Unsubscribe(string sessionId) => Write(writer =>
|
|
|
|
|
{
|
|
|
|
|
writer.WriteString("sessionID", sessionId);
|
|
|
|
|
writer.WriteString("t", "unsubscribe");
|
|
|
|
|
});
|
|
|
|
|
|
2026-08-04 03:10:06 -07:00
|
|
|
public static string ApprovalAllow(string approvalId, JsonElement? updatedInput = null) =>
|
|
|
|
|
ApprovalRespond(approvalId, "allow", updatedInput: updatedInput);
|
|
|
|
|
|
|
|
|
|
public static string ApprovalDeny(string approvalId, string? reason = null) =>
|
|
|
|
|
ApprovalRespond(approvalId, "deny", reason: reason);
|
|
|
|
|
|
|
|
|
|
public static string ApprovalAllowAlways(string approvalId, ApprovalAlwaysScope scope) =>
|
|
|
|
|
ApprovalRespond(approvalId, "allowAlways", scope: ScopeValue(scope));
|
|
|
|
|
|
|
|
|
|
public static string ApprovalCancelRun(string approvalId) =>
|
|
|
|
|
ApprovalRespond(approvalId, "cancelRun");
|
2026-08-04 02:46:53 -07:00
|
|
|
|
|
|
|
|
public static string SendInput(string sessionId, string text) => Write(writer =>
|
|
|
|
|
{
|
|
|
|
|
writer.WritePropertyName("input");
|
|
|
|
|
writer.WriteStartObject();
|
|
|
|
|
writer.WritePropertyName("parts");
|
|
|
|
|
writer.WriteStartArray();
|
|
|
|
|
writer.WriteStartObject();
|
|
|
|
|
writer.WriteString("text", text);
|
|
|
|
|
writer.WriteString("type", "text");
|
|
|
|
|
writer.WriteEndObject();
|
|
|
|
|
writer.WriteEndArray();
|
|
|
|
|
writer.WriteEndObject();
|
|
|
|
|
writer.WriteString("sessionID", sessionId);
|
|
|
|
|
writer.WriteString("t", "sendInput");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
private static string TagOnly(string tag) => JsonSerializer.Serialize(
|
|
|
|
|
new TagOnlyIntent(tag), ProtocolJsonContext.Default.TagOnlyIntent);
|
|
|
|
|
|
2026-08-04 03:10:06 -07:00
|
|
|
private static string ApprovalRespond(
|
|
|
|
|
string approvalId, string decisionType, JsonElement? updatedInput = null,
|
|
|
|
|
string? scope = null, string? reason = null) => Write(writer =>
|
|
|
|
|
{
|
|
|
|
|
writer.WriteString("approvalID", approvalId);
|
|
|
|
|
writer.WritePropertyName("decision");
|
|
|
|
|
writer.WriteStartObject();
|
|
|
|
|
writer.WriteString("type", decisionType);
|
|
|
|
|
if (updatedInput is { } input)
|
|
|
|
|
{
|
|
|
|
|
writer.WritePropertyName("updatedInput");
|
|
|
|
|
input.WriteTo(writer);
|
|
|
|
|
}
|
|
|
|
|
if (scope is not null) writer.WriteString("scope", scope);
|
|
|
|
|
if (reason is not null) writer.WriteString("reason", reason);
|
|
|
|
|
writer.WriteEndObject();
|
|
|
|
|
writer.WriteString("t", "approvalRespond");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
private static string ScopeValue(ApprovalAlwaysScope scope) => scope switch
|
|
|
|
|
{
|
|
|
|
|
ApprovalAlwaysScope.Session => "session",
|
|
|
|
|
ApprovalAlwaysScope.ToolName => "toolName",
|
|
|
|
|
ApprovalAlwaysScope.ToolNameWithPattern => "toolNameWithPattern",
|
|
|
|
|
_ => throw new ArgumentOutOfRangeException(nameof(scope)),
|
|
|
|
|
};
|
|
|
|
|
|
2026-08-04 02:46:53 -07:00
|
|
|
private static string Write(Action<Utf8JsonWriter> body)
|
|
|
|
|
{
|
|
|
|
|
using var stream = new MemoryStream();
|
|
|
|
|
using (var writer = new Utf8JsonWriter(stream, new JsonWriterOptions
|
|
|
|
|
{
|
|
|
|
|
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
|
|
|
|
|
}))
|
|
|
|
|
{
|
|
|
|
|
writer.WriteStartObject();
|
|
|
|
|
body(writer);
|
|
|
|
|
writer.WriteEndObject();
|
|
|
|
|
}
|
|
|
|
|
return System.Text.Encoding.UTF8.GetString(stream.GetBuffer(), 0, checked((int)stream.Length));
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-08-04 03:10:06 -07:00
|
|
|
|
|
|
|
|
public enum ApprovalAlwaysScope
|
|
|
|
|
{
|
|
|
|
|
Session,
|
|
|
|
|
ToolName,
|
|
|
|
|
ToolNameWithPattern,
|
|
|
|
|
}
|