源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,347 @@
|
||||
package runtimeprep
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type CommandSourceKind string
|
||||
|
||||
const (
|
||||
CommandSourceBuiltin CommandSourceKind = "builtin"
|
||||
CommandSourceApp CommandSourceKind = "app"
|
||||
)
|
||||
|
||||
type CommandSource struct {
|
||||
Kind CommandSourceKind
|
||||
AppID string
|
||||
AppName string
|
||||
}
|
||||
|
||||
type CommandTableColumn struct {
|
||||
Key string
|
||||
Label string
|
||||
}
|
||||
|
||||
type CommandTableOutput struct {
|
||||
Columns []CommandTableColumn
|
||||
}
|
||||
|
||||
type CommandCapabilityOutput struct {
|
||||
DefaultMode string
|
||||
JSON bool
|
||||
Table *CommandTableOutput
|
||||
}
|
||||
|
||||
type CommandCapability struct {
|
||||
ID string
|
||||
Path []string
|
||||
Summary string
|
||||
Description string
|
||||
Visibility string
|
||||
InputSchema map[string]any
|
||||
Output CommandCapabilityOutput
|
||||
ExecutionMode string
|
||||
Source CommandSource
|
||||
}
|
||||
|
||||
type CommandContext struct {
|
||||
Source string
|
||||
WorkspaceID string
|
||||
SkipCapabilityFilters bool
|
||||
IncludeIntegrationCapabilities bool
|
||||
}
|
||||
|
||||
type CommandCatalog interface {
|
||||
Capabilities(context.Context, CommandContext) []CommandCapability
|
||||
}
|
||||
|
||||
type CommandCapabilityProjection struct {
|
||||
// AllowedIDs switches the projection to an exact capability allowlist when
|
||||
// non-empty. It includes both public and promoted integration capabilities.
|
||||
// Empty preserves the legacy public-by-default projection.
|
||||
AllowedIDs []string
|
||||
IncludeIntegrationIDs []string
|
||||
ExcludeIDs []string
|
||||
}
|
||||
|
||||
func resolveCommandCapabilities(
|
||||
ctx context.Context,
|
||||
catalog CommandCatalog,
|
||||
workspaceID string,
|
||||
cliName string,
|
||||
projections ...*CommandCapabilityProjection,
|
||||
) (*CommandResolver, error) {
|
||||
if catalog == nil {
|
||||
return nil, errors.New("agent runtime preparation requires a command catalog")
|
||||
}
|
||||
capabilities := catalog.Capabilities(ctx, CommandContext{
|
||||
Source: "agent-runtime",
|
||||
WorkspaceID: strings.TrimSpace(workspaceID),
|
||||
SkipCapabilityFilters: true,
|
||||
IncludeIntegrationCapabilities: projectionRequestsIntegration(
|
||||
projections,
|
||||
),
|
||||
})
|
||||
var projection *CommandCapabilityProjection
|
||||
if len(projections) > 0 {
|
||||
projection = projections[0]
|
||||
}
|
||||
projected, err := projectCommandCapabilities(capabilities, projection)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newCommandResolver(cliName, projected)
|
||||
}
|
||||
|
||||
func projectionRequestsIntegration(
|
||||
projections []*CommandCapabilityProjection,
|
||||
) bool {
|
||||
return len(projections) > 0 &&
|
||||
projections[0] != nil &&
|
||||
len(normalizedCommandCapabilityIDs(
|
||||
projections[0].IncludeIntegrationIDs,
|
||||
)) > 0
|
||||
}
|
||||
|
||||
func commandVisibleToAgent(capability CommandCapability) bool {
|
||||
visibility := strings.TrimSpace(capability.Visibility)
|
||||
return visibility == "" || visibility == "public"
|
||||
}
|
||||
|
||||
func projectCommandCapabilities(
|
||||
capabilities []CommandCapability,
|
||||
projection *CommandCapabilityProjection,
|
||||
) ([]CommandCapability, error) {
|
||||
if projection == nil {
|
||||
return capabilities, nil
|
||||
}
|
||||
included := normalizedCommandCapabilityIDs(projection.IncludeIntegrationIDs)
|
||||
excluded := normalizedCommandCapabilityIDs(projection.ExcludeIDs)
|
||||
allowed := normalizedCommandCapabilityIDs(projection.AllowedIDs)
|
||||
foundIncluded := make(map[string]struct{}, len(included))
|
||||
foundAllowed := make(map[string]struct{}, len(allowed))
|
||||
projected := make([]CommandCapability, 0, len(capabilities))
|
||||
for _, capability := range capabilities {
|
||||
id := strings.TrimSpace(capability.ID)
|
||||
if len(allowed) > 0 {
|
||||
if _, accepted := allowed[id]; !accepted {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if _, denied := excluded[id]; denied {
|
||||
continue
|
||||
}
|
||||
if _, requested := included[id]; requested {
|
||||
capability.Visibility = "public"
|
||||
foundIncluded[id] = struct{}{}
|
||||
}
|
||||
projected = append(projected, capability)
|
||||
if _, required := allowed[id]; required {
|
||||
foundAllowed[id] = struct{}{}
|
||||
}
|
||||
}
|
||||
for id := range allowed {
|
||||
if _, found := foundAllowed[id]; !found {
|
||||
return nil, fmt.Errorf(
|
||||
"agent command capability projection requires unavailable allowed command %q",
|
||||
id,
|
||||
)
|
||||
}
|
||||
}
|
||||
for id := range included {
|
||||
if _, found := foundIncluded[id]; !found {
|
||||
return nil, fmt.Errorf(
|
||||
"agent command capability projection requires unavailable command %q",
|
||||
id,
|
||||
)
|
||||
}
|
||||
}
|
||||
return projected, nil
|
||||
}
|
||||
|
||||
func normalizedCommandCapabilityIDs(values []string) map[string]struct{} {
|
||||
normalized := make(map[string]struct{}, len(values))
|
||||
for _, value := range values {
|
||||
if value = strings.TrimSpace(value); value != "" {
|
||||
normalized[value] = struct{}{}
|
||||
}
|
||||
}
|
||||
return normalized
|
||||
}
|
||||
|
||||
// Wait execution adds a wrapper-owned timeout input. It is part of the
|
||||
// invocation contract even though app handlers do not receive it.
|
||||
func executionFacingInputSchema(mode string, schema map[string]any) map[string]any {
|
||||
if strings.TrimSpace(mode) != "wait" {
|
||||
return schema
|
||||
}
|
||||
projected := cloneSchemaMap(schema)
|
||||
projected["type"] = "object"
|
||||
properties := cloneSchemaMap(mapSchemaValue(schema["properties"]))
|
||||
if _, exists := properties["timeout-ms"]; !exists {
|
||||
properties["timeout-ms"] = map[string]any{
|
||||
"type": "integer",
|
||||
"description": "Maximum total wait in milliseconds; omit to wait until the command reaches a stop point.",
|
||||
}
|
||||
}
|
||||
projected["properties"] = properties
|
||||
return projected
|
||||
}
|
||||
|
||||
func cloneSchemaMap(source map[string]any) map[string]any {
|
||||
if source == nil {
|
||||
return nil
|
||||
}
|
||||
clone := make(map[string]any, len(source))
|
||||
for key, value := range source {
|
||||
clone[key] = cloneSchemaValue(value)
|
||||
}
|
||||
return clone
|
||||
}
|
||||
|
||||
func cloneSchemaValue(value any) any {
|
||||
switch typed := value.(type) {
|
||||
case map[string]any:
|
||||
return cloneSchemaMap(typed)
|
||||
case []any:
|
||||
clone := make([]any, len(typed))
|
||||
for index, item := range typed {
|
||||
clone[index] = cloneSchemaValue(item)
|
||||
}
|
||||
return clone
|
||||
case []map[string]any:
|
||||
clone := make([]map[string]any, len(typed))
|
||||
for index, item := range typed {
|
||||
clone[index] = cloneSchemaMap(item)
|
||||
}
|
||||
return clone
|
||||
case []string:
|
||||
return append([]string(nil), typed...)
|
||||
default:
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
func commandPath(path []string) string {
|
||||
return strings.Join(normalizedCommandPath(path), " ")
|
||||
}
|
||||
|
||||
func inputDetailsForCommand(_ string, schema map[string]any) string {
|
||||
properties := mapSchemaValue(schema["properties"])
|
||||
if len(properties) == 0 {
|
||||
return ""
|
||||
}
|
||||
required := make(map[string]bool)
|
||||
for _, name := range stringSliceSchemaValue(schema["required"]) {
|
||||
required[strings.TrimSpace(name)] = true
|
||||
}
|
||||
names := make([]string, 0, len(properties))
|
||||
for name := range properties {
|
||||
if name = strings.TrimSpace(name); name != "" {
|
||||
names = append(names, name)
|
||||
}
|
||||
}
|
||||
sortCommandInputs(names, required)
|
||||
parts := make([]string, 0, len(names))
|
||||
for _, name := range names {
|
||||
property := mapSchemaValue(properties[name])
|
||||
detail := "--" + name
|
||||
if typ := schemaTypeLabel(property); typ != "" {
|
||||
detail += " <" + typ + ">"
|
||||
}
|
||||
qualifiers := []string{"optional"}
|
||||
if required[name] {
|
||||
qualifiers[0] = "required"
|
||||
}
|
||||
if enum := stringSliceSchemaValue(property["enum"]); len(enum) > 0 {
|
||||
qualifiers = append(qualifiers, "values: "+strings.Join(enum, "|"))
|
||||
}
|
||||
if defaultValue, ok := property["default"]; ok {
|
||||
if text := strings.TrimSpace(fmt.Sprint(defaultValue)); text != "" {
|
||||
qualifiers = append(qualifiers, "default: "+text)
|
||||
}
|
||||
}
|
||||
detail += " (" + strings.Join(qualifiers, "; ") + ")"
|
||||
if description := strings.TrimSpace(asSchemaString(property["description"])); description != "" {
|
||||
detail += " - " + description
|
||||
}
|
||||
parts = append(parts, detail)
|
||||
}
|
||||
return strings.Join(parts, "; ")
|
||||
}
|
||||
|
||||
func sortCommandInputs(names []string, required map[string]bool) {
|
||||
sort.SliceStable(names, func(left int, right int) bool {
|
||||
if required[names[left]] != required[names[right]] {
|
||||
return required[names[left]]
|
||||
}
|
||||
return names[left] < names[right]
|
||||
})
|
||||
}
|
||||
|
||||
func schemaTypeLabel(property map[string]any) string {
|
||||
switch strings.TrimSpace(asSchemaString(property["type"])) {
|
||||
case "integer", "number":
|
||||
return "number"
|
||||
case "boolean":
|
||||
return "true|false"
|
||||
case "array", "object":
|
||||
return "json"
|
||||
default:
|
||||
return strings.TrimSpace(asSchemaString(property["type"]))
|
||||
}
|
||||
}
|
||||
|
||||
func mapSchemaValue(value any) map[string]any {
|
||||
if typed, ok := value.(map[string]any); ok {
|
||||
return typed
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func asSchemaString(value any) string {
|
||||
text, _ := value.(string)
|
||||
return text
|
||||
}
|
||||
|
||||
func schemaHasInput(schema map[string]any, name string) bool {
|
||||
_, ok := mapSchemaValue(schema["properties"])[strings.TrimSpace(name)]
|
||||
return ok
|
||||
}
|
||||
|
||||
func stringSliceSchemaValue(value any) []string {
|
||||
switch typed := value.(type) {
|
||||
case []string:
|
||||
return append([]string(nil), typed...)
|
||||
case []any:
|
||||
result := make([]string, 0, len(typed))
|
||||
for _, item := range typed {
|
||||
if text, ok := item.(string); ok {
|
||||
result = append(result, text)
|
||||
}
|
||||
}
|
||||
return result
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func normalizeCLICommandName(cliName string) string {
|
||||
if cliName = strings.TrimSpace(cliName); cliName != "" {
|
||||
return cliName
|
||||
}
|
||||
return "tutti"
|
||||
}
|
||||
|
||||
func firstNonEmptyText(values ...string) string {
|
||||
for _, value := range values {
|
||||
if value = strings.TrimSpace(value); value != "" {
|
||||
return value
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
Reference in New Issue
Block a user