From 984ff796e65de0066fbda7cff7f1d940b134d530 Mon Sep 17 00:00:00 2001 From: iliya Date: Wed, 21 Oct 2026 15:47:42 +0300 Subject: [PATCH 1/6] fix(group): keep no-change updates of pending manual native registrations read-only A Kiro MCP registration without a Kiro CLI is deliberately left pending (manual_activation_required, only the managed package receipt recorded). activeNativeDelivery treated that stable pending state as an incomplete projection, so every no-change update registered a native attempt, cleared it again, and reported mutated=true with rewritten state. This broke the update-twice idempotency contract and the catalog publication gate ("update changed package" at atlassian:validate_update on Linux). Treat an incomplete projection as settled when the binding is manual_activation_required, has no unresolved attempt, and the activator reports it cannot act automatically on this exact request: verify the recorded objects read-only instead. A later request the adapter can act on (user installed the Kiro CLI) keeps the projection incomplete, so registration completes then and correctly reports the mutation. --- .../usecase/manual_remote_lifecycle_test.go | 63 +++++++++++++++++++ .../agentplugins/usecase/native_projection.go | 26 +++++++- 2 files changed, 88 insertions(+), 1 deletion(-) diff --git a/install/integrationctl/agentplugins/usecase/manual_remote_lifecycle_test.go b/install/integrationctl/agentplugins/usecase/manual_remote_lifecycle_test.go index ac0a622aa..bd5109286 100644 --- a/install/integrationctl/agentplugins/usecase/manual_remote_lifecycle_test.go +++ b/install/integrationctl/agentplugins/usecase/manual_remote_lifecycle_test.go @@ -1,6 +1,7 @@ package usecase import ( + "bytes" "context" "fmt" "os" @@ -324,6 +325,49 @@ func TestClinePackageSupportsAutomaticAddUpdateRepairAndRemoveInIsolatedHome(t * } } +// A Kiro MCP registration without a Kiro CLI is deliberately left pending, so a +// no-change update must not spin a native attempt and rewrite state: the same +// command run twice has to report no_change and mutate nothing. +func TestKiroMCPManualActivationNoChangeUpdateIsNoOp(t *testing.T) { + t.Parallel() + service, store, _ := serviceFixture(t) + service.NativeObserver = providerstest.NewObserver(providers.NativeIdentityObserver{Stager: service.Stager}) + client := domain.DetectedClient{ClientID: domain.ClientKiro, DisplayName: "Kiro", Status: domain.DetectionDetected, ConfigRoot: filepath.Join(t.TempDir(), ".kiro")} + + add := kiroMCPInput(t, client, "1.0.0", "sha256:kiro-mcp-v1", "sha256:kiro-mcp-manifest-v1") + added, err := service.AddGroup(context.Background(), GroupInput{Targets: []AddInput{add}, OperationGroupID: "kiro-mcp-add", Confirmed: true}) + if err != nil { + t.Fatal(err) + } + if added.Targets[0].Activation.Activation != domain.ActivationManual { + t.Fatalf("kiro MCP add without a Kiro CLI must stay manual: %+v", added.Targets[0]) + } + before, err := os.ReadFile(store.Path) + if err != nil { + t.Fatal(err) + } + + update := kiroMCPInput(t, client, "1.0.0", "sha256:kiro-mcp-v1", "sha256:kiro-mcp-manifest-v1") + update.InstallationID = added.InstallationID + updated, err := service.UpdateGroup(context.Background(), GroupInput{Targets: []AddInput{update}, CompatibilityChecks: []AddInput{update}, OperationGroupID: "kiro-mcp-update", Confirmed: true}) + if err != nil { + t.Fatal(err) + } + if !updated.Targets[0].NoChange || updated.Targets[0].Mutated { + t.Fatalf("no-change update of a pending manual Kiro MCP registration mutated: %+v", updated.Targets[0]) + } + if updated.Targets[0].Activation.Activation != domain.ActivationManual { + t.Fatalf("no-change update claimed Kiro MCP registration: %+v", updated.Targets[0]) + } + after, err := os.ReadFile(store.Path) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(before, after) { + t.Fatalf("no-change update rewrote installation state:\nbefore: %s\nafter: %s", before, after) + } +} + func containsAction(actions []string, fragment string) bool { for _, action := range actions { if strings.Contains(action, fragment) { @@ -380,6 +424,25 @@ func kiroPowerInput(t *testing.T, client domain.DetectedClient, version, treeDig return input } +// kiroMCPInput mirrors the catalog's remote-MCP packages (like atlassian): an +// MCP-only envelope whose Kiro registration needs a Kiro CLI to complete. +func kiroMCPInput(t *testing.T, client domain.DetectedClient, version, treeDigest, manifestDigest string) AddInput { + t.Helper() + input := addInput(t, client, "https://example.com/kiro") + setEnvelopeVersion(t, &input.Envelope, version, treeDigest, manifestDigest) + mcpBody := []byte(`{"$schema":"https://agent-plugins.org/schemas/1.0.0/mcp.schema.json","mcpServers":{"docs":{"type":"streamable-http","url":"https://example.test/mcp"}}}`) + if err := os.WriteFile(filepath.Join(input.Envelope.SnapshotRoot, "mcp.json"), mcpBody, 0o644); err != nil { + t.Fatal(err) + } + input.Envelope.MCP = domain.MCPComponent{Present: true, Enabled: true, SchemaURI: domain.MCPSchemaV1, Raw: mcpBody, Servers: map[string]domain.MCPServer{ + "docs": {Name: "docs", Type: "streamable-http", Raw: []byte(`{"type":"streamable-http","url":"https://example.test/mcp"}`), Decoded: map[string]any{"type": "streamable-http", "url": "https://example.test/mcp"}}, + }} + input.Envelope.Inventory.MCPPresent = true + input.Envelope.Inventory.MCPEnabled = true + input.Envelope.Inventory.MCPServers = []string{"docs"} + return input +} + func openCodePluginInput(t *testing.T, client domain.DetectedClient, version, treeDigest, manifestDigest, command string) AddInput { t.Helper() if client.ClientID == domain.ClientOpenCode { diff --git a/install/integrationctl/agentplugins/usecase/native_projection.go b/install/integrationctl/agentplugins/usecase/native_projection.go index fcfb6a7e7..1a04dfdf5 100644 --- a/install/integrationctl/agentplugins/usecase/native_projection.go +++ b/install/integrationctl/agentplugins/usecase/native_projection.go @@ -64,7 +64,31 @@ func (service Service) activeNativeDelivery(ctx context.Context, input AddInput, if err != nil { return delivery, false, err } - return delivery, confirmedNativeProjection(client.NativeObjects, delivery.NativeObjects), nil + if confirmedNativeProjection(client.NativeObjects, delivery.NativeObjects) { + return delivery, true, nil + } + if service.manualRegistrationSettled(input, plan, client) { + // A deliberately pending manual registration is a stable projection: + // no activation can finish it until the adapter can act again, so + // update verifies the recorded objects instead of churning an attempt. + delivery.NativeObjects = append([]domain.NativeObjectOwnership(nil), client.NativeObjects...) + return delivery, true, nil + } + return delivery, false, nil +} + +// manualRegistrationSettled reports an incomplete projection that no adapter +// action could complete for this exact request. A later request the adapter +// can act on keeps the projection incomplete, so registration completes then. +func (service Service) manualRegistrationSettled(input AddInput, plan domain.DeliveryPlan, client domain.ClientBinding) bool { + if client.Activation != domain.ActivationManual || client.NativeActivationAttempt != "" || client.PendingNativeIntent != nil { + return false + } + classifier, ok := service.Activator.(ports.AutomaticActivationClassifier) + if !ok { + return false + } + return !classifier.AutomaticallyActivates(domain.ActivationRequest{Client: input.Client, Plan: plan, BackendExecutable: input.BackendExecutable}) } // requireCurrentCommandProjection derives the installed native projection of From b3ca466321269ddbd60f8ce019b422dbec22a1dd Mon Sep 17 00:00:00 2001 From: iliya Date: Wed, 21 Oct 2026 17:37:40 +0300 Subject: [PATCH 2/6] fix(usecase): classify settled manual registrations on every update path Review follow-up to the pending-manual no-op fix. The settled guard now classifies the exact request the acting adapter would receive (desired delivery plus recorded prior objects), so adapters that gate on those fields -- Windsurf on Delivery, OpenCode on PreviousNativeObjects -- are never frozen by a misclassified guard. The non-native branch settles the same way, so single-target updates of pending manual registrations (ChatGPT remote, Cursor) report no_change instead of a phantom change, and the resume path treats a settled projection as unchanged alongside the verified-registration check. The replace branch of no-change resume now also refuses registration migrations. --- .../agentplugins/usecase/apply.go | 4 +- .../agentplugins/usecase/group_activate.go | 2 +- .../agentplugins/usecase/lifecycle.go | 10 +- .../usecase/manual_remote_lifecycle_test.go | 143 ++++++++++++++++++ .../agentplugins/usecase/native_projection.go | 67 +++++--- .../agentplugins/usecase/repair_native.go | 2 +- 6 files changed, 197 insertions(+), 31 deletions(-) diff --git a/install/integrationctl/agentplugins/usecase/apply.go b/install/integrationctl/agentplugins/usecase/apply.go index c65757758..490df4abc 100644 --- a/install/integrationctl/agentplugins/usecase/apply.go +++ b/install/integrationctl/agentplugins/usecase/apply.go @@ -300,7 +300,7 @@ func (session *applySession) noChangeOrResume() (bool, AddResult, error) { if err := session.service.observeNativeIdentity(session.ctx, session.input.Client, session.plan, session.managedBinding); err != nil { return true, session.result, err } - if !nativeDialectProjectionChanged(previousClient, session.plan) && !requiresComponentRemoval(session.plan) && packageRevisionMatches(previousClient.PackageRevision, session.input.Envelope) && previousClient.PackageRevision.ResolvedRevision == session.input.Envelope.Source.ResolvedRevision { + if !session.registrationMigration && !nativeDialectProjectionChanged(previousClient, session.plan) && !requiresComponentRemoval(session.plan) && packageRevisionMatches(previousClient.PackageRevision, session.input.Envelope) && previousClient.PackageRevision.ResolvedRevision == session.input.Envelope.Source.ResolvedRevision { return session.finishExistingLifecycle(previousClient, "") } } @@ -328,7 +328,7 @@ func (session *applySession) finishExistingLifecycle(current domain.ClientBindin } } if nativeLifecycleClient(session.input.Client.ClientID, session.plan.SelectedDelivery) { - _, complete, err := session.service.activeNativeDelivery(session.ctx, session.input, session.plan, session.state.Installations[session.installationIndex], current) + _, complete, _, err := session.service.activeNativeDelivery(session.ctx, session.input, session.plan, session.state.Installations[session.installationIndex], current) if err != nil { return true, session.result, err } diff --git a/install/integrationctl/agentplugins/usecase/group_activate.go b/install/integrationctl/agentplugins/usecase/group_activate.go index 3c6d0ac1d..f7e645db8 100644 --- a/install/integrationctl/agentplugins/usecase/group_activate.go +++ b/install/integrationctl/agentplugins/usecase/group_activate.go @@ -88,7 +88,7 @@ func (session *groupSession) activateGroupDelivery(target plannedGroupTarget) (d nativeComplete := true if target.noChange && target.managed != nil { var err error - delivery, nativeComplete, err = session.service.activeNativeDelivery(session.ctx, target.input, target.plan, session.state.Installations[session.installationIndex], *target.managed) + delivery, nativeComplete, _, err = session.service.activeNativeDelivery(session.ctx, target.input, target.plan, session.state.Installations[session.installationIndex], *target.managed) if err != nil { // A projection failure happens before the adapter can run. Keep the // recorded lifecycle and acknowledged objects instead of persisting diff --git a/install/integrationctl/agentplugins/usecase/lifecycle.go b/install/integrationctl/agentplugins/usecase/lifecycle.go index ed3aef7cd..fe9ff188f 100644 --- a/install/integrationctl/agentplugins/usecase/lifecycle.go +++ b/install/integrationctl/agentplugins/usecase/lifecycle.go @@ -35,7 +35,7 @@ func (service Service) resume( result.RequiresConfirmation = true return result, nil } - delivery, complete, err := service.resumeNativeDelivery(ctx, input, result.Plan, installationID, client) + delivery, complete, settled, err := service.resumeNativeDelivery(ctx, input, result.Plan, installationID, client) if err != nil { return result, err } @@ -75,7 +75,9 @@ func (service Service) resume( if activationErr != nil { return result, activationErr } - result.NoChange = complete && !changed && service.verifiedRegistrationUnchanged(input, result.Plan, client, outcome) + // A settled manual registration is a stable no-change outcome: this request + // cannot finish it, and a later one the adapter can act on will. + result.NoChange = complete && !changed && (service.verifiedRegistrationUnchanged(input, result.Plan, client, outcome) || settled) return result, nil } @@ -89,10 +91,10 @@ func unresolvedNativeAttemptID(client domain.ClientBinding) string { return "" } -func (service Service) resumeNativeDelivery(ctx context.Context, input AddInput, plan domain.DeliveryPlan, installationID string, client domain.ClientBinding) (domain.StagedDelivery, bool, error) { +func (service Service) resumeNativeDelivery(ctx context.Context, input AddInput, plan domain.DeliveryPlan, installationID string, client domain.ClientBinding) (domain.StagedDelivery, bool, bool, error) { state, err := service.StateStore.Load() if err != nil { - return domain.StagedDelivery{}, false, err + return domain.StagedDelivery{}, false, false, err } var installation domain.Installation for _, item := range state.Installations { diff --git a/install/integrationctl/agentplugins/usecase/manual_remote_lifecycle_test.go b/install/integrationctl/agentplugins/usecase/manual_remote_lifecycle_test.go index bd5109286..a9392b7bd 100644 --- a/install/integrationctl/agentplugins/usecase/manual_remote_lifecycle_test.go +++ b/install/integrationctl/agentplugins/usecase/manual_remote_lifecycle_test.go @@ -11,6 +11,8 @@ import ( "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/adapters/nativeconfig" "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/clients/contracttest" + "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/clients/opencode" + "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/clients/windsurf" "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/domain" "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/providers" "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/providerstest" @@ -359,6 +361,12 @@ func TestKiroMCPManualActivationNoChangeUpdateIsNoOp(t *testing.T) { if updated.Targets[0].Activation.Activation != domain.ActivationManual { t.Fatalf("no-change update claimed Kiro MCP registration: %+v", updated.Targets[0]) } + if updated.Targets[0].Activation.Verification == domain.VerificationInstalled { + t.Fatalf("no-change update verified an uninstalled Kiro MCP registration: %+v", updated.Targets[0]) + } + if !containsAction(updated.Targets[0].Activation.UserActions, "install a current Kiro CLI") { + t.Fatalf("no-change update lost the Kiro CLI user action: %+v", updated.Targets[0]) + } after, err := os.ReadFile(store.Path) if err != nil { t.Fatal(err) @@ -368,6 +376,91 @@ func TestKiroMCPManualActivationNoChangeUpdateIsNoOp(t *testing.T) { } } +// The single-target update path (installer's one-compatibility-check update) +// must keep the same read-only guarantee as the group path. +func TestKiroMCPManualActivationNoChangeSingleTargetUpdateIsNoOp(t *testing.T) { + t.Parallel() + service, store, _ := serviceFixture(t) + service.NativeObserver = providerstest.NewObserver(providers.NativeIdentityObserver{Stager: service.Stager}) + client := domain.DetectedClient{ClientID: domain.ClientKiro, DisplayName: "Kiro", Status: domain.DetectionDetected, ConfigRoot: filepath.Join(t.TempDir(), ".kiro")} + + add := kiroMCPInput(t, client, "1.0.0", "sha256:kiro-mcp-v1", "sha256:kiro-mcp-manifest-v1") + add.Confirmed = true + added, err := service.Add(context.Background(), add) + if err != nil { + t.Fatal(err) + } + before, err := os.ReadFile(store.Path) + if err != nil { + t.Fatal(err) + } + + update := kiroMCPInput(t, client, "1.0.0", "sha256:kiro-mcp-v1", "sha256:kiro-mcp-manifest-v1") + update.Confirmed = true + update.InstallationID = added.InstallationID + updated, err := service.Update(context.Background(), update) + if err != nil { + t.Fatal(err) + } + if !updated.NoChange || updated.Mutated { + t.Fatalf("single-target no-change update of a pending manual Kiro MCP registration mutated: %+v", updated) + } + if updated.Activation.Activation != domain.ActivationManual { + t.Fatalf("single-target no-change update claimed Kiro MCP registration: %+v", updated) + } + if !containsAction(updated.Activation.UserActions, "install a current Kiro CLI") { + t.Fatalf("single-target no-change update lost the Kiro CLI user action: %+v", updated) + } + after, err := os.ReadFile(store.Path) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(before, after) { + t.Fatalf("single-target no-change update rewrote installation state:\nbefore: %s\nafter: %s", before, after) + } +} + +// A non-native manual registration (ChatGPT's remote activation) keeps the +// same read-only guarantee on the single-target update path. +func TestChatGPTManualNoChangeSingleTargetUpdateIsNoOp(t *testing.T) { + t.Parallel() + service, store, _ := serviceFixture(t) + service.NativeObserver = providerstest.NewObserver(providers.NativeIdentityObserver{Stager: service.Stager}) + client := domain.DetectedClient{ClientID: domain.ClientChatGPT, DisplayName: "ChatGPT", Status: domain.DetectionNotDetected} + + add := signedChatGPTInput(t, client, "1.0.0", "sha256:chatgpt-v1", "sha256:chatgpt-manifest-v1") + add.Confirmed = true + added, err := service.Add(context.Background(), add) + if err != nil { + t.Fatal(err) + } + before, err := os.ReadFile(store.Path) + if err != nil { + t.Fatal(err) + } + + update := signedChatGPTInput(t, client, "1.0.0", "sha256:chatgpt-v1", "sha256:chatgpt-manifest-v1") + update.Confirmed = true + update.InstallationID = added.InstallationID + updated, err := service.Update(context.Background(), update) + if err != nil { + t.Fatal(err) + } + if !updated.NoChange || updated.Mutated { + t.Fatalf("single-target no-change update of a pending manual ChatGPT registration mutated: %+v", updated) + } + if updated.Activation.Activation != domain.ActivationManual { + t.Fatalf("single-target no-change update claimed ChatGPT remote activation: %+v", updated) + } + after, err := os.ReadFile(store.Path) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(before, after) { + t.Fatalf("single-target no-change update rewrote installation state:\nbefore: %s\nafter: %s", before, after) + } +} + func containsAction(actions []string, fragment string) bool { for _, action := range actions { if strings.Contains(action, fragment) { @@ -377,6 +470,56 @@ func containsAction(actions []string, fragment string) bool { return false } +// manualRegistrationSettled must classify the exact request the acting adapter +// would receive: a Windsurf delivery whose native objects its adapter can act +// on is never settled, and a Kiro registration stops being settled the moment a +// Kiro CLI can complete it. +func TestManualRegistrationSettledClassifiesTheActingRequest(t *testing.T) { + t.Parallel() + service, _, _ := serviceFixture(t) + client := domain.DetectedClient{ClientID: domain.ClientKiro, DisplayName: "Kiro", Status: domain.DetectionDetected, ConfigRoot: filepath.Join(t.TempDir(), ".kiro")} + add := kiroMCPInput(t, client, "1.0.0", "sha256:kiro-mcp-v1", "sha256:kiro-mcp-manifest-v1") + added, err := service.AddGroup(context.Background(), GroupInput{Targets: []AddInput{add}, OperationGroupID: "kiro-settled-plan", Confirmed: true}) + if err != nil { + t.Fatal(err) + } + plan := added.Targets[0].Plan + binding := domain.ClientBinding{Activation: domain.ActivationManual} + delivery := domain.StagedDelivery{ClientID: domain.ClientKiro} + if !service.manualRegistrationSettled(add, plan, binding, delivery) { + t.Fatal("kiro registration without a Kiro CLI must settle") + } + withCLI := add + withCLI.BackendExecutable = "kiro-cli" + if service.manualRegistrationSettled(withCLI, plan, binding, delivery) { + t.Fatal("kiro registration with a usable Kiro CLI must stay unsettled") + } + attempted := binding + attempted.NativeActivationAttempt = "attempt-1" + if service.manualRegistrationSettled(add, plan, attempted, delivery) { + t.Fatal("an unresolved native attempt must keep the projection unsettled") + } + windsurfInput := add + windsurfInput.Client = domain.DetectedClient{ClientID: domain.ClientWindsurf, DisplayName: "Windsurf", Status: domain.DetectionDetected, ConfigRoot: filepath.Join(t.TempDir(), ".codeium")} + windsurfDelivery := domain.StagedDelivery{ClientID: domain.ClientWindsurf, NativeObjects: []domain.NativeObjectOwnership{ + {ObjectID: "windsurf:docs", Kind: string(windsurf.WindsurfMCPObjectKind)}, + }} + windsurfPlan := domain.DeliveryPlan{InstallIntent: domain.InstallIntentAutomatic} + if service.manualRegistrationSettled(windsurfInput, windsurfPlan, binding, windsurfDelivery) { + t.Fatal("a windsurf delivery its adapter can act on must stay unsettled") + } + openCodeInput := add + openCodeInput.Client = domain.DetectedClient{ClientID: domain.ClientOpenCode, DisplayName: "OpenCode", Status: domain.DetectionDetected, ConfigRoot: filepath.Join(t.TempDir(), ".opencode")} + openCodeBinding := domain.ClientBinding{Activation: domain.ActivationManual, NativeObjects: []domain.NativeObjectOwnership{ + {ObjectID: "opencode:docs", Kind: string(opencode.OpenCodeV2MCPObjectKind)}, + }} + openCodeDelivery := domain.StagedDelivery{ClientID: domain.ClientOpenCode} + openCodePlan := domain.DeliveryPlan{InstallIntent: domain.InstallIntentAutomatic} + if service.manualRegistrationSettled(openCodeInput, openCodePlan, openCodeBinding, openCodeDelivery) { + t.Fatal("an opencode final-removal request its adapter can act on must stay unsettled") + } +} + func signedChatGPTInput(t *testing.T, client domain.DetectedClient, version, treeDigest, manifestDigest string) AddInput { t.Helper() input := addInput(t, client, "https://example.com/chatgpt") diff --git a/install/integrationctl/agentplugins/usecase/native_projection.go b/install/integrationctl/agentplugins/usecase/native_projection.go index 1a04dfdf5..7c632c340 100644 --- a/install/integrationctl/agentplugins/usecase/native_projection.go +++ b/install/integrationctl/agentplugins/usecase/native_projection.go @@ -13,36 +13,40 @@ import ( // activeNativeDelivery contains the complete desired projection, derived from // the selected components and a verified installed package. Its native objects // are never ownership evidence until an adapter confirms the external effect. -func (service Service) activeNativeDelivery(ctx context.Context, input AddInput, plan domain.DeliveryPlan, installation domain.Installation, client domain.ClientBinding) (domain.StagedDelivery, bool, error) { - delivery := domain.StagedDelivery{ClientID: input.Client.ClientID, OwnedBase: plan.TargetRoot, ActivePath: client.TargetLocator, ArtifactDigest: managedDigest(client)} +// The settled result reports a complete projection that is only complete +// because no adapter action could finish the pending manual registration. +func (service Service) activeNativeDelivery(ctx context.Context, input AddInput, plan domain.DeliveryPlan, installation domain.Installation, client domain.ClientBinding) (delivery domain.StagedDelivery, complete, settled bool, err error) { + delivery = domain.StagedDelivery{ClientID: input.Client.ClientID, OwnedBase: plan.TargetRoot, ActivePath: client.TargetLocator, ArtifactDigest: managedDigest(client)} if delivery.ArtifactDigest == "" { - return delivery, false, fmt.Errorf("managed package receipt is missing") + return delivery, false, false, fmt.Errorf("managed package receipt is missing") } if !nativeLifecycleClient(input.Client.ClientID, plan.SelectedDelivery) { delivery.NativeObjects = append([]domain.NativeObjectOwnership(nil), client.NativeObjects...) - return delivery, service.nonNativeRegistrationComplete(input, plan, client), nil + complete = service.nonNativeRegistrationComplete(input, plan, client, delivery) + settled = complete && service.manualRegistrationSettled(input, plan, client, delivery) + return delivery, complete, settled, nil } if !packageRevisionMatches(client.PackageRevision, input.Envelope) { - return delivery, false, fmt.Errorf("active package revision differs from the requested native projection") + return delivery, false, false, fmt.Errorf("active package revision differs from the requested native projection") } projector, ok := service.Stager.(ports.ActiveNativeProjector) if !ok { - return delivery, false, fmt.Errorf("stager cannot derive the installed native projection read-only") + return delivery, false, false, fmt.Errorf("stager cannot derive the installed native projection read-only") } dataPath := "" if packageNeedsPluginData(input.Envelope, plan) { receipt, found := installation.DataReceipts[client.DataReceiptID] if !found || receipt.DataReceiptID == "" || service.PluginData == nil { - return delivery, false, fmt.Errorf("native projection has no confirmed PLUGIN_DATA receipt") + return delivery, false, false, fmt.Errorf("native projection has no confirmed PLUGIN_DATA receipt") } if err := service.PluginData.ValidateData(ctx, receipt); err != nil { - return delivery, false, fmt.Errorf("validate native projection PLUGIN_DATA receipt: %w", err) + return delivery, false, false, fmt.Errorf("validate native projection PLUGIN_DATA receipt: %w", err) } dataPath = receipt.Locator } projected, err := projector.ProjectActiveNative(ctx, input.Envelope, cloneLocalObservationPlan(plan), delivery.ArtifactDigest, dataPath) if err != nil { - return delivery, false, err + return delivery, false, false, err } for _, object := range client.NativeObjects { if object.Kind == "managed_package_directory" { @@ -50,37 +54,42 @@ func (service Service) activeNativeDelivery(ctx context.Context, input AddInput, } } if len(delivery.NativeObjects) != 1 { - return delivery, false, fmt.Errorf("active package has no unique managed directory receipt") + return delivery, false, false, fmt.Errorf("active package has no unique managed directory receipt") } seen := map[string]bool{delivery.NativeObjects[0].ObjectID: true} for _, object := range projected { if object.ObjectID == "" || object.Kind == "" || seen[object.ObjectID] || object.Kind == "managed_package_directory" { - return delivery, false, fmt.Errorf("native projection has incomplete or duplicate ownership identity") + return delivery, false, false, fmt.Errorf("native projection has incomplete or duplicate ownership identity") } seen[object.ObjectID] = true delivery.NativeObjects = append(delivery.NativeObjects, object) } delivery.NativeObjects, err = retainRecordedLocalSelector(plan.SelectedDelivery, client, delivery.NativeObjects) if err != nil { - return delivery, false, err + return delivery, false, false, err } if confirmedNativeProjection(client.NativeObjects, delivery.NativeObjects) { - return delivery, true, nil + return delivery, true, false, nil } - if service.manualRegistrationSettled(input, plan, client) { + // Classify before replacing the projection: the acting request carries the + // full desired delivery, and adapters gate on its native objects. + settled = service.manualRegistrationSettled(input, plan, client, delivery) + if settled { // A deliberately pending manual registration is a stable projection: // no activation can finish it until the adapter can act again, so // update verifies the recorded objects instead of churning an attempt. delivery.NativeObjects = append([]domain.NativeObjectOwnership(nil), client.NativeObjects...) - return delivery, true, nil + return delivery, true, true, nil } - return delivery, false, nil + return delivery, false, false, nil } // manualRegistrationSettled reports an incomplete projection that no adapter -// action could complete for this exact request. A later request the adapter -// can act on keeps the projection incomplete, so registration completes then. -func (service Service) manualRegistrationSettled(input AddInput, plan domain.DeliveryPlan, client domain.ClientBinding) bool { +// action could complete for this exact request. The classifier sees the same +// request the acting adapter would, so a client whose adapter could act on +// this delivery keeps the projection incomplete and registration completes +// when its conditions arrive. +func (service Service) manualRegistrationSettled(input AddInput, plan domain.DeliveryPlan, client domain.ClientBinding, delivery domain.StagedDelivery) bool { if client.Activation != domain.ActivationManual || client.NativeActivationAttempt != "" || client.PendingNativeIntent != nil { return false } @@ -88,7 +97,19 @@ func (service Service) manualRegistrationSettled(input AddInput, plan domain.Del if !ok { return false } - return !classifier.AutomaticallyActivates(domain.ActivationRequest{Client: input.Client, Plan: plan, BackendExecutable: input.BackendExecutable}) + return !classifier.AutomaticallyActivates(activationClassifierRequest(input, plan, client, delivery)) +} + +// activationClassifierRequest mirrors the request the acting adapter would +// receive, so classifiers gate on the same delivery and prior objects. +func activationClassifierRequest(input AddInput, plan domain.DeliveryPlan, client domain.ClientBinding, delivery domain.StagedDelivery) domain.ActivationRequest { + return domain.ActivationRequest{ + Client: input.Client, + Plan: plan, + Delivery: delivery, + BackendExecutable: input.BackendExecutable, + PreviousNativeObjects: client.NativeObjects, + } } // requireCurrentCommandProjection derives the installed native projection of @@ -99,7 +120,7 @@ func (service Service) requireCurrentCommandProjection(ctx context.Context, inpu if !rendersCommands(input.Envelope, input.Client.ClientID) || !nativeLifecycleClient(input.Client.ClientID, plan.SelectedDelivery) { return nil } - if _, _, err := service.activeNativeDelivery(ctx, input, plan, installation, client); errors.Is(err, ErrProjectionRefreshRequired) { + if _, _, _, err := service.activeNativeDelivery(ctx, input, plan, installation, client); errors.Is(err, ErrProjectionRefreshRequired) { return err } return nil @@ -108,9 +129,9 @@ func (service Service) requireCurrentCommandProjection(ctx context.Context, inpu // nonNativeRegistrationComplete separates CLI effects from package reuse. // Explicit attestation still runs the adapter's verifier; recognized negative // evidence cannot be overridden. Unattempted registration still needs effects. -func (service Service) nonNativeRegistrationComplete(input AddInput, plan domain.DeliveryPlan, client domain.ClientBinding) bool { +func (service Service) nonNativeRegistrationComplete(input AddInput, plan domain.DeliveryPlan, client domain.ClientBinding, delivery domain.StagedDelivery) bool { classifier, ok := service.Activator.(ports.AutomaticActivationClassifier) - cliBacked := ok && classifier.AutomaticallyActivates(domain.ActivationRequest{Client: input.Client, Plan: plan, BackendExecutable: input.BackendExecutable}) + cliBacked := ok && classifier.AutomaticallyActivates(activationClassifierRequest(input, plan, client, delivery)) if plan.SelectedDelivery.EffectiveTraits(input.Client.ClientID).LifecycleKind == domain.LifecycleCLIRegistry && cliBacked { return input.ActivationComplete || client.Activation == domain.ActivationActive && (client.Verification == domain.VerificationInstalled || client.Verification == domain.VerificationRuntime) } diff --git a/install/integrationctl/agentplugins/usecase/repair_native.go b/install/integrationctl/agentplugins/usecase/repair_native.go index 0adf5d75c..ed57795a2 100644 --- a/install/integrationctl/agentplugins/usecase/repair_native.go +++ b/install/integrationctl/agentplugins/usecase/repair_native.go @@ -9,7 +9,7 @@ import ( ) func (session *repairSession) repairNative() (AddResult, error) { - delivery, complete, err := session.service.activeNativeDelivery(session.ctx, session.input, session.plan, session.installation, session.client) + delivery, complete, _, err := session.service.activeNativeDelivery(session.ctx, session.input, session.plan, session.installation, session.client) if err != nil { return session.result, err } From b72ff04d3ab74c8ba0dd856bda788dc4588988f8 Mon Sep 17 00:00:00 2001 From: iliya Date: Wed, 21 Oct 2026 17:55:26 +0300 Subject: [PATCH 3/6] refactor(usecase): extract desiredNativeObjects to satisfy size gates Keeps activeNativeDelivery under the funlen/gocyclo limits and drops the constant-only parameters from the kiro MCP test helper (unparam). --- .../usecase/manual_remote_lifecycle_test.go | 14 +++++----- .../agentplugins/usecase/native_projection.go | 27 ++++++++++++------- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/install/integrationctl/agentplugins/usecase/manual_remote_lifecycle_test.go b/install/integrationctl/agentplugins/usecase/manual_remote_lifecycle_test.go index a9392b7bd..921ed51d5 100644 --- a/install/integrationctl/agentplugins/usecase/manual_remote_lifecycle_test.go +++ b/install/integrationctl/agentplugins/usecase/manual_remote_lifecycle_test.go @@ -336,7 +336,7 @@ func TestKiroMCPManualActivationNoChangeUpdateIsNoOp(t *testing.T) { service.NativeObserver = providerstest.NewObserver(providers.NativeIdentityObserver{Stager: service.Stager}) client := domain.DetectedClient{ClientID: domain.ClientKiro, DisplayName: "Kiro", Status: domain.DetectionDetected, ConfigRoot: filepath.Join(t.TempDir(), ".kiro")} - add := kiroMCPInput(t, client, "1.0.0", "sha256:kiro-mcp-v1", "sha256:kiro-mcp-manifest-v1") + add := kiroMCPInput(t, client) added, err := service.AddGroup(context.Background(), GroupInput{Targets: []AddInput{add}, OperationGroupID: "kiro-mcp-add", Confirmed: true}) if err != nil { t.Fatal(err) @@ -349,7 +349,7 @@ func TestKiroMCPManualActivationNoChangeUpdateIsNoOp(t *testing.T) { t.Fatal(err) } - update := kiroMCPInput(t, client, "1.0.0", "sha256:kiro-mcp-v1", "sha256:kiro-mcp-manifest-v1") + update := kiroMCPInput(t, client) update.InstallationID = added.InstallationID updated, err := service.UpdateGroup(context.Background(), GroupInput{Targets: []AddInput{update}, CompatibilityChecks: []AddInput{update}, OperationGroupID: "kiro-mcp-update", Confirmed: true}) if err != nil { @@ -384,7 +384,7 @@ func TestKiroMCPManualActivationNoChangeSingleTargetUpdateIsNoOp(t *testing.T) { service.NativeObserver = providerstest.NewObserver(providers.NativeIdentityObserver{Stager: service.Stager}) client := domain.DetectedClient{ClientID: domain.ClientKiro, DisplayName: "Kiro", Status: domain.DetectionDetected, ConfigRoot: filepath.Join(t.TempDir(), ".kiro")} - add := kiroMCPInput(t, client, "1.0.0", "sha256:kiro-mcp-v1", "sha256:kiro-mcp-manifest-v1") + add := kiroMCPInput(t, client) add.Confirmed = true added, err := service.Add(context.Background(), add) if err != nil { @@ -395,7 +395,7 @@ func TestKiroMCPManualActivationNoChangeSingleTargetUpdateIsNoOp(t *testing.T) { t.Fatal(err) } - update := kiroMCPInput(t, client, "1.0.0", "sha256:kiro-mcp-v1", "sha256:kiro-mcp-manifest-v1") + update := kiroMCPInput(t, client) update.Confirmed = true update.InstallationID = added.InstallationID updated, err := service.Update(context.Background(), update) @@ -478,7 +478,7 @@ func TestManualRegistrationSettledClassifiesTheActingRequest(t *testing.T) { t.Parallel() service, _, _ := serviceFixture(t) client := domain.DetectedClient{ClientID: domain.ClientKiro, DisplayName: "Kiro", Status: domain.DetectionDetected, ConfigRoot: filepath.Join(t.TempDir(), ".kiro")} - add := kiroMCPInput(t, client, "1.0.0", "sha256:kiro-mcp-v1", "sha256:kiro-mcp-manifest-v1") + add := kiroMCPInput(t, client) added, err := service.AddGroup(context.Background(), GroupInput{Targets: []AddInput{add}, OperationGroupID: "kiro-settled-plan", Confirmed: true}) if err != nil { t.Fatal(err) @@ -569,10 +569,10 @@ func kiroPowerInput(t *testing.T, client domain.DetectedClient, version, treeDig // kiroMCPInput mirrors the catalog's remote-MCP packages (like atlassian): an // MCP-only envelope whose Kiro registration needs a Kiro CLI to complete. -func kiroMCPInput(t *testing.T, client domain.DetectedClient, version, treeDigest, manifestDigest string) AddInput { +func kiroMCPInput(t *testing.T, client domain.DetectedClient) AddInput { t.Helper() input := addInput(t, client, "https://example.com/kiro") - setEnvelopeVersion(t, &input.Envelope, version, treeDigest, manifestDigest) + setEnvelopeVersion(t, &input.Envelope, "1.0.0", "sha256:kiro-mcp-v1", "sha256:kiro-mcp-manifest-v1") mcpBody := []byte(`{"$schema":"https://agent-plugins.org/schemas/1.0.0/mcp.schema.json","mcpServers":{"docs":{"type":"streamable-http","url":"https://example.test/mcp"}}}`) if err := os.WriteFile(filepath.Join(input.Envelope.SnapshotRoot, "mcp.json"), mcpBody, 0o644); err != nil { t.Fatal(err) diff --git a/install/integrationctl/agentplugins/usecase/native_projection.go b/install/integrationctl/agentplugins/usecase/native_projection.go index 7c632c340..1bac22102 100644 --- a/install/integrationctl/agentplugins/usecase/native_projection.go +++ b/install/integrationctl/agentplugins/usecase/native_projection.go @@ -56,15 +56,7 @@ func (service Service) activeNativeDelivery(ctx context.Context, input AddInput, if len(delivery.NativeObjects) != 1 { return delivery, false, false, fmt.Errorf("active package has no unique managed directory receipt") } - seen := map[string]bool{delivery.NativeObjects[0].ObjectID: true} - for _, object := range projected { - if object.ObjectID == "" || object.Kind == "" || seen[object.ObjectID] || object.Kind == "managed_package_directory" { - return delivery, false, false, fmt.Errorf("native projection has incomplete or duplicate ownership identity") - } - seen[object.ObjectID] = true - delivery.NativeObjects = append(delivery.NativeObjects, object) - } - delivery.NativeObjects, err = retainRecordedLocalSelector(plan.SelectedDelivery, client, delivery.NativeObjects) + delivery.NativeObjects, err = desiredNativeObjects(plan, client, delivery.NativeObjects[0], projected) if err != nil { return delivery, false, false, err } @@ -84,6 +76,23 @@ func (service Service) activeNativeDelivery(ctx context.Context, input AddInput, return delivery, false, false, nil } +// desiredNativeObjects assembles the unique owned identity of the desired +// projection: the managed package directory receipt first, then each projected +// object, then a reconciled recorded Local selector. +func desiredNativeObjects(plan domain.DeliveryPlan, client domain.ClientBinding, managed domain.NativeObjectOwnership, projected []domain.NativeObjectOwnership) ([]domain.NativeObjectOwnership, error) { + objects := make([]domain.NativeObjectOwnership, 0, len(projected)+1) + objects = append(objects, managed) + seen := map[string]bool{managed.ObjectID: true} + for _, object := range projected { + if object.ObjectID == "" || object.Kind == "" || seen[object.ObjectID] || object.Kind == "managed_package_directory" { + return nil, fmt.Errorf("native projection has incomplete or duplicate ownership identity") + } + seen[object.ObjectID] = true + objects = append(objects, object) + } + return retainRecordedLocalSelector(plan.SelectedDelivery, client, objects) +} + // manualRegistrationSettled reports an incomplete projection that no adapter // action could complete for this exact request. The classifier sees the same // request the acting adapter would, so a client whose adapter could act on From 2ef6b5350920c84fd7873cbea43413f735a29406 Mon Sep 17 00:00:00 2001 From: iliya Date: Wed, 21 Oct 2026 18:07:25 +0300 Subject: [PATCH 4/6] fix(cli): keep add-resume guidance for pending manual lifecycles A settled manual registration is now a no-change outcome, but the add printer claimed lifecycle verification was complete and dropped the "Next:" resume step whenever Activation was not fully installed. Limit that footer to fully installed lifecycles so a repeated add keeps resuming the manual onboarding without creating another receipt. --- cli/internal/agentpluginscli/add_result.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/internal/agentpluginscli/add_result.go b/cli/internal/agentpluginscli/add_result.go index bd9e85c80..296a1afde 100644 --- a/cli/internal/agentpluginscli/add_result.go +++ b/cli/internal/agentpluginscli/add_result.go @@ -102,7 +102,7 @@ func renderHumanAddOutcome(writer io.Writer, result usecase.AddResult) error { _, err := fmt.Fprintln(writer, message+"\nNext: "+nextLocalLifecycleAction(result)) return err } - if result.NoChange { + if result.NoChange && fullyInstalled(result.Activation) { _, _ = fmt.Fprintln(writer, terminaltheme.For(writer).Text(terminaltheme.Muted, "Already installed and lifecycle verification is complete. No changes made.")) return nil } From cbaaabbdb668384d1243935cc2b39e0fc64ead16 Mon Sep 17 00:00:00 2001 From: iliya Date: Wed, 21 Oct 2026 18:30:58 +0300 Subject: [PATCH 5/6] build: bump Go toolchain to 1.26.10 for GO-2026-6809 The crypto/x509 advisory published 2026-10-21 affects every stdlib before 1.26.10 (and 1.27.x before 1.27.3). All six govulncheck jobs are required by the release gate, so the repo-wide 1.26.9 pin moves to the same-line fix 1.26.10: go.mod/go.work toolchains, workflow setup-go pins, build-manifest go_version contracts, and the docs that state the required version. --- .github/workflows/agentplugins-native-clients.yml | 2 +- .github/workflows/agentplugins-npm-publish.yml | 2 +- .github/workflows/agentplugins-release.yml | 4 ++-- .../agentplugins-released-native-clients.yml | 2 +- .github/workflows/authoring-frozen-native.yml | 2 +- .github/workflows/authoring-milestone-a-e2e.yml | 4 ++-- .github/workflows/authoring-native.yml | 6 +++--- .github/workflows/ci.yml | 2 +- .github/workflows/codeql.yml | 2 +- .github/workflows/core-fast.yml | 12 ++++++------ .github/workflows/coverage.yml | 2 +- .github/workflows/darwin-terminal-cancel.yml | 2 +- .github/workflows/docs-canary.yml | 2 +- .github/workflows/docs-pages.yml | 2 +- .github/workflows/docs.yml | 2 +- .github/workflows/extended.yml | 2 +- .github/workflows/govulncheck.yml | 2 +- .github/workflows/landing.yml | 4 ++-- .github/workflows/lint.yml | 2 +- .github/workflows/live.yml | 2 +- .github/workflows/opencode-sdk.yml | 2 +- .github/workflows/physical-profile-native.yml | 2 +- .github/workflows/polyglot-smoke.yml | 2 +- .github/workflows/registry-compatibility-mirror.yml | 2 +- .github/workflows/terminal-ui.yml | 2 +- .github/workflows/terminal-windows-diagnostic.yml | 2 +- .github/workflows/vscode-local-native.yml | 4 ++-- Makefile | 2 +- cli/README.md | 2 +- cli/cmd/agentplugins/release_workflow_test.go | 2 +- cli/go.mod | 2 +- go.mod | 2 +- go.work | 2 +- .../agentplugins/geminihooks/README.md | 2 +- install/integrationctl/agentplugins/go.mod | 2 +- install/integrationctl/go.mod | 2 +- .../scripts/authoring-native-qualification.js | 6 +++--- npm/agentplugins/scripts/dual-authoring-candidate.js | 2 +- npm/agentplugins/scripts/packed-installer-bridge.md | 4 ++-- .../scripts/stage-dual-authoring-candidate.js | 4 ++-- .../test/authoring-native-inputs.test.js | 2 +- .../test/authoring-native-qualification.test.js | 6 +++--- npm/agentplugins/test/authoring-promotion.test.js | 2 +- .../test/authoring-release-producer.test.js | 6 +++--- .../test/dual-authoring-candidate-marker.test.js | 4 ++-- .../test/dual-authoring-candidate.test.js | 6 +++--- npm/agentplugins/test/private-npm-bootstrap.test.js | 2 +- npm/agentplugins/test/private-npm-fixture.js | 6 +++--- plugininstall/go.mod | 2 +- scripts/check-authoring-native-results.py | 2 +- scripts/check-packed-ci.py | 4 ++-- scripts/check-packed-workflow.py | 2 +- scripts/terminal-ui/README.md | 2 +- scripts/test_check_authoring_native_results.py | 4 ++-- scripts/test_packed_ci.py | 2 +- sdk/go.mod | 2 +- website/tools/lib/preflight.mjs | 4 ++-- 57 files changed, 84 insertions(+), 84 deletions(-) diff --git a/.github/workflows/agentplugins-native-clients.yml b/.github/workflows/agentplugins-native-clients.yml index 525dc95fa..1e2da7ad1 100644 --- a/.github/workflows/agentplugins-native-clients.yml +++ b/.github/workflows/agentplugins-native-clients.yml @@ -55,7 +55,7 @@ jobs: ref: ${{ github.event.pull_request.head.sha || github.sha }} - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: - go-version: '1.26.9' + go-version: '1.26.10' cache: false - name: Verify native matrix safety and evidence gates shell: bash diff --git a/.github/workflows/agentplugins-npm-publish.yml b/.github/workflows/agentplugins-npm-publish.yml index 21776759c..e53b69096 100644 --- a/.github/workflows/agentplugins-npm-publish.yml +++ b/.github/workflows/agentplugins-npm-publish.yml @@ -177,7 +177,7 @@ jobs: package-manager-cache: false - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: - go-version: "1.26.9" + go-version: "1.26.10" cache: false - name: Verify metadata, signatures, provenance, and isolated lifecycle env: diff --git a/.github/workflows/agentplugins-release.yml b/.github/workflows/agentplugins-release.yml index f707cb396..467a2ae95 100644 --- a/.github/workflows/agentplugins-release.yml +++ b/.github/workflows/agentplugins-release.yml @@ -115,7 +115,7 @@ jobs: - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 if: ${{ inputs.publish_release != true }} with: - go-version: 1.26.9 + go-version: 1.26.10 cache: false - name: Verify exact release-bound Directory bootstrap if: ${{ inputs.publish_release != true }} @@ -187,7 +187,7 @@ jobs: ref: ${{ needs.validate.outputs.commit }} - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: - go-version: 1.26.9 + go-version: 1.26.10 cache: false - name: Build exact-version binary env: diff --git a/.github/workflows/agentplugins-released-native-clients.yml b/.github/workflows/agentplugins-released-native-clients.yml index 9c4932578..6eabd140b 100644 --- a/.github/workflows/agentplugins-released-native-clients.yml +++ b/.github/workflows/agentplugins-released-native-clients.yml @@ -133,7 +133,7 @@ jobs: path: producer-source - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: - go-version: '1.26.9' + go-version: '1.26.10' cache: false - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: diff --git a/.github/workflows/authoring-frozen-native.yml b/.github/workflows/authoring-frozen-native.yml index d7fe1fff6..f3beab8b4 100644 --- a/.github/workflows/authoring-frozen-native.yml +++ b/.github/workflows/authoring-frozen-native.yml @@ -118,7 +118,7 @@ jobs: NODE - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: - go-version: 1.26.9 + go-version: 1.26.10 cache: false - name: Acquire and extract the same checked preparation ZIP env: diff --git a/.github/workflows/authoring-milestone-a-e2e.yml b/.github/workflows/authoring-milestone-a-e2e.yml index 9c02febff..62f538fac 100644 --- a/.github/workflows/authoring-milestone-a-e2e.yml +++ b/.github/workflows/authoring-milestone-a-e2e.yml @@ -30,7 +30,7 @@ jobs: persist-credentials: false - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e with: - go-version: '1.26.9' + go-version: '1.26.10' cache: false - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 with: @@ -111,7 +111,7 @@ jobs: - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e if: runner.os == 'macOS' with: - go-version: '1.26.9' + go-version: '1.26.10' cache: false - name: Check Darwin writable acquisition and separate read-only regressions if: runner.os == 'macOS' diff --git a/.github/workflows/authoring-native.yml b/.github/workflows/authoring-native.yml index ca73cf9c0..a0197f66f 100644 --- a/.github/workflows/authoring-native.yml +++ b/.github/workflows/authoring-native.yml @@ -51,7 +51,7 @@ jobs: persist-credentials: false - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # ci.yml with: - go-version: '1.26.9' + go-version: '1.26.10' architecture: ${{ matrix.arch == 'amd64' && 'x64' || matrix.arch }} cache: false - name: Prepare disposable second NTFS filesystem on Windows ARM64 @@ -94,7 +94,7 @@ jobs: go env -json GOOS GOARCH GOHOSTOS GOHOSTARCH GOVERSION GOROOT > "$NATIVE_ROOT/evidence/go-env.json" test "$(go env GOHOSTOS)/$(go env GOHOSTARCH)" = "$EXPECTED_OS/$EXPECTED_ARCH" test "$(go env GOOS)/$(go env GOARCH)" = "$EXPECTED_OS/$EXPECTED_ARCH" - test "$(go env GOVERSION)" = go1.26.9 + test "$(go env GOVERSION)" = go1.26.10 # Node is used only for generated JavaScript syntax checks (--check). unset NODE_OPTIONS NODE_PATH node --version > "$NATIVE_ROOT/evidence/node-version.txt" @@ -206,7 +206,7 @@ jobs: persist-credentials: false - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e with: - go-version: '1.26.9' + go-version: '1.26.10' architecture: x64 cache: false - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d2f20cb4d..08dba3648 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,7 +41,7 @@ jobs: - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: - go-version: "1.26.9" + go-version: "1.26.10" cache: false - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index bc8d9bef8..885d53c54 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -32,7 +32,7 @@ jobs: - if: matrix.language == 'go' uses: actions/setup-go@v6 with: - go-version: "1.26.9" + go-version: "1.26.10" cache: false - uses: github/codeql-action/init@v4 diff --git a/.github/workflows/core-fast.yml b/.github/workflows/core-fast.yml index a5c9bca17..e734a1b7a 100644 --- a/.github/workflows/core-fast.yml +++ b/.github/workflows/core-fast.yml @@ -46,7 +46,7 @@ jobs: persist-credentials: false - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: - go-version: "1.26.9" + go-version: "1.26.10" cache: false - name: Qualify native Windows transition privacy and durable recovery working-directory: install/integrationctl/agentplugins @@ -66,7 +66,7 @@ jobs: persist-credentials: false - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: - go-version: "1.26.9" + go-version: "1.26.10" cache: false - name: Qualify native Windows managed stdio process-tree ownership working-directory: install/integrationctl/agentplugins @@ -96,7 +96,7 @@ jobs: persist-credentials: false - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: - go-version: "1.26.9" + go-version: "1.26.10" cache: false - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: @@ -127,7 +127,7 @@ jobs: - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: - go-version: "1.26.9" + go-version: "1.26.10" cache: false # Same target as the local preflight, so a green run here means the same @@ -171,7 +171,7 @@ jobs: - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: - go-version: "1.26.9" + go-version: "1.26.10" cache: false # The core carries 39 platform-tagged files; only a real cross build @@ -197,7 +197,7 @@ jobs: - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: - go-version: "1.26.9" + go-version: "1.26.10" cache: false # test-core does not compile the authoring commands, terminal prompts, diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 896a53147..954cb7520 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -29,7 +29,7 @@ jobs: - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: - go-version: "1.26.9" + go-version: "1.26.10" cache: false - name: Collect Go coverage diff --git a/.github/workflows/darwin-terminal-cancel.yml b/.github/workflows/darwin-terminal-cancel.yml index 9c15fa60a..52d0403c3 100644 --- a/.github/workflows/darwin-terminal-cancel.yml +++ b/.github/workflows/darwin-terminal-cancel.yml @@ -29,7 +29,7 @@ jobs: persist-credentials: false - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e with: - go-version: '1.26.9' + go-version: '1.26.10' cache: false - name: Reproduce failure on the public pre-fix library shell: bash diff --git a/.github/workflows/docs-canary.yml b/.github/workflows/docs-canary.yml index 22a4a5084..8ec670c3b 100644 --- a/.github/workflows/docs-canary.yml +++ b/.github/workflows/docs-canary.yml @@ -28,7 +28,7 @@ jobs: - uses: actions/setup-go@v6 with: - go-version: "1.26.9" + go-version: "1.26.10" cache: false - name: Install pinned docs toolchain diff --git a/.github/workflows/docs-pages.yml b/.github/workflows/docs-pages.yml index feed6f554..dbeac639e 100644 --- a/.github/workflows/docs-pages.yml +++ b/.github/workflows/docs-pages.yml @@ -41,7 +41,7 @@ jobs: - uses: actions/setup-go@v6 with: - go-version: "1.26.9" + go-version: "1.26.10" cache: false - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.0.0 diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index ecb8b1e27..37537dae5 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -33,7 +33,7 @@ jobs: - uses: actions/setup-go@v6 with: - go-version: "1.26.9" + go-version: "1.26.10" cache: false - uses: actions/setup-python@v6 diff --git a/.github/workflows/extended.yml b/.github/workflows/extended.yml index 01ad2112a..341ff4c93 100644 --- a/.github/workflows/extended.yml +++ b/.github/workflows/extended.yml @@ -29,7 +29,7 @@ jobs: - uses: actions/setup-go@v6 with: - go-version: "1.26.9" + go-version: "1.26.10" cache: false - name: Run extended evidence lane diff --git a/.github/workflows/govulncheck.yml b/.github/workflows/govulncheck.yml index 6aabb1c27..30a11ddf9 100644 --- a/.github/workflows/govulncheck.yml +++ b/.github/workflows/govulncheck.yml @@ -38,7 +38,7 @@ jobs: - uses: actions/setup-go@v6 with: - go-version: "1.26.9" + go-version: "1.26.10" cache: false - name: Run govulncheck diff --git a/.github/workflows/landing.yml b/.github/workflows/landing.yml index 7479412e6..89954ae07 100644 --- a/.github/workflows/landing.yml +++ b/.github/workflows/landing.yml @@ -33,7 +33,7 @@ jobs: - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: - go-version: "1.26.9" + go-version: "1.26.10" cache: false - uses: pnpm/action-setup@a8198c4bff370c8506180b035930dea56dbd5288 # v5 @@ -132,7 +132,7 @@ jobs: - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: - go-version: "1.26.9" + go-version: "1.26.10" cache: false # Keep docs on its own packageManager; landing uses a newer lockfile format. diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 2f9e8f722..1acdd4c44 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -51,7 +51,7 @@ jobs: - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: - go-version: "1.26.9" + go-version: "1.26.10" cache: false # Correctness and style on changed lines only: the legacy tree predates the diff --git a/.github/workflows/live.yml b/.github/workflows/live.yml index 61b9205c1..11733474d 100644 --- a/.github/workflows/live.yml +++ b/.github/workflows/live.yml @@ -45,7 +45,7 @@ jobs: - uses: actions/setup-go@v6 with: - go-version: "1.26.9" + go-version: "1.26.10" cache: false - name: Run live evidence lane diff --git a/.github/workflows/opencode-sdk.yml b/.github/workflows/opencode-sdk.yml index 0d048ff44..323ffb68c 100644 --- a/.github/workflows/opencode-sdk.yml +++ b/.github/workflows/opencode-sdk.yml @@ -55,7 +55,7 @@ jobs: persist-credentials: false - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: - go-version: '1.26.9' + go-version: '1.26.10' cache: false - name: Check neutral wire decoder working-directory: sdk diff --git a/.github/workflows/physical-profile-native.yml b/.github/workflows/physical-profile-native.yml index 8f30029fe..1080eda8e 100644 --- a/.github/workflows/physical-profile-native.yml +++ b/.github/workflows/physical-profile-native.yml @@ -37,7 +37,7 @@ jobs: persist-credentials: false - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e with: - go-version: '1.26.9' + go-version: '1.26.10' cache: false - name: Create canonical Windows TEST temp root if: runner.os == 'Windows' diff --git a/.github/workflows/polyglot-smoke.yml b/.github/workflows/polyglot-smoke.yml index 3b4012a66..04392e5b5 100644 --- a/.github/workflows/polyglot-smoke.yml +++ b/.github/workflows/polyglot-smoke.yml @@ -40,7 +40,7 @@ jobs: - uses: actions/setup-go@v6 with: - go-version: "1.26.9" + go-version: "1.26.10" cache: false - uses: actions/setup-node@v6 diff --git a/.github/workflows/registry-compatibility-mirror.yml b/.github/workflows/registry-compatibility-mirror.yml index fbceb952d..ea163464f 100644 --- a/.github/workflows/registry-compatibility-mirror.yml +++ b/.github/workflows/registry-compatibility-mirror.yml @@ -43,7 +43,7 @@ jobs: - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: - go-version: "1.26.9" + go-version: "1.26.10" cache: false # Keep docs on its own packageManager; landing uses a newer lockfile format. diff --git a/.github/workflows/terminal-ui.yml b/.github/workflows/terminal-ui.yml index 3580f9d80..1f842bd9b 100644 --- a/.github/workflows/terminal-ui.yml +++ b/.github/workflows/terminal-ui.yml @@ -39,7 +39,7 @@ jobs: persist-credentials: false - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e with: - go-version: '1.26.9' + go-version: '1.26.10' cache: false - name: Focused contracts and frozen release build id: build diff --git a/.github/workflows/terminal-windows-diagnostic.yml b/.github/workflows/terminal-windows-diagnostic.yml index 74035351d..7f18258e4 100644 --- a/.github/workflows/terminal-windows-diagnostic.yml +++ b/.github/workflows/terminal-windows-diagnostic.yml @@ -22,7 +22,7 @@ jobs: persist-credentials: false - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e with: - go-version: '1.26.9' + go-version: '1.26.10' cache: false - name: Focused native contracts working-directory: cli diff --git a/.github/workflows/vscode-local-native.yml b/.github/workflows/vscode-local-native.yml index 7b823c0c9..418d4cd28 100644 --- a/.github/workflows/vscode-local-native.yml +++ b/.github/workflows/vscode-local-native.yml @@ -54,7 +54,7 @@ jobs: persist-credentials: false - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e with: - go-version: '1.26.9' + go-version: '1.26.10' cache: false - name: Qualify exact public renderer on native system shell run: | @@ -81,7 +81,7 @@ jobs: GOPROXY=off GOSUMDB=off GOMAXPROCS=2 U2_REQUIRE_NATIVE="$U2_REQUIRE_NATIVE") "${native_env[@]}" "$go_bin" env -json GOHOSTOS GOOS GOARCH GOVERSION > "$scratch/evidence/go-env.json" test "$("${native_env[@]}" "$go_bin" env GOHOSTOS)" = "$U2_REQUIRE_NATIVE" - test "$("${native_env[@]}" "$go_bin" env GOVERSION)" = go1.26.9 + test "$("${native_env[@]}" "$go_bin" env GOVERSION)" = go1.26.10 set +e "${native_env[@]}" "$go_bin" test -p 2 -count=1 -timeout=3m -json ./vscodelocalhooks \ > "$scratch/evidence/test.json" 2> "$scratch/evidence/test.stderr" diff --git a/Makefile b/Makefile index 00cc6c9ef..9d54aaaa6 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ GOCACHE ?= /tmp/plugin-kit-ai-gocache export GOCACHE -SECURITY_GOTOOLCHAIN ?= go1.26.9 +SECURITY_GOTOOLCHAIN ?= go1.26.10 EXTENDED_TEST_ARGS ?= REQUIRED_TEST_TIMEOUT ?= 20m diff --git a/cli/README.md b/cli/README.md index f5e3a196f..2785af004 100644 --- a/cli/README.md +++ b/cli/README.md @@ -100,7 +100,7 @@ go build -o bin/plugin-kit-ai ./cli/cmd/plugin-kit-ai Choose the lane that matches the delivery model you need today. Expand later from the same repo when the product needs more outputs. -Maintainer note: building the checked-in monorepo workspace currently requires Go `1.26.9` for the CLI module and CI lanes. Generated Go plugin projects stay on the public Go SDK path with Go `1.22+`. +Maintainer note: building the checked-in monorepo workspace currently requires Go `1.26.10` for the CLI module and CI lanes. Generated Go plugin projects stay on the public Go SDK path with Go `1.22+`. ## Fast Local Plugin For repo-local plugins where fast iteration matters more than packaged distribution: diff --git a/cli/cmd/agentplugins/release_workflow_test.go b/cli/cmd/agentplugins/release_workflow_test.go index 2b03c0dec..c97cc3e38 100644 --- a/cli/cmd/agentplugins/release_workflow_test.go +++ b/cli/cmd/agentplugins/release_workflow_test.go @@ -33,7 +33,7 @@ func TestStableReleaseRequiresVerifiedReproducibleBootstrapBeforeBuild(t *testin t.Fatal("Directory bootstrap gate must be in validate before build") } for _, required := range []string{ - "go-version: 1.26.9", + "go-version: 1.26.10", "node-version: \"22.21.1\"", "GOWORK: \"off\"", "GOTOOLCHAIN: local", diff --git a/cli/go.mod b/cli/go.mod index 4aa6bb6ee..9ca68cd52 100644 --- a/cli/go.mod +++ b/cli/go.mod @@ -2,7 +2,7 @@ module github.com/777genius/plugin-kit-ai/cli go 1.25.8 -toolchain go1.26.9 +toolchain go1.26.10 replace github.com/777genius/plugin-kit-ai/sdk => ../sdk diff --git a/go.mod b/go.mod index a658fcc5c..1a57c1596 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,4 @@ module github.com/777genius/plugin-kit-ai go 1.22 -toolchain go1.26.9 +toolchain go1.26.10 diff --git a/go.work b/go.work index 82393fb4e..85661d5c1 100644 --- a/go.work +++ b/go.work @@ -1,6 +1,6 @@ go 1.25.8 -toolchain go1.26.9 +toolchain go1.26.10 use ( . diff --git a/install/integrationctl/agentplugins/geminihooks/README.md b/install/integrationctl/agentplugins/geminihooks/README.md index 4f337d95a..43bdcf4bd 100644 --- a/install/integrationctl/agentplugins/geminihooks/README.md +++ b/install/integrationctl/agentplugins/geminihooks/README.md @@ -112,7 +112,7 @@ trailing commas are rejected because native settings use Tests cover comment-bearing fixtures and trailing-comma rejection; they do not claim exhaustive grammar parity with strip-json-comments. -Run from the module with Go 1.26.9, `go test -p 2 ./geminihooks +Run from the module with Go 1.26.10, `go test -p 2 ./geminihooks ./adapters/nativeconfig`. Tests require Node >=22.18 to execute the unchanged official 0.62.0 environment resolver fixture. Its supplied source provenance is Gemini v0.62.0 commit `b460678f3db508407554afd604cc9d6635becb2a`, diff --git a/install/integrationctl/agentplugins/go.mod b/install/integrationctl/agentplugins/go.mod index 8cf354e0a..c7b97bccd 100644 --- a/install/integrationctl/agentplugins/go.mod +++ b/install/integrationctl/agentplugins/go.mod @@ -2,7 +2,7 @@ module github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins go 1.25.0 -toolchain go1.26.9 +toolchain go1.26.10 replace github.com/777genius/plugin-kit-ai/install/integrationctl => ../ diff --git a/install/integrationctl/go.mod b/install/integrationctl/go.mod index 52626407f..d2c714e81 100644 --- a/install/integrationctl/go.mod +++ b/install/integrationctl/go.mod @@ -2,7 +2,7 @@ module github.com/777genius/plugin-kit-ai/install/integrationctl go 1.25.0 -toolchain go1.26.9 +toolchain go1.26.10 require gopkg.in/yaml.v3 v3.0.1 diff --git a/npm/agentplugins/scripts/authoring-native-qualification.js b/npm/agentplugins/scripts/authoring-native-qualification.js index 1912a0a3c..f4b3db14d 100644 --- a/npm/agentplugins/scripts/authoring-native-qualification.js +++ b/npm/agentplugins/scripts/authoring-native-qualification.js @@ -908,7 +908,7 @@ function readTerminals(root, inputRoot, pins, expected) { exact(host, { platform: contract.platform, architecture: contract.architecture, machine: contract.machine, target, observation: "whole-descendant-authoring-no-process-network/1" }); c.keys(expected.tools, ["go", "node"], "host tools"); - for (const [name, version] of [["go", "go1.26.9"], ["node", "v22.21.1"]]) { + for (const [name, version] of [["go", "go1.26.10"], ["node", "v22.21.1"]]) { c.keys(expected.tools[name], ["sha256", "version"], "tool pin"); sha(expected.tools[name].sha256); exact(expected.tools[name].version, version); } const result = []; @@ -944,7 +944,7 @@ async function produce(options, signal) { const tool = context(path.join(options.work, "host-tool")); const go = await subprocess(options.go, ["env", "-json", "GOVERSION", "GOHOSTOS", "GOHOSTARCH"], tool, signal); exact(go.status, 0); exact(go.stderr, ""); - exact(JSON.parse(go.stdout), { GOVERSION: "go1.26.9", GOHOSTOS: contract.goos, GOHOSTARCH: contract.goarch }); + exact(JSON.parse(go.stdout), { GOVERSION: "go1.26.10", GOHOSTOS: contract.goos, GOHOSTARCH: contract.goarch }); for (const p of c.PRODUCTS) { contexts[p] = context(path.join(options.work, p)); const a = frozen.manifest.products[p].assets[target], bytes = c.readFile(path.join(root, p, a.file)); @@ -1033,7 +1033,7 @@ async function produce(options, signal) { e["host.json"] = { platform: process.platform, architecture: process.arch, machine: os.machine(), target, observation: "whole-descendant-authoring-no-process-network/1" }; verifyJourney(e, pins, target); - const tools = { go: { sha256: options.go_sha256, version: "go1.26.9" }, node: { sha256: c.digest(c.readFile(process.execPath)), version: process.version } }; + const tools = { go: { sha256: options.go_sha256, version: "go1.26.10" }, node: { sha256: c.digest(c.readFile(process.execPath)), version: process.version } }; for (const file of FILES) fs.writeFileSync(path.join(options.output, file), c.encode(e[file]), { flag: "wx", mode: 0o400 }); if (signal?.aborted) fail("cancelled before terminal"); for (const p of c.PRODUCTS) { diff --git a/npm/agentplugins/scripts/dual-authoring-candidate.js b/npm/agentplugins/scripts/dual-authoring-candidate.js index 5a46dbef2..d3402cd21 100644 --- a/npm/agentplugins/scripts/dual-authoring-candidate.js +++ b/npm/agentplugins/scripts/dual-authoring-candidate.js @@ -192,7 +192,7 @@ function manifestShape(manifest, expected, expectedScope, expectedMode) { manifest.identity.commit !== expected.commit || manifest.identity.repository !== expected.repository || PRODUCTS.some((p) => manifest.identity.versions[p] !== expected.versions[p])) throw new Error("candidate identity/schema mismatch"); keys(manifest.build, ["method", "go_version", "go_sha256", "source_archive_sha256", "authoring_mode"], "build"); - if (manifest.build.method !== "controlled-git-archive-go-build/v1" || manifest.build.go_version !== "go1.26.9" || + if (manifest.build.method !== "controlled-git-archive-go-build/v1" || manifest.build.go_version !== "go1.26.10" || manifest.build.authoring_mode !== mode || typeof manifest.build.go_sha256 !== "string" || typeof manifest.build.source_archive_sha256 !== "string" || !/^[0-9a-f]{64}$/.test(manifest.build.go_sha256) || !/^[0-9a-f]{64}$/.test(manifest.build.source_archive_sha256)) { diff --git a/npm/agentplugins/scripts/packed-installer-bridge.md b/npm/agentplugins/scripts/packed-installer-bridge.md index d42d2a0a9..5431f762a 100644 --- a/npm/agentplugins/scripts/packed-installer-bridge.md +++ b/npm/agentplugins/scripts/packed-installer-bridge.md @@ -75,7 +75,7 @@ namespace contract, not protection against a hostile concurrent same-UID writer. every symlink; the containing npm fixture permits only contained symlinks such as installed `.bin` links. All ordinary files must have one hard link. -4. Run only the packed bridge test, using installed Go **1.26.9**, offline cache, +4. Run only the packed bridge test, using installed Go **1.26.10**, offline cache, private HOME/TMP/config/GOCACHE and `GOMAXPROCS=2`. Keep result in a different external directory from config and all observed inputs. Example from checkout: @@ -141,7 +141,7 @@ Use the same offline/private environment above, without any packed opt-in vars. exact-SHA checkout and 45-minute ceiling. It runs `scripts/run-packed-ci.py "$PACKED_ROOT" "$EXPECTED_HEAD"` after setup. `PACKED_ROOT` must be absent, absolute and outside checkout. The runner resolves installed Go, Node and npm's -JavaScript CLI; no root-host tool or cache paths are embedded. Go is 1.26.9, +JavaScript CLI; no root-host tool or cache paths are embedded. Go is 1.26.10, Node is **22.23.2**, and npm is its bundled **10.9.8**, with no npm upgrade. ROOT selected this pair from the fresh official Node release index (2026-07-28 security release). Versions and tool SHA256 hashes, including stager Node, are diff --git a/npm/agentplugins/scripts/stage-dual-authoring-candidate.js b/npm/agentplugins/scripts/stage-dual-authoring-candidate.js index 59810e9a4..c3b84a2f6 100644 --- a/npm/agentplugins/scripts/stage-dual-authoring-candidate.js +++ b/npm/agentplugins/scripts/stage-dual-authoring-candidate.js @@ -10,7 +10,7 @@ const cp = require("node:child_process"); const c = require("./dual-authoring-candidate"); const SOURCE_PATHS = ["go.mod", "go.work", "go.work.sum", "cli", "install", "plugininstall", "sdk"]; -const GO_VERSION = "go1.26.9"; +const GO_VERSION = "go1.26.10"; function run(command, args, options = {}) { return cp.execFileSync(command, args, { timeout: 10 * 60 * 1000, maxBuffer: 64 * 1024 * 1024, ...options }); @@ -52,7 +52,7 @@ function toolchain(go, context) { const hash = c.digest(c.readFile(go)); const info = JSON.parse(run(go, ["env", "-json", "GOVERSION", "GOHOSTOS", "GOHOSTARCH"], { env: context.env })); if (info.GOVERSION !== GO_VERSION || info.GOHOSTOS !== "linux" || info.GOHOSTARCH !== "amd64") { - throw new Error("this bounded candidate producer/verifier requires trusted Go 1.26.9 on Linux amd64"); + throw new Error("this bounded candidate producer/verifier requires trusted Go 1.26.10 on Linux amd64"); } return hash; } diff --git a/npm/agentplugins/test/authoring-native-inputs.test.js b/npm/agentplugins/test/authoring-native-inputs.test.js index 2832cd09e..0ee574471 100644 --- a/npm/agentplugins/test/authoring-native-inputs.test.js +++ b/npm/agentplugins/test/authoring-native-inputs.test.js @@ -350,7 +350,7 @@ function c1Fixture(t) { fs.writeFileSync(file, bytes); return c.metadata(bytes); }; const manifest = { schema: c.SCHEMA, status: "CANDIDATE", identity: input.identity, asset_scope: input.asset_scope, - build: { method: "controlled-git-archive-go-build/v1", go_version: "go1.26.9", go_sha256: sha(80), + build: { method: "controlled-git-archive-go-build/v1", go_version: "go1.26.10", go_sha256: sha(80), source_archive_sha256: sha(81), authoring_mode: input.authoring_mode }, products: {}, release_eligible: false }; for (const product of products) { for (const target of targets) { diff --git a/npm/agentplugins/test/authoring-native-qualification.test.js b/npm/agentplugins/test/authoring-native-qualification.test.js index 67f2ab97c..7f485537b 100644 --- a/npm/agentplugins/test/authoring-native-qualification.test.js +++ b/npm/agentplugins/test/authoring-native-qualification.test.js @@ -196,14 +196,14 @@ function output(value, status=0) { } function main() { if (selected === cfg.go) { - if (argv[0]==='env') return output({GOVERSION:'go1.26.9',GOHOSTOS:'linux',GOHOSTARCH:'amd64'}); + if (argv[0]==='env') return output({GOVERSION:'go1.26.10',GOHOSTOS:'linux',GOHOSTARCH:'amd64'}); const p = path.basename(argv[3]); const settings = {GOOS:'linux',GOARCH:'amd64',CGO_ENABLED:'0','-buildmode':'exe','-compiler':'gc', '-ldflags':cfg.linker[p]}; if(scenario==='wrong-build-target') settings.GOARCH='arm64'; if(scenario==='wrong-build-mode') settings['-buildmode']='pie'; if(scenario==='wrong-build-source') settings['-ldflags']=settings['-ldflags'].replace(cfg.identity.commit,'b'.repeat(40)); - return output({GoVersion:'go1.26.9',Path:'github.com/777genius/plugin-kit-ai/cli/cmd/'+(scenario==='wrong-binary'?'peer':p), + return output({GoVersion:'go1.26.10',Path:'github.com/777genius/plugin-kit-ai/cli/cmd/'+(scenario==='wrong-binary'?'peer':p), Settings:Object.entries(settings).map(([Key,Value])=>({Key,Value}))}); } let args=argv.filter(x=>x!=='--format=json'); @@ -431,7 +431,7 @@ function subprocessFixtures(t, f, scenario = "ok") { } function expectations(f) { return { producer: f.options.producer, preparation: f.options.preparation, - tools: { go: { sha256: f.options.go_sha256, version: "go1.26.9" }, node: { sha256: c.digest(c.readFile(process.execPath)), version: process.version } } }; + tools: { go: { sha256: f.options.go_sha256, version: "go1.26.10" }, node: { sha256: c.digest(c.readFile(process.execPath)), version: process.version } } }; } test("shared verifier consumes uploaded projections, not missing flat candidate assets", () => { diff --git a/npm/agentplugins/test/authoring-promotion.test.js b/npm/agentplugins/test/authoring-promotion.test.js index 819b62982..d6393515a 100644 --- a/npm/agentplugins/test/authoring-promotion.test.js +++ b/npm/agentplugins/test/authoring-promotion.test.js @@ -22,7 +22,7 @@ function fixture() { const root = path.join(sandbox, "frozen"), scratch = path.join(sandbox, "provider"); fs.mkdirSync(root); fs.mkdirSync(scratch); fs.mkdirSync(path.join(root, "candidate")); const manifest = { schema: c.SCHEMA, status: "CANDIDATE", identity: structuredClone(ID), asset_scope: "six-platform-pair", - build: { method: "controlled-git-archive-go-build/v1", go_version: "go1.26.9", go_sha256: hash("go fixture"), + build: { method: "controlled-git-archive-go-build/v1", go_version: "go1.26.10", go_sha256: hash("go fixture"), source_archive_sha256: hash("source fixture"), authoring_mode: "release-cli-contract-v1" }, products: {}, release_eligible: false }; for (const product of c.PRODUCTS) { const assets = {}; diff --git a/npm/agentplugins/test/authoring-release-producer.test.js b/npm/agentplugins/test/authoring-release-producer.test.js index 6fd1d0192..4b84c4983 100644 --- a/npm/agentplugins/test/authoring-release-producer.test.js +++ b/npm/agentplugins/test/authoring-release-producer.test.js @@ -31,7 +31,7 @@ const fs = require('node:fs'); const args = process.argv.slice(2); fs.appendFileSync(${JSON.stringify(path.join(sandbox, "calls.jsonl"))}, JSON.stringify(args) + '\\n'); if (JSON.stringify(args) === JSON.stringify(['env', '-json', 'GOVERSION', 'GOHOSTOS', 'GOHOSTARCH'])) { - console.log(JSON.stringify({ GOVERSION: 'go1.26.9', GOHOSTOS: 'linux', GOHOSTARCH: 'amd64' })); + console.log(JSON.stringify({ GOVERSION: 'go1.26.10', GOHOSTOS: 'linux', GOHOSTARCH: 'amd64' })); } else if (args.length === 4 && args.slice(0, 3).join(' ') === 'version -m -json') { const stat = fs.statSync(args[3]); if (stat.mode & 0o111) throw Error('subject executable permission'); @@ -39,14 +39,14 @@ if (JSON.stringify(args) === JSON.stringify(['env', '-json', 'GOVERSION', 'GOHOS } else throw Error('compile or unexpected tool invocation forbidden'); `, { mode: 0o755 }); const manifest = { schema: c.SCHEMA, status: "CANDIDATE", identity: structuredClone(ID), asset_scope: SCOPE, - build: { method: "controlled-git-archive-go-build/v1", go_version: "go1.26.9", go_sha256: c.digest(c.readFile(go)), + build: { method: "controlled-git-archive-go-build/v1", go_version: "go1.26.10", go_sha256: c.digest(c.readFile(go)), source_archive_sha256: "c".repeat(64), authoring_mode: MODE }, products: {}, release_eligible: false }; for (const product of c.PRODUCTS) { const assets = {}; manifest.products[product] = { version: ID.versions[product], assets }; for (const target of c.TARGETS) { const [GOOS, GOARCH] = target.split("-"); - const binary = c.encode({ GoVersion: "go1.26.9", Path: `github.com/777genius/plugin-kit-ai/cli/cmd/${product}`, + const binary = c.encode({ GoVersion: "go1.26.10", Path: `github.com/777genius/plugin-kit-ai/cli/cmd/${product}`, Settings: Object.entries({ GOOS, GOARCH, CGO_ENABLED: "0", "-buildmode": "exe", "-compiler": "gc", "-ldflags": c.linkerFlags(product, ID, MODE) }).map(([Key, Value]) => ({ Key, Value })) }); const file = c.assetName(product, ID.versions[product], target); diff --git a/npm/agentplugins/test/dual-authoring-candidate-marker.test.js b/npm/agentplugins/test/dual-authoring-candidate-marker.test.js index 0b80e61a1..1214bee05 100644 --- a/npm/agentplugins/test/dual-authoring-candidate-marker.test.js +++ b/npm/agentplugins/test/dual-authoring-candidate-marker.test.js @@ -44,7 +44,7 @@ function fixture(t, mode) { const exec = cp.execFileSync; t.mock.method(cp, "execFileSync", function (command, args, opts) { if (command !== options.go) return exec.apply(this, arguments); - if (args[0] === "env") return JSON.stringify({ GOVERSION: "go1.26.9", GOHOSTOS: "linux", GOHOSTARCH: "amd64" }); + if (args[0] === "env") return JSON.stringify({ GOVERSION: "go1.26.10", GOHOSTOS: "linux", GOHOSTARCH: "amd64" }); if (args[0] === "build") { const product = args.at(-1).split("/").at(-1); assert.equal(args[args.indexOf("-ldflags") + 1], c.linkerFlags(product, identity, mode)); @@ -54,7 +54,7 @@ function fixture(t, mode) { assert.equal(args[0], "version"); const product = fs.readFileSync(args.at(-1), "utf8").replace("STRUCTURAL ONLY: ", ""); assert.ok(c.PRODUCTS.includes(product)); - return JSON.stringify({ GoVersion: "go1.26.9", Path: `github.com/777genius/plugin-kit-ai/cli/cmd/${product}`, + return JSON.stringify({ GoVersion: "go1.26.10", Path: `github.com/777genius/plugin-kit-ai/cli/cmd/${product}`, Settings: Object.entries({ GOOS: "linux", GOARCH: "amd64", CGO_ENABLED: "0", "-buildmode": "exe", "-compiler": "gc", "-ldflags": c.linkerFlags(product, identity, mode) }).map(([Key, Value]) => ({ Key, Value })) }); }); diff --git a/npm/agentplugins/test/dual-authoring-candidate.test.js b/npm/agentplugins/test/dual-authoring-candidate.test.js index 4b3ddf645..aecaaab83 100644 --- a/npm/agentplugins/test/dual-authoring-candidate.test.js +++ b/npm/agentplugins/test/dual-authoring-candidate.test.js @@ -25,7 +25,7 @@ function structuralFixture() { const root = temp(); const manifest = { schema: c.SCHEMA, status: "CANDIDATE", asset_scope: SCOPE, identity: structuredClone(ID), - build: { method: "controlled-git-archive-go-build/v1", go_version: "go1.26.9", + build: { method: "controlled-git-archive-go-build/v1", go_version: "go1.26.10", go_sha256: "b".repeat(64), source_archive_sha256: "c".repeat(64), authoring_mode: "vertical-slice-v1" }, products: {}, release_eligible: false }; @@ -233,7 +233,7 @@ test("canonical archive rejects path traversal, links, headers, extra records an test("Go build-info parser binds actual main path, flags, product version, engine, target and compiler", () => { const valid = { - GoVersion: "go1.26.9", Path: "github.com/777genius/plugin-kit-ai/cli/cmd/agentplugins", + GoVersion: "go1.26.10", Path: "github.com/777genius/plugin-kit-ai/cli/cmd/agentplugins", Settings: Object.entries({ GOOS: "linux", GOARCH: "amd64", CGO_ENABLED: "0", "-buildmode": "exe", "-compiler": "gc", "-ldflags": c.linkerFlags("agentplugins", ID) }).map(([Key, Value]) => ({ Key, Value })) }; @@ -292,7 +292,7 @@ test("private mode is explicit, closed and bound to embedded bytes", () => { assert.equal(c.authoringMode(), "vertical-slice-v1"); assert.throws(() => c.authoringMode("enabled"), /unknown private/); assert.notEqual(c.linkerFlags("agentplugins", ID), c.linkerFlags("agentplugins", ID, mode)); - const info = { GoVersion: "go1.26.9", Path: "github.com/777genius/plugin-kit-ai/cli/cmd/agentplugins", + const info = { GoVersion: "go1.26.10", Path: "github.com/777genius/plugin-kit-ai/cli/cmd/agentplugins", Settings: Object.entries({ GOOS: "linux", GOARCH: "amd64", CGO_ENABLED: "0", "-buildmode": "exe", "-compiler": "gc", "-ldflags": c.linkerFlags("agentplugins", ID, mode) }).map(([Key, Value]) => ({ Key, Value })) }; producer.buildInfo(info, "agentplugins", "linux-amd64", ID, mode); diff --git a/npm/agentplugins/test/private-npm-bootstrap.test.js b/npm/agentplugins/test/private-npm-bootstrap.test.js index e7a9bf3ec..bdaa4944b 100644 --- a/npm/agentplugins/test/private-npm-bootstrap.test.js +++ b/npm/agentplugins/test/private-npm-bootstrap.test.js @@ -26,7 +26,7 @@ function fixture(scope = "linux-amd64-pair", identity = ID) { const source = path.join(ancestor, "candidate"); mkdir(source); const cache = path.join(root, "cache with spaces"); mkdir(cache); const manifest = { schema: c.SCHEMA, status: "CANDIDATE", identity: structuredClone(identity), asset_scope: scope, - build: { method: "controlled-git-archive-go-build/v1", go_version: "go1.26.9", go_sha256: "b".repeat(64), + build: { method: "controlled-git-archive-go-build/v1", go_version: "go1.26.10", go_sha256: "b".repeat(64), source_archive_sha256: "c".repeat(64), authoring_mode: "vertical-slice-v1" }, products: {}, release_eligible: false }; const packages = {}, descriptors = {}, bodies = {}; for (const product of c.PRODUCTS) { diff --git a/npm/agentplugins/test/private-npm-fixture.js b/npm/agentplugins/test/private-npm-fixture.js index dac102ba9..444b33f22 100644 --- a/npm/agentplugins/test/private-npm-fixture.js +++ b/npm/agentplugins/test/private-npm-fixture.js @@ -53,13 +53,13 @@ function sourceFixture(root, env) { function candidate(root, commit, versions = { agentplugins: "0.1.23", "plugin-kit-ai": "2.0.0" }, behavior = "normal") { const source = mkdir(path.join(root, "candidate inputs with spaces", "candidate")); const go = path.join(mkdir(path.join(root, "tools")), "mock-go"); - write(go, `#!${node}\nconst fs=require('node:fs');const a=process.argv.slice(2);\nif(a[0]==='env') console.log(JSON.stringify({GOVERSION:'go1.26.9',GOHOSTOS:'linux',GOHOSTARCH:'amd64'}));\nelse if(a[1]==='-m')console.log(fs.readFileSync(a[3],'utf8').split('\\n')[1].slice(2));\nelse console.log('go version go1.26.9 linux/amd64 (STRUCTURAL MOCK)');\n`, 0o755); + write(go, `#!${node}\nconst fs=require('node:fs');const a=process.argv.slice(2);\nif(a[0]==='env') console.log(JSON.stringify({GOVERSION:'go1.26.10',GOHOSTOS:'linux',GOHOSTARCH:'amd64'}));\nelse if(a[1]==='-m')console.log(fs.readFileSync(a[3],'utf8').split('\\n')[1].slice(2));\nelse console.log('go version go1.26.10 linux/amd64 (STRUCTURAL MOCK)');\n`, 0o755); const identity = { repository: c.REPOSITORY, commit, engine_revision: commit, versions }; const manifest = { schema: c.SCHEMA, status: "CANDIDATE", identity, asset_scope: "linux-amd64-pair", - build: { method: "controlled-git-archive-go-build/v1", go_version: "go1.26.9", go_sha256: c.digest(fs.readFileSync(go)), + build: { method: "controlled-git-archive-go-build/v1", go_version: "go1.26.10", go_sha256: c.digest(fs.readFileSync(go)), source_archive_sha256: "c".repeat(64), authoring_mode: s.MODE }, products: {}, release_eligible: false }; for (const product of c.PRODUCTS) { - const info = { GoVersion: "go1.26.9", Path: `github.com/777genius/plugin-kit-ai/cli/cmd/${product}`, + const info = { GoVersion: "go1.26.10", Path: `github.com/777genius/plugin-kit-ai/cli/cmd/${product}`, Settings: Object.entries({ GOOS: "linux", GOARCH: "amd64", CGO_ENABLED: "0", "-buildmode": "exe", "-compiler": "gc", "-ldflags": c.linkerFlags(product, identity, s.MODE) }).map(([Key, Value]) => ({ Key, Value })) }; const body = Buffer.from(`#!${behavior === "spawn-error" ? "/absent-structural-interpreter" : node}\n//${JSON.stringify(info)}\n` + diff --git a/plugininstall/go.mod b/plugininstall/go.mod index dbfa27276..1479e23f9 100644 --- a/plugininstall/go.mod +++ b/plugininstall/go.mod @@ -2,4 +2,4 @@ module github.com/777genius/plugin-kit-ai/plugininstall go 1.22 -toolchain go1.26.9 +toolchain go1.26.10 diff --git a/scripts/check-authoring-native-results.py b/scripts/check-authoring-native-results.py index f8b400fc8..3952f7016 100644 --- a/scripts/check-authoring-native-results.py +++ b/scripts/check-authoring-native-results.py @@ -98,7 +98,7 @@ def digest(path): require(native_arch == env["GOHOSTARCH"] == env["GOARCH"] == os.environ["EXPECTED_ARCH"], "native architecture mismatch") require(native_arch in ("amd64", "arm64"), "unsupported native architecture") require(os.environ.get("RUNNER_ARCH", "").lower() == {"amd64": "x64", "arm64": "arm64"}.get(native_arch), "runner architecture mismatch") - require(env["GOVERSION"] == "go1.26.9", "Go pin mismatch") + require(env["GOVERSION"] == "go1.26.10", "Go pin mismatch") suffix = ".exe" if native_os == "windows" else "" summary["go_sha256"] = digest(Path(env["GOROOT"]) / "bin" / ("go" + suffix)) binaries = {name: digest(root / "bin" / (name + suffix)) for name in ("agentplugins", "plugin-kit-ai")} diff --git a/scripts/check-packed-ci.py b/scripts/check-packed-ci.py index 5abc3b3df..22f5232a6 100644 --- a/scripts/check-packed-ci.py +++ b/scripts/check-packed-ci.py @@ -9,7 +9,7 @@ import stat import sys -VERSIONS = dict(go='go1.26.9', node='v22.23.2', npm='10.9.8') +VERSIONS = dict(go='go1.26.10', node='v22.23.2', npm='10.9.8') MODE = 'release-cli-contract-v1' PRODUCTS = ('agentplugins', 'plugin-kit-ai') LANES = ('skill', 'mcp-remote', 'mcp-stdio', 'hybrid-remote', 'hybrid-stdio') @@ -212,7 +212,7 @@ def check(root, sha): for name in ('node', 'npm', 'go', 'stager_node'): tool = pack['tools'][name]; key = 'node' if name == 'stager_node' else name require(tool['path'] == run['tools'][key]['path'] and tool['sha256'] == run['tools'][key]['sha256'], 'stager tool hash') - require(tool['version'] == ('go version go1.26.9 linux/amd64' if key == 'go' else VERSIONS[key]), 'stager tool version') + require(tool['version'] == ('go version go1.26.10 linux/amd64' if key == 'go' else VERSIONS[key]), 'stager tool version') require(candidate['build']['go_version'] == VERSIONS['go'] and candidate['build']['authoring_mode'] == MODE and candidate['build']['go_sha256'] == run['tools']['go']['sha256'], 'candidate build identity') invocations = read(root / 'native/invocations.json') diff --git a/scripts/check-packed-workflow.py b/scripts/check-packed-workflow.py index 74b355b80..cc9cb9e29 100644 --- a/scripts/check-packed-workflow.py +++ b/scripts/check-packed-workflow.py @@ -54,7 +54,7 @@ def check(text, runner): ' persist-credentials: false\n' in body, 'exact clean checkout') require(not re.search(r'\|\|\s*(?:true|:)|exit 0|set \+e', body), 'masked failure') require(all(line.strip() == 'if: always()' for line in body.splitlines() if re.match(r'\s*if:', line)), 'skipped step') - require(' go-version: \'1.26.9\'' in packed and " node-version: '22.23.2'" in packed, 'tool pins') + require(' go-version: \'1.26.10\'' in packed and " node-version: '22.23.2'" in packed, 'tool pins') require(' run: python3 -B scripts/run-packed-ci.py "$PACKED_ROOT" "$EXPECTED_HEAD"\n' in packed and ' run: python3 -B scripts/check-packed-ci.py "$PACKED_ROOT" "$EXPECTED_HEAD"\n' in packed, 'runner/checker required') require(' python3 -B scripts/check-packed-workflow.py\n' in aggregate and diff --git a/scripts/terminal-ui/README.md b/scripts/terminal-ui/README.md index bd6c3f1a2..ba330b8ec 100644 --- a/scripts/terminal-ui/README.md +++ b/scripts/terminal-ui/README.md @@ -9,7 +9,7 @@ Codex and Cursor must be the only compatible choices. Unknown ambient choices must be investigated, not accepted by updating expected targets. ```sh -# From repository root; Go 1.26.9 or the integration's required toolchain. +# From repository root; Go 1.26.10 or the integration's required toolchain. (cd cli && GOTOOLCHAIN=local \ GOMODCACHE=/tmp/uap-go-modcache GOCACHE=/tmp/uap-go-buildcache \ /tmp/uap-go-toolchain/go/bin/go build -o /tmp/agentplugins-ui ./cmd/agentplugins) diff --git a/scripts/test_check_authoring_native_results.py b/scripts/test_check_authoring_native_results.py index d3975624c..76467eec4 100644 --- a/scripts/test_check_authoring_native_results.py +++ b/scripts/test_check_authoring_native_results.py @@ -171,7 +171,7 @@ def fixture(self, system, arch): (evidence / "head.txt").write_text(head) self.system, self.arch, self.root = system, arch, root self.env = dict(GOOS=system, GOHOSTOS=system, GOARCH=arch, GOHOSTARCH=arch, - GOVERSION="go1.26.9", GOROOT=str(root / "go")) + GOVERSION="go1.26.10", GOROOT=str(root / "go")) self.expected = dict(EXPECTED_OS=system, EXPECTED_ARCH=arch, EXPECTED_HEAD=head, RUNNER_ARCH="X64" if arch == "amd64" else "ARM64") self.suffix = ".exe" if system == "windows" else "" @@ -180,7 +180,7 @@ def fixture(self, system, arch): for name in ("agentplugins", "plugin-kit-ai"): (root / "bin" / (name + self.suffix)).write_bytes(executable(system, arch)) settings = dict(GOOS=system, GOARCH=arch, **{"vcs.revision": head, "vcs.modified": "false"}) - self.builds[name] = dict(GoVersion="go1.26.9", + self.builds[name] = dict(GoVersion="go1.26.10", Path="github.com/777genius/plugin-kit-ai/cli/cmd/" + name, Settings=[dict(Key=k, Value=v) for k, v in settings.items()]) prefix = "github.com/777genius/plugin-kit-ai/" diff --git a/scripts/test_packed_ci.py b/scripts/test_packed_ci.py index 5c32fa3d0..fb7c7bda3 100644 --- a/scripts/test_packed_ci.py +++ b/scripts/test_packed_ci.py @@ -162,7 +162,7 @@ def get(name): return json.loads((root / name).read_text()) body = (root / 'npm-pair' / file).read_bytes() packs[product] = dict(file=file, size=len(body), sha256=p.digest(root / 'npm-pair' / file), integrity='sha512-' + p.base64.b64encode(p.hashlib.sha512(body).digest()).decode()) - pack_tools = {key: dict(value, version='go version go1.26.9 linux/amd64' if key == 'go' else p.VERSIONS[key]) for key, value in tools.items()} + pack_tools = {key: dict(value, version='go version go1.26.10 linux/amd64' if key == 'go' else p.VERSIONS[key]) for key, value in tools.items()} pack_tools['stager_node'] = pack_tools['node'] put('npm-pair/completion.json', dict(schema='dual-authoring-npm-completion/v1', identity=identity, status='CANDIDATE', authoring_mode=p.MODE, asset_scope='linux-amd64-pair', candidate_sha256=candidate_pin, packs=packs, tools=pack_tools, **claims)) diff --git a/sdk/go.mod b/sdk/go.mod index a05f97e3b..4572462b1 100644 --- a/sdk/go.mod +++ b/sdk/go.mod @@ -2,4 +2,4 @@ module github.com/777genius/plugin-kit-ai/sdk go 1.22 -toolchain go1.26.9 +toolchain go1.26.10 diff --git a/website/tools/lib/preflight.mjs b/website/tools/lib/preflight.mjs index 9f8a56468..978cbcdd1 100644 --- a/website/tools/lib/preflight.mjs +++ b/website/tools/lib/preflight.mjs @@ -24,8 +24,8 @@ export async function generationPrerequisites() { if (!process.env.GOWORK || !path.isAbsolute(process.env.GOWORK)) errors.push("Explicit absolute GOWORK required"); try { const version = await run("go", ["version"]); - if (!version.includes(" go1.26.9 ")) errors.push(`Go 1.26.9 required; found ${version.trim()}`); - } catch { errors.push("Missing Go 1.26.9 executable"); } + if (!version.includes(" go1.26.10 ")) errors.push(`Go 1.26.10 required; found ${version.trim()}`); + } catch { errors.push("Missing Go 1.26.10 executable"); } if (!process.env.GOMODCACHE) errors.push("Explicit existing GOMODCACHE required"); else { try { await fs.access(process.env.GOMODCACHE); } From 93613cc4ea2ad27cf4a46c9ce2d916635291858f Mon Sep 17 00:00:00 2001 From: iliya Date: Wed, 21 Oct 2026 18:41:22 +0300 Subject: [PATCH 6/6] fix(website): bump escaped Go version regex in site-consumer check The pin lives in a regex literal (/ go1\.26\.9 /) so the repo-wide 1.26.9 -> 1.26.10 replace missed it, and docs-check failed asserting the runner's go version. Align it with the bumped toolchain. --- website/tools/quality/test-site-consumer.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/tools/quality/test-site-consumer.mjs b/website/tools/quality/test-site-consumer.mjs index 042040259..d16eb88fe 100644 --- a/website/tools/quality/test-site-consumer.mjs +++ b/website/tools/quality/test-site-consumer.mjs @@ -13,7 +13,7 @@ for (const [key, value] of Object.entries({ GOPROXY: "off", GOSUMDB: "off", GOEN for (const key of ["HOME", "TMPDIR", "GOCACHE", "GOMODCACHE", "DOCS_TOOLS_ROOT"]) if (!path.isAbsolute(process.env[key] || "")) throw new Error(`Required integration needs private absolute ${key} (GOMODCACHE may be an existing read-only cache)`); if (process.env.GOFLAGS) throw new Error("Required integration needs empty GOFLAGS"); -assert.match(await run("go", ["version"]), / go1\.26\.9 /); +assert.match(await run("go", ["version"]), / go1\.26\.10 /); const directory = await fs.mkdtemp(path.join(os.tmpdir(), "docs-consumer-integration-")); console.log(`Integration evidence: ${directory}`); const source = path.join(directory, "source");