feat: integrate performance upgrade and agent inspection tooling
Validate ShrinkSDK Workspace / catalog (push) Successful in 5s
Validate ShrinkSDK Workspace / unity (push) Successful in 3m20s

This commit is contained in:
2026-09-29 10:16:02 +08:00
parent f92105c97d
commit 08246ddb01
114 changed files with 7135 additions and 87 deletions
@@ -0,0 +1,102 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Newtonsoft.Json;
using ShrinkContext;
using ShrinkEventBus;
using ShrinkNetwork;
using ShrinkCommand;
namespace ShrinkSDK.Inspection
{
public sealed class ShrinkInspectionRelation
{
public string From = "";
public string To = "";
public string Kind = "";
public string Scope = "";
}
/// <summary>Explicit, on-demand snapshot. Call from the owning host thread while registration/composition is stable.</summary>
public sealed class ShrinkInspectionSnapshot
{
public int FormatVersion = 1;
public string BuildId = "";
public string CapturedAtUtc = DateTime.UtcNow.ToString("O");
public readonly List<string> Coverage = new();
public readonly List<ShrinkInspectionRelation> Relations = new();
public readonly Dictionary<string, object> State = new();
public static string BuildIdentity(IEnumerable<string> assemblyNames)
{
var loaded = AppDomain.CurrentDomain.GetAssemblies().Where(a => !a.IsDynamic).ToArray();
var identity = string.Join(";", assemblyNames.Distinct().OrderBy(n => n, StringComparer.Ordinal).Select(name =>
{
var candidates = loaded.Where(a => a.GetName().Name == name).ToArray();
if (candidates.Length != 1) throw new InvalidOperationException("Cannot establish unique runtime assembly identity: " + name);
return name + ":" + candidates[0].ManifestModule.ModuleVersionId.ToString("N");
}));
using var sha = System.Security.Cryptography.SHA256.Create();
return BitConverter.ToString(sha.ComputeHash(System.Text.Encoding.UTF8.GetBytes(identity))).Replace("-", "").ToLowerInvariant();
}
public ShrinkInspectionSnapshot(string buildId) { BuildId = buildId; }
public string ToJson() => JsonConvert.SerializeObject(this, Formatting.Indented, new Newtonsoft.Json.Converters.StringEnumConverter());
public void AddContext(string scope, ShrinkContextRuntime runtime, ShrinkContextLoader? loader = null)
{
var snapshot = runtime.CaptureDiagnostic();
State.Add(scope, new { snapshot.BindingCount, snapshot.Notifications,
Fibers = snapshot.Fibers.Select(f => new { f.Uid, f.Name, f.Status, f.Retired, f.InTransition, f.Inject, f.Provide, f.Dependencies, f.ErrorType }).ToArray(),
Transaction = loader?.LastTransaction is { } t ? new { t.Generation, t.Phase, t.CurrentEntryId, t.ErrorType, t.RestoreAttempted, t.PreviousCompositionRestored, t.RestoreErrorType } : null });
foreach (var fiber in snapshot.Fibers.Where(f => !f.Retired))
foreach (var dependency in fiber.Dependencies)
{
Add("fiber:" + scope + ":" + fiber.Uid, "key:" + dependency.Key, "requires@" + dependency.Realm, scope);
if (dependency.CurrentProviderUid.HasValue)
Add("fiber:" + scope + ":" + dependency.CurrentProviderUid, "fiber:" + scope + ":" + fiber.Uid, "provider:" + dependency.Key + "@" + dependency.Realm, scope);
}
}
public void AddNetwork(string scope, ShrinkNetworkService service)
{
State.Add(scope, new { Metrics = service.GetDiagnosticsSnapshot(), Queue = service.DispatchScheduler is ShrinkNetworkDispatchQueue queued ? queued.CaptureDiagnostics() : (service.DispatchScheduler as ShrinkNetworkInlineDispatchScheduler)?.CaptureDiagnostics() });
foreach (var meta in service.MessageRegistry.Registrations)
{
Add("opcode:" + meta.Opcode, "type:" + TypeName(meta.MessageType), "message", scope);
if (!string.IsNullOrEmpty(meta.Route)) Add("route:" + meta.Route, "type:" + TypeName(meta.MessageType), "message", scope);
}
foreach (var pair in service.Router.CaptureBindings()) Add("type:" + TypeName(pair.Key), MethodId(pair.Value), "handler", scope);
}
public void AddEventBus(string scope, IShrinkEventBus bus)
{
try
{
var bindings = EventBus.CaptureBindings(bus);
State.Add(scope, new { Bus = bus.Key.ToString(), Subscribers = bindings.Count });
foreach (var binding in bindings) Add("type:" + TypeName(binding.EventType), MethodId(binding.Handler), "subscribes", scope);
}
catch (NotSupportedException) { Coverage.Add(scope + ": custom EventBus does not expose bindings."); }
}
public void AddCommands(string scope, ShrinkCommandService service)
{
State.Add(scope, new { Registrations = service.Commands.Select(c => new { c.Path, c.Aliases, c.Permission, c.SourceKind }).ToArray() });
foreach (var binding in service.CaptureBindings()) Add("command:" + binding.Path, MethodId(binding.Handler), "command", scope);
}
private void Add(string from, string to, string kind, string scope) => Relations.Add(new ShrinkInspectionRelation { From = from, To = to, Kind = kind, Scope = scope });
private static string TypeName(Type type) => (type.FullName ?? type.Name).Replace('+', '.');
public static string MethodId(MethodInfo method)
{
// Generated wrappers and generic signatures remain runtime-only endpoints rather than guessed source matches.
if (method.IsGenericMethod || method.DeclaringType?.IsGenericType == true || method.GetParameters().Any(p => p.ParameterType.IsGenericType || p.ParameterType.IsArray || p.ParameterType.IsByRef))
return "runtime-method:" + method.Module.ModuleVersionId.ToString("N") + ":" + method.MetadataToken;
var parameters = method.GetParameters();
return "M:" + TypeName(method.DeclaringType!) + "." + method.Name + (parameters.Length == 0 ? "" : "(" + string.Join(",", parameters.Select(p => TypeName(p.ParameterType))) + ")");
}
}
}