@pi-in-go/pigpen-ahp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CREDITS.md +27 -0
- package/LICENSE +23 -0
- package/README.md +148 -0
- package/extensions/ahp/access_options_test.go +116 -0
- package/extensions/ahp/extension.go +54 -0
- package/extensions/ahp/go.mod +12 -0
- package/extensions/ahp/go.sum +2 -0
- package/extensions/ahp/go.work +8 -0
- package/extensions/ahp/internal/channels/chat.go +110 -0
- package/extensions/ahp/internal/channels/root.go +32 -0
- package/extensions/ahp/internal/channels/session.go +128 -0
- package/extensions/ahp/internal/channels/session_test.go +108 -0
- package/extensions/ahp/internal/compose/compose.go +153 -0
- package/extensions/ahp/internal/compose/compose_test.go +120 -0
- package/extensions/ahp/internal/gaps/gaps_test.go +88 -0
- package/extensions/ahp/internal/host/handshake_test.go +206 -0
- package/extensions/ahp/internal/host/host.go +1305 -0
- package/extensions/ahp/internal/host/reconnect_test.go +197 -0
- package/extensions/ahp/internal/host/replaywindow_test.go +31 -0
- package/extensions/ahp/internal/host/schema_test.go +79 -0
- package/extensions/ahp/internal/host/store.go +291 -0
- package/extensions/ahp/internal/host/store_update_test.go +85 -0
- package/extensions/ahp/internal/host/subscriptions_test.go +160 -0
- package/extensions/ahp/internal/host/surface_test.go +95 -0
- package/extensions/ahp/internal/host/workarounds.go +458 -0
- package/extensions/ahp/internal/host/workarounds_test.go +96 -0
- package/extensions/ahp/internal/live/live.go +328 -0
- package/extensions/ahp/internal/live/live_test.go +91 -0
- package/extensions/ahp/internal/live/store.go +113 -0
- package/extensions/ahp/internal/mapper/activity.go +199 -0
- package/extensions/ahp/internal/mapper/activity_test.go +188 -0
- package/extensions/ahp/internal/mapper/bench_test.go +38 -0
- package/extensions/ahp/internal/mapper/event_mapper_test.go +380 -0
- package/extensions/ahp/internal/mapper/fixtures_test.go +387 -0
- package/extensions/ahp/internal/mapper/helpers_test.go +251 -0
- package/extensions/ahp/internal/mapper/js.go +131 -0
- package/extensions/ahp/internal/mapper/mapper.go +600 -0
- package/extensions/ahp/internal/mapper/message_input_test.go +196 -0
- package/extensions/ahp/internal/mapper/messageinput.go +272 -0
- package/extensions/ahp/internal/mapper/schema_helpers_test.go +5 -0
- package/extensions/ahp/internal/mapper/testdata/LICENSE-pi-ahp +21 -0
- package/extensions/ahp/internal/mapper/testdata/fixtures/abort.json +711 -0
- package/extensions/ahp/internal/mapper/testdata/fixtures/bash-long-output.json +1312 -0
- package/extensions/ahp/internal/mapper/testdata/fixtures/compaction.json +6285 -0
- package/extensions/ahp/internal/mapper/testdata/fixtures/parallel-tools.json +2622 -0
- package/extensions/ahp/internal/mapper/testdata/fixtures/plain-text.json +1856 -0
- package/extensions/ahp/internal/mapper/testdata/fixtures/single-tool.json +1128 -0
- package/extensions/ahp/internal/mapper/testdata/fixtures/steering.json +3926 -0
- package/extensions/ahp/internal/mapper/testdata/fixtures/tool-bash.json +2372 -0
- package/extensions/ahp/internal/mapper/testdata/fixtures/tool-edit.json +3983 -0
- package/extensions/ahp/internal/mapper/testdata/fixtures/tool-error.json +2850 -0
- package/extensions/ahp/internal/mapper/testdata/fixtures/tool-find.json +1162 -0
- package/extensions/ahp/internal/mapper/testdata/fixtures/tool-grep.json +2783 -0
- package/extensions/ahp/internal/mapper/testdata/fixtures/tool-loop.json +1693 -0
- package/extensions/ahp/internal/mapper/testdata/fixtures/tool-ls.json +2427 -0
- package/extensions/ahp/internal/mapper/testdata/fixtures/tool-write.json +1271 -0
- package/extensions/ahp/internal/mapper/title.go +34 -0
- package/extensions/ahp/internal/mapper/usermsg.go +87 -0
- package/extensions/ahp/internal/pi/activeturn_test.go +296 -0
- package/extensions/ahp/internal/pi/backend.go +64 -0
- package/extensions/ahp/internal/pi/catalogue.go +370 -0
- package/extensions/ahp/internal/pi/catalogue_test.go +271 -0
- package/extensions/ahp/internal/pi/chatdriver.go +533 -0
- package/extensions/ahp/internal/pi/chatdriver_test.go +416 -0
- package/extensions/ahp/internal/pi/clientactions.go +212 -0
- package/extensions/ahp/internal/pi/clientactions_test.go +273 -0
- package/extensions/ahp/internal/pi/completions.go +230 -0
- package/extensions/ahp/internal/pi/completions_test.go +272 -0
- package/extensions/ahp/internal/pi/config_test.go +269 -0
- package/extensions/ahp/internal/pi/deletesession.go +69 -0
- package/extensions/ahp/internal/pi/deletesession_test.go +153 -0
- package/extensions/ahp/internal/pi/disposal_test.go +362 -0
- package/extensions/ahp/internal/pi/fixture_test.go +308 -0
- package/extensions/ahp/internal/pi/foreign_test.go +122 -0
- package/extensions/ahp/internal/pi/harness_test.go +83 -0
- package/extensions/ahp/internal/pi/history.go +269 -0
- package/extensions/ahp/internal/pi/hydrated_test.go +171 -0
- package/extensions/ahp/internal/pi/hydratedlifecycle_test.go +196 -0
- package/extensions/ahp/internal/pi/hydration_test.go +209 -0
- package/extensions/ahp/internal/pi/hydrator.go +212 -0
- package/extensions/ahp/internal/pi/imageinput.go +224 -0
- package/extensions/ahp/internal/pi/imageinput_test.go +57 -0
- package/extensions/ahp/internal/pi/lifecycle_test.go +381 -0
- package/extensions/ahp/internal/pi/models.go +212 -0
- package/extensions/ahp/internal/pi/models_test.go +128 -0
- package/extensions/ahp/internal/pi/paging.go +95 -0
- package/extensions/ahp/internal/pi/pagingtruncate_test.go +323 -0
- package/extensions/ahp/internal/pi/projecttrust.go +222 -0
- package/extensions/ahp/internal/pi/registry.go +924 -0
- package/extensions/ahp/internal/pi/restart_test.go +185 -0
- package/extensions/ahp/internal/pi/services.go +70 -0
- package/extensions/ahp/internal/pi/sessionconfig.go +64 -0
- package/extensions/ahp/internal/pi/sessionfiles_test.go +74 -0
- package/extensions/ahp/internal/pi/sessionstore.go +83 -0
- package/extensions/ahp/internal/pi/summary_test.go +426 -0
- package/extensions/ahp/internal/pi/workarounds_wire_test.go +208 -0
- package/extensions/ahp/internal/pisession/fromentries_test.go +32 -0
- package/extensions/ahp/internal/pisession/json.go +31 -0
- package/extensions/ahp/internal/pisession/pisession.go +580 -0
- package/extensions/ahp/internal/settings/access.go +63 -0
- package/extensions/ahp/internal/settings/access_test.go +52 -0
- package/extensions/ahp/internal/settings/settings.go +117 -0
- package/extensions/ahp/internal/settings/settings_test.go +104 -0
- package/extensions/ahp/internal/svc/etag_other.go +15 -0
- package/extensions/ahp/internal/svc/etag_unix.go +34 -0
- package/extensions/ahp/internal/svc/glob.go +197 -0
- package/extensions/ahp/internal/svc/mime.go +37 -0
- package/extensions/ahp/internal/svc/paths.go +108 -0
- package/extensions/ahp/internal/svc/pty.go +64 -0
- package/extensions/ahp/internal/svc/pty_darwin.go +42 -0
- package/extensions/ahp/internal/svc/pty_linux.go +36 -0
- package/extensions/ahp/internal/svc/pty_other.go +9 -0
- package/extensions/ahp/internal/svc/pty_test.go +114 -0
- package/extensions/ahp/internal/svc/pty_unix.go +147 -0
- package/extensions/ahp/internal/svc/resource.go +495 -0
- package/extensions/ahp/internal/svc/resource_test.go +501 -0
- package/extensions/ahp/internal/svc/stat_bsd.go +9 -0
- package/extensions/ahp/internal/svc/stat_linux.go +9 -0
- package/extensions/ahp/internal/svc/terminal.go +454 -0
- package/extensions/ahp/internal/svc/terminal_test.go +512 -0
- package/extensions/ahp/internal/svc/watch.go +590 -0
- package/extensions/ahp/internal/svc/watch_test.go +627 -0
- package/extensions/ahp/internal/svc/watchevents_test.go +452 -0
- package/extensions/ahp/internal/svc/watchpolicy.go +81 -0
- package/extensions/ahp/internal/svc/watchpolicy_test.go +151 -0
- package/extensions/ahp/internal/svc/watchracy_test.go +61 -0
- package/extensions/ahp/internal/testkit/schema/LICENSE-agent-host-protocol +21 -0
- package/extensions/ahp/internal/testkit/schema/actions.schema.json +9208 -0
- package/extensions/ahp/internal/testkit/schema/commands.schema.json +10862 -0
- package/extensions/ahp/internal/testkit/schema/errors.schema.json +10928 -0
- package/extensions/ahp/internal/testkit/schema/notifications.schema.json +6667 -0
- package/extensions/ahp/internal/testkit/schema/state.schema.json +6392 -0
- package/extensions/ahp/internal/testkit/schema.go +360 -0
- package/extensions/ahp/internal/testkit/testkit.go +367 -0
- package/extensions/ahp/internal/twin/twin.go +27 -0
- package/extensions/ahp/internal/wire/dispatchable.go +106 -0
- package/extensions/ahp/internal/wire/dispatchable_list.go +15 -0
- package/extensions/ahp/internal/wire/helpers_test.go +5 -0
- package/extensions/ahp/internal/wire/wire.go +218 -0
- package/extensions/ahp/internal/wire/wire_test.go +123 -0
- package/extensions/ahp/internal/ws/helpers_test.go +7 -0
- package/extensions/ahp/internal/ws/vscode_test.go +198 -0
- package/extensions/ahp/internal/ws/ws.go +674 -0
- package/extensions/ahp/internal/ws/ws_test.go +324 -0
- package/extensions/ahp/realpig_test.go +589 -0
- package/extensions/ahp/runtime.go +311 -0
- package/extensions/ahp/runtime_test.go +110 -0
- package/extensions/ahp/testdata/upstream-tests.json +3833 -0
- package/extensions/ahp/third_party/agent-host-protocol-go/LICENSE +21 -0
- package/extensions/ahp/third_party/agent-host-protocol-go/NOTICE-PIGPEN.md +18 -0
- package/extensions/ahp/third_party/agent-host-protocol-go/ahp/client.go +1011 -0
- package/extensions/ahp/third_party/agent-host-protocol-go/ahp/error.go +111 -0
- package/extensions/ahp/third_party/agent-host-protocol-go/ahp/multi_host_state_mirror.go +239 -0
- package/extensions/ahp/third_party/agent-host-protocol-go/ahp/reducers.go +1939 -0
- package/extensions/ahp/third_party/agent-host-protocol-go/ahp/transport.go +176 -0
- package/extensions/ahp/third_party/agent-host-protocol-go/ahptypes/actions.generated.go +2447 -0
- package/extensions/ahp/third_party/agent-host-protocol-go/ahptypes/commands.generated.go +1546 -0
- package/extensions/ahp/third_party/agent-host-protocol-go/ahptypes/common.go +205 -0
- package/extensions/ahp/third_party/agent-host-protocol-go/ahptypes/errors.generated.go +65 -0
- package/extensions/ahp/third_party/agent-host-protocol-go/ahptypes/messages.generated.go +138 -0
- package/extensions/ahp/third_party/agent-host-protocol-go/ahptypes/notifications.generated.go +264 -0
- package/extensions/ahp/third_party/agent-host-protocol-go/ahptypes/state.generated.go +6171 -0
- package/extensions/ahp/third_party/agent-host-protocol-go/ahptypes/version.generated.go +31 -0
- package/extensions/ahp/third_party/agent-host-protocol-go/go.mod +3 -0
- package/extensions/ahp/twins_test.go +91 -0
- package/package.json +40 -0
- package/proof/PORT.md +121 -0
- package/proof/mutations.json +152 -0
- package/proof/oracle/LICENSE +21 -0
- package/proof/oracle/README.md +120 -0
- package/proof/oracle/UPSTREAM.md +7 -0
- package/proof/oracle/package.json +68 -0
- package/proof/oracle/src/bin/cli.ts +66 -0
- package/proof/oracle/src/bin/tunnel.ts +128 -0
- package/proof/oracle/src/channels/chat.ts +134 -0
- package/proof/oracle/src/channels/root.ts +39 -0
- package/proof/oracle/src/channels/session.ts +118 -0
- package/proof/oracle/src/channels/terminal.ts +11 -0
- package/proof/oracle/src/core/channels.ts +108 -0
- package/proof/oracle/src/core/client-workarounds.ts +358 -0
- package/proof/oracle/src/core/connection.ts +41 -0
- package/proof/oracle/src/core/host.ts +882 -0
- package/proof/oracle/src/core/sequencer.ts +75 -0
- package/proof/oracle/src/core/state-store.ts +162 -0
- package/proof/oracle/src/core/uri.ts +25 -0
- package/proof/oracle/src/host/direct-settings.ts +110 -0
- package/proof/oracle/src/host/pi-host.ts +220 -0
- package/proof/oracle/src/host/serve.ts +71 -0
- package/proof/oracle/src/host/terminal-service.ts +346 -0
- package/proof/oracle/src/pi/activity.ts +171 -0
- package/proof/oracle/src/pi/changeset-service.ts +646 -0
- package/proof/oracle/src/pi/changeset-uri.ts +64 -0
- package/proof/oracle/src/pi/chat-driver.ts +529 -0
- package/proof/oracle/src/pi/completions.ts +160 -0
- package/proof/oracle/src/pi/delete-session.ts +53 -0
- package/proof/oracle/src/pi/event-mapper.ts +648 -0
- package/proof/oracle/src/pi/git-changes.ts +605 -0
- package/proof/oracle/src/pi/history.ts +305 -0
- package/proof/oracle/src/pi/image-input.ts +56 -0
- package/proof/oracle/src/pi/image-mime.ts +8 -0
- package/proof/oracle/src/pi/in-process-backend.ts +155 -0
- package/proof/oracle/src/pi/message-input.ts +212 -0
- package/proof/oracle/src/pi/models.ts +124 -0
- package/proof/oracle/src/pi/project-trust.ts +66 -0
- package/proof/oracle/src/pi/provider.ts +2 -0
- package/proof/oracle/src/pi/resource-paths.ts +80 -0
- package/proof/oracle/src/pi/resource-service.ts +356 -0
- package/proof/oracle/src/pi/resource-watch-policy.ts +35 -0
- package/proof/oracle/src/pi/resource-watch.ts +357 -0
- package/proof/oracle/src/pi/session-catalogue.ts +318 -0
- package/proof/oracle/src/pi/session-config.ts +84 -0
- package/proof/oracle/src/pi/session-history.ts +75 -0
- package/proof/oracle/src/pi/session-hydrator.ts +219 -0
- package/proof/oracle/src/pi/session-registry.ts +815 -0
- package/proof/oracle/src/pi/session-storage.ts +29 -0
- package/proof/oracle/src/pi/session-title.ts +18 -0
- package/proof/oracle/src/pi/turn-paging.ts +94 -0
- package/proof/oracle/src/pi/user-message.ts +66 -0
- package/proof/oracle/src/protocol/errors.ts +44 -0
- package/proof/oracle/src/protocol/jsonrpc.ts +89 -0
- package/proof/oracle/src/protocol/version.ts +39 -0
- package/proof/oracle/src/transport/websocket.ts +136 -0
- package/proof/oracle/src/tunnel/devtunnel.ts +293 -0
- package/proof/oracle/src/tunnel/discovery.ts +37 -0
- package/proof/oracle/test/active-turn-reconnect.test.ts +274 -0
- package/proof/oracle/test/activity.test.ts +171 -0
- package/proof/oracle/test/changeset-lifecycle.test.serial.ts +303 -0
- package/proof/oracle/test/changeset-uri.test.ts +37 -0
- package/proof/oracle/test/changeset.test.serial.ts +487 -0
- package/proof/oracle/test/chat-driver.test.ts +691 -0
- package/proof/oracle/test/client-actions.test.ts +409 -0
- package/proof/oracle/test/client-workarounds.test.ts +320 -0
- package/proof/oracle/test/completions.test.ts +323 -0
- package/proof/oracle/test/delete-session.test.ts +142 -0
- package/proof/oracle/test/direct-settings.test.ts +81 -0
- package/proof/oracle/test/event-mapper.test.ts +619 -0
- package/proof/oracle/test/fetch-turns.test.ts +207 -0
- package/proof/oracle/test/fixtures/abort.json +711 -0
- package/proof/oracle/test/fixtures/bash-long-output.json +1312 -0
- package/proof/oracle/test/fixtures/compaction.json +6285 -0
- package/proof/oracle/test/fixtures/parallel-tools.json +2622 -0
- package/proof/oracle/test/fixtures/plain-text.json +1856 -0
- package/proof/oracle/test/fixtures/single-tool.json +1128 -0
- package/proof/oracle/test/fixtures/steering.json +3926 -0
- package/proof/oracle/test/fixtures/tool-bash.json +2372 -0
- package/proof/oracle/test/fixtures/tool-edit.json +3983 -0
- package/proof/oracle/test/fixtures/tool-error.json +2850 -0
- package/proof/oracle/test/fixtures/tool-find.json +1162 -0
- package/proof/oracle/test/fixtures/tool-grep.json +2783 -0
- package/proof/oracle/test/fixtures/tool-loop.json +1693 -0
- package/proof/oracle/test/fixtures/tool-ls.json +2427 -0
- package/proof/oracle/test/fixtures/tool-write.json +1271 -0
- package/proof/oracle/test/handshake.test.ts +275 -0
- package/proof/oracle/test/harness.ts +153 -0
- package/proof/oracle/test/hydrated-session-lifecycle.test.ts +211 -0
- package/proof/oracle/test/image-input.test.ts +28 -0
- package/proof/oracle/test/image-session.test.ts +69 -0
- package/proof/oracle/test/live-turn.test.ts +304 -0
- package/proof/oracle/test/mapper-fixtures.test.ts +293 -0
- package/proof/oracle/test/message-input.test.ts +181 -0
- package/proof/oracle/test/model-discovery.test.ts +170 -0
- package/proof/oracle/test/models.test.ts +109 -0
- package/proof/oracle/test/pi-host.test.ts +91 -0
- package/proof/oracle/test/pi-replay.test.ts +141 -0
- package/proof/oracle/test/project-trust.test.ts +125 -0
- package/proof/oracle/test/protocol-surface.test.ts +121 -0
- package/proof/oracle/test/pty.test.ts +100 -0
- package/proof/oracle/test/reconnect.test.ts +389 -0
- package/proof/oracle/test/resource-watch-policy.test.ts +78 -0
- package/proof/oracle/test/resource-watch.test.serial.ts +536 -0
- package/proof/oracle/test/resource.test.ts +499 -0
- package/proof/oracle/test/schema.test.ts +88 -0
- package/proof/oracle/test/session-catalogue.test.ts +314 -0
- package/proof/oracle/test/session-config.test.ts +224 -0
- package/proof/oracle/test/session-disposal.test.ts +364 -0
- package/proof/oracle/test/session-hydration.test.ts +194 -0
- package/proof/oracle/test/session-lifecycle.test.ts +416 -0
- package/proof/oracle/test/session-storage.test.serial.ts +32 -0
- package/proof/oracle/test/session-summary.test.ts +418 -0
- package/proof/oracle/test/subscriptions.test.ts +198 -0
- package/proof/oracle/test/support/assertions.ts +32 -0
- package/proof/oracle/test/support/async.ts +26 -0
- package/proof/oracle/test/support/hydrated-session.ts +205 -0
- package/proof/oracle/test/support/images.ts +8 -0
- package/proof/oracle/test/support/recorded-fixtures.ts +60 -0
- package/proof/oracle/test/support/recorded-scenarios.ts +145 -0
- package/proof/oracle/test/support/replay.ts +194 -0
- package/proof/oracle/test/support/schema.ts +221 -0
- package/proof/oracle/test/support/session-files.ts +12 -0
- package/proof/oracle/test/support/session-storage.ts +22 -0
- package/proof/oracle/test/support/upstream.ts +25 -0
- package/proof/oracle/test/support/watch-events.ts +108 -0
- package/proof/oracle/test/terminal-service.test.ts +495 -0
- package/proof/oracle/test/truncate.test.ts +230 -0
- package/proof/oracle/test/tunnel.test.ts +258 -0
- package/proof/oracle/test/upstream-workarounds.test.ts +37 -0
- package/proof/oracle/test/uri.test.ts +24 -0
- package/proof/oracle/test/watch-events.test.ts +118 -0
- package/proof/oracle/tsconfig.json +32 -0
- package/proof/proof-piglet/piglet.yaml +18 -0
- package/proof/tools/fakellm/go.mod +3 -0
- package/proof/tools/fakellm/main.go +109 -0
- package/proof/tools/gen-dispatchable.py +30 -0
- package/provenance.json +28 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
package channels_test
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"encoding/json"
|
|
5
|
+
"reflect"
|
|
6
|
+
"testing"
|
|
7
|
+
|
|
8
|
+
"github.com/microsoft/agent-host-protocol/clients/go/ahptypes"
|
|
9
|
+
|
|
10
|
+
"github.com/MichaelKinsy/pigpen/ahp/internal/channels"
|
|
11
|
+
"github.com/MichaelKinsy/pigpen/ahp/internal/twin"
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
// Twins of the "session chat aggregation" describe of upstream test/session-summary.test.ts.
|
|
15
|
+
|
|
16
|
+
const (
|
|
17
|
+
start = "2025-01-01T00:00:00.000Z"
|
|
18
|
+
end = "2025-01-01T00:00:01.000Z"
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
func summary(resource string, status ahptypes.SessionStatus, modifiedAt string) ahptypes.ChatSummary {
|
|
22
|
+
return ahptypes.ChatSummary{Resource: resource, Title: resource, Status: status, ModifiedAt: modifiedAt}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
func withActivity(s ahptypes.ChatSummary, activity string) ahptypes.ChatSummary {
|
|
26
|
+
s.Activity = &activity
|
|
27
|
+
return s
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
func sessionState(chats ...ahptypes.ChatSummary) *ahptypes.SessionState {
|
|
31
|
+
return &ahptypes.SessionState{
|
|
32
|
+
Provider: "pi", Title: "Session", Status: ahptypes.SessionStatusIdle, Lifecycle: ahptypes.SessionLifecycleReady,
|
|
33
|
+
ActiveClients: []ahptypes.SessionActiveClient{}, Chats: chats,
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
func sp(s string) *string { return &s }
|
|
38
|
+
|
|
39
|
+
func check(t *testing.T, got channels.SessionChatAggregate, status ahptypes.SessionStatus, activity *string, modifiedAt string) {
|
|
40
|
+
t.Helper()
|
|
41
|
+
want := channels.SessionChatAggregate{Status: status, Activity: activity, ModifiedAt: modifiedAt}
|
|
42
|
+
if !reflect.DeepEqual(got, want) {
|
|
43
|
+
gj, _ := json.Marshal(got)
|
|
44
|
+
wj, _ := json.Marshal(want)
|
|
45
|
+
t.Fatalf("aggregate = %s, want %s", gj, wj)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
func TestSessionChatAggregation(t *testing.T) {
|
|
50
|
+
twin.Run(t, "session-summary", "passes through single-chat activity but preserves session-owned and unknown flags", func(t *testing.T) {
|
|
51
|
+
flags := ahptypes.SessionStatusIsRead | ahptypes.SessionStatusIsArchived | (1 << 10)
|
|
52
|
+
for _, status := range []ahptypes.SessionStatus{
|
|
53
|
+
ahptypes.SessionStatusIdle, ahptypes.SessionStatusInProgress, ahptypes.SessionStatusError, ahptypes.SessionStatusInputNeeded,
|
|
54
|
+
} {
|
|
55
|
+
state := sessionState(withActivity(summary("chat", status, start), "Working"))
|
|
56
|
+
state.Status = ahptypes.SessionStatusIdle | flags
|
|
57
|
+
before, _ := json.Marshal(state)
|
|
58
|
+
check(t, channels.AggregateSessionChats(state), status|flags, sp("Working"), start)
|
|
59
|
+
after, _ := json.Marshal(state)
|
|
60
|
+
if string(before) != string(after) {
|
|
61
|
+
t.Fatal("projection must not mutate source state")
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
state := sessionState(summary("chat", ahptypes.SessionStatusIdle|ahptypes.SessionStatusIsRead, start))
|
|
65
|
+
if got := channels.AggregateSessionChats(state).Status; got != ahptypes.SessionStatusIdle {
|
|
66
|
+
t.Fatalf("chat flags must not leak into the session; status = %d", got)
|
|
67
|
+
}
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
twin.Run(t, "session-summary", "uses default chat activity but the latest timestamp, comparing instants rather than strings", func(t *testing.T) {
|
|
71
|
+
recent := "2024-12-31T19:01:00-05:00"
|
|
72
|
+
state := sessionState(
|
|
73
|
+
withActivity(summary("default", ahptypes.SessionStatusIdle, start), "Default"),
|
|
74
|
+
withActivity(summary("recent", ahptypes.SessionStatusInProgress, recent), "Recent"),
|
|
75
|
+
)
|
|
76
|
+
state.DefaultChat = sp("default")
|
|
77
|
+
check(t, channels.AggregateSessionChats(state), ahptypes.SessionStatusIdle, sp("Default"), recent)
|
|
78
|
+
for _, defaultChat := range []*string{nil, sp("missing")} {
|
|
79
|
+
state.DefaultChat = defaultChat
|
|
80
|
+
check(t, channels.AggregateSessionChats(state), ahptypes.SessionStatusInProgress, sp("Recent"), recent)
|
|
81
|
+
}
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
twin.Run(t, "session-summary", "promotes Error and InputNeeded, preferring the most recent blocker of the winning kind", func(t *testing.T) {
|
|
85
|
+
state := sessionState(summary("default", ahptypes.SessionStatusIdle, start), withActivity(summary("error", ahptypes.SessionStatusError, start), "Error"))
|
|
86
|
+
state.DefaultChat = sp("default")
|
|
87
|
+
check(t, channels.AggregateSessionChats(state), ahptypes.SessionStatusError, sp("Error"), start)
|
|
88
|
+
state.Chats = append(state.Chats,
|
|
89
|
+
summary("old-input", ahptypes.SessionStatusInputNeeded, start),
|
|
90
|
+
withActivity(summary("input", ahptypes.SessionStatusInputNeeded, end), "Approval"))
|
|
91
|
+
check(t, channels.AggregateSessionChats(state), ahptypes.SessionStatusInputNeeded, sp("Approval"), end)
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
twin.Run(t, "session-summary", "handles an empty catalogue and chooses stable ties and valid timestamps", func(t *testing.T) {
|
|
95
|
+
empty := sessionState()
|
|
96
|
+
empty.Activity = sp("Starting")
|
|
97
|
+
check(t, channels.AggregateSessionChats(empty), ahptypes.SessionStatusIdle, sp("Starting"), "")
|
|
98
|
+
if got := channels.SessionSummaryOf("session", start, empty, nil).ModifiedAt; got != start {
|
|
99
|
+
t.Fatalf("modifiedAt = %s", got)
|
|
100
|
+
}
|
|
101
|
+
state := sessionState(
|
|
102
|
+
withActivity(summary("invalid", ahptypes.SessionStatusIdle, "invalid"), "Invalid"),
|
|
103
|
+
withActivity(summary("first", ahptypes.SessionStatusInProgress, start), "First"),
|
|
104
|
+
withActivity(summary("tie", ahptypes.SessionStatusIdle, start), "Tie"),
|
|
105
|
+
)
|
|
106
|
+
check(t, channels.AggregateSessionChats(state), ahptypes.SessionStatusInProgress, sp("First"), start)
|
|
107
|
+
})
|
|
108
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
// Package compose is the composition root (port of src/host/pi-host.ts createPiHost): it builds
|
|
2
|
+
// a host and wires the independently tested services to it. Nothing here opens a socket; the
|
|
3
|
+
// caller decides whether and where to listen.
|
|
4
|
+
package compose
|
|
5
|
+
|
|
6
|
+
import (
|
|
7
|
+
"errors"
|
|
8
|
+
"sync"
|
|
9
|
+
|
|
10
|
+
ahptypes "github.com/microsoft/agent-host-protocol/clients/go/ahptypes"
|
|
11
|
+
|
|
12
|
+
"github.com/MichaelKinsy/pigpen/ahp/internal/host"
|
|
13
|
+
"github.com/MichaelKinsy/pigpen/ahp/internal/pi"
|
|
14
|
+
"github.com/MichaelKinsy/pigpen/ahp/internal/svc"
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
// MentionTrigger is the character that starts a file mention in a message.
|
|
18
|
+
const MentionTrigger = "@"
|
|
19
|
+
|
|
20
|
+
// FilesystemOptions opts a client into browsing and editing files (resources and watches). The
|
|
21
|
+
// remote filesystem is never exposed unless this is given: Roots confine every path, and
|
|
22
|
+
// Unrestricted is the explicit way to drop the confinement.
|
|
23
|
+
type FilesystemOptions struct {
|
|
24
|
+
Roots []string
|
|
25
|
+
Unrestricted bool
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// TerminalOptions opts a client into shells on this machine.
|
|
29
|
+
type TerminalOptions struct {
|
|
30
|
+
Shell string
|
|
31
|
+
Spawn svc.PtySpawner // nil = the real PTY
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Options configure Build.
|
|
35
|
+
type Options struct {
|
|
36
|
+
ServerInfo *ahptypes.Implementation
|
|
37
|
+
WorkingDirectory string
|
|
38
|
+
// Models lists the models offered to clients; nil or empty means none.
|
|
39
|
+
Models func() []pi.Model
|
|
40
|
+
// SessionRoot is where Pi's session files live, for the catalogue and hydration.
|
|
41
|
+
SessionRoot string
|
|
42
|
+
// CreateSessionManager is the storage for sessions created through the host.
|
|
43
|
+
CreateSessionManager pi.SessionManagerFactory
|
|
44
|
+
CreateBackend pi.BackendFactory
|
|
45
|
+
DefaultSelection func() *ahptypes.ModelSelection
|
|
46
|
+
DeleteFile func(path string) (pi.SessionFileDeletionResult, error)
|
|
47
|
+
// WrapStore replaces the store of a session hydrated from disk (see pi.HydratorOptions).
|
|
48
|
+
WrapStore func(sessionID string, opened pi.SessionStore) pi.SessionStore
|
|
49
|
+
// AdoptForeignTurns mirrors prompts typed into the session locally into its chat.
|
|
50
|
+
AdoptForeignTurns bool
|
|
51
|
+
AgentDir string
|
|
52
|
+
ProjectTrustPolicy pi.ProjectTrustPolicy
|
|
53
|
+
Log func(format string, args ...any)
|
|
54
|
+
|
|
55
|
+
// Filesystem and Terminals are nil unless the user opted in.
|
|
56
|
+
Filesystem *FilesystemOptions
|
|
57
|
+
Terminals *TerminalOptions
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Built is the composed host and the services a caller may need to reach or shut down.
|
|
61
|
+
type Built struct {
|
|
62
|
+
Host *host.Host
|
|
63
|
+
Sessions *pi.Services
|
|
64
|
+
Resources *svc.ResourceService // nil unless Filesystem was given
|
|
65
|
+
Watches *svc.WatchService // nil unless Filesystem was given
|
|
66
|
+
Terminals *svc.TerminalService // nil unless Terminals was given
|
|
67
|
+
|
|
68
|
+
closeOnce sync.Once
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Build composes the host.
|
|
72
|
+
func Build(opts Options) (*Built, error) {
|
|
73
|
+
if opts.CreateBackend == nil {
|
|
74
|
+
return nil, errors.New("compose: CreateBackend is required")
|
|
75
|
+
}
|
|
76
|
+
if opts.CreateSessionManager == nil {
|
|
77
|
+
opts.CreateSessionManager = pi.InMemoryStorage
|
|
78
|
+
}
|
|
79
|
+
logf := func(format string, args ...any) {
|
|
80
|
+
if opts.Log != nil {
|
|
81
|
+
opts.Log(format, args...)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
h := host.New(host.Options{
|
|
85
|
+
ServerInfo: opts.ServerInfo, CompletionTriggerCharacters: []string{MentionTrigger},
|
|
86
|
+
Log: func(message string) { logf("%s", message) },
|
|
87
|
+
})
|
|
88
|
+
var models []pi.Model
|
|
89
|
+
if opts.Models != nil {
|
|
90
|
+
models = opts.Models()
|
|
91
|
+
}
|
|
92
|
+
h.InstallRootChannel([]ahptypes.AgentInfo{pi.BuildAgentInfo(models)})
|
|
93
|
+
|
|
94
|
+
deleteFile := opts.DeleteFile
|
|
95
|
+
if deleteFile == nil {
|
|
96
|
+
deleteFile = pi.FileDeleter
|
|
97
|
+
}
|
|
98
|
+
sessions := pi.NewServices(pi.ServicesOptions{
|
|
99
|
+
Host: h, SessionRoot: opts.SessionRoot, DefaultWorkingDirectory: opts.WorkingDirectory,
|
|
100
|
+
CreateBackend: opts.CreateBackend, CreateSessionManager: opts.CreateSessionManager,
|
|
101
|
+
DefaultSelection: opts.DefaultSelection, DeleteFile: deleteFile, WrapStore: opts.WrapStore, AdoptForeignTurns: opts.AdoptForeignTurns, Log: logf,
|
|
102
|
+
})
|
|
103
|
+
built := &Built{Host: h, Sessions: sessions}
|
|
104
|
+
|
|
105
|
+
caps := sessions.Capabilities()
|
|
106
|
+
caps.SessionConfig = pi.NewSessionConfigService(pi.SessionConfigOptions{
|
|
107
|
+
DefaultWorkingDirectory: opts.WorkingDirectory, ProjectTrustPolicy: opts.ProjectTrustPolicy, AgentDir: opts.AgentDir,
|
|
108
|
+
})
|
|
109
|
+
caps.Completions = pi.NewCompletionService(pi.CompletionServiceOptions{WorkingDirectoryFor: func(chat string) string {
|
|
110
|
+
if s, ok := sessions.Registry.GetByChat(chat); ok {
|
|
111
|
+
return s.WorkingDirectory
|
|
112
|
+
}
|
|
113
|
+
return ""
|
|
114
|
+
}})
|
|
115
|
+
|
|
116
|
+
if fs := opts.Filesystem; fs != nil {
|
|
117
|
+
if len(fs.Roots) == 0 && !fs.Unrestricted {
|
|
118
|
+
return nil, errors.New("compose: filesystem access needs roots, or Unrestricted set explicitly")
|
|
119
|
+
}
|
|
120
|
+
var roots []string
|
|
121
|
+
if !fs.Unrestricted {
|
|
122
|
+
roots = fs.Roots
|
|
123
|
+
}
|
|
124
|
+
policy, err := svc.NewPathPolicy(roots...)
|
|
125
|
+
if err != nil {
|
|
126
|
+
return nil, err
|
|
127
|
+
}
|
|
128
|
+
built.Resources = svc.NewResourceService(svc.ResourceOptions{Paths: policy})
|
|
129
|
+
built.Watches = svc.NewWatchService(h, svc.WatchOptions{Paths: policy, Log: func(m string) { logf("%s", m) }})
|
|
130
|
+
caps.Resources = built.Resources
|
|
131
|
+
caps.ResourceWatches = built.Watches
|
|
132
|
+
}
|
|
133
|
+
if t := opts.Terminals; t != nil {
|
|
134
|
+
built.Terminals = svc.NewTerminalService(h, svc.TerminalOptions{
|
|
135
|
+
DefaultWorkingDirectory: opts.WorkingDirectory, Shell: t.Shell, Spawn: t.Spawn, Log: func(m string) { logf("%s", m) },
|
|
136
|
+
})
|
|
137
|
+
caps.Terminals = built.Terminals
|
|
138
|
+
}
|
|
139
|
+
h.Serve(caps)
|
|
140
|
+
return built, nil
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Close shuts the optional services down: terminals are killed, watches released.
|
|
144
|
+
func (b *Built) Close() {
|
|
145
|
+
b.closeOnce.Do(func() {
|
|
146
|
+
if b.Terminals != nil {
|
|
147
|
+
b.Terminals.Shutdown()
|
|
148
|
+
}
|
|
149
|
+
if b.Watches != nil {
|
|
150
|
+
<-b.Watches.Dispose()
|
|
151
|
+
}
|
|
152
|
+
})
|
|
153
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
package compose
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"context"
|
|
5
|
+
"encoding/json"
|
|
6
|
+
"os"
|
|
7
|
+
"path/filepath"
|
|
8
|
+
"reflect"
|
|
9
|
+
"testing"
|
|
10
|
+
|
|
11
|
+
ahptypes "github.com/microsoft/agent-host-protocol/clients/go/ahptypes"
|
|
12
|
+
|
|
13
|
+
"github.com/MichaelKinsy/pigpen/ahp/internal/mapper"
|
|
14
|
+
"github.com/MichaelKinsy/pigpen/ahp/internal/pi"
|
|
15
|
+
"github.com/MichaelKinsy/pigpen/ahp/internal/testkit"
|
|
16
|
+
"github.com/MichaelKinsy/pigpen/ahp/internal/twin"
|
|
17
|
+
"github.com/MichaelKinsy/pigpen/ahp/internal/wire"
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
type idleBackend struct{}
|
|
21
|
+
|
|
22
|
+
func (idleBackend) Subscribe(func(mapper.Event)) func() { return func() {} }
|
|
23
|
+
func (idleBackend) Prompt(context.Context, string, []mapper.Image) error { return nil }
|
|
24
|
+
func (idleBackend) Steer(context.Context, string, []mapper.Image) error { return nil }
|
|
25
|
+
func (idleBackend) Abort(context.Context) error { return nil }
|
|
26
|
+
|
|
27
|
+
func TestComposition(t *testing.T) {
|
|
28
|
+
// Twin of upstream test/pi-host.test.ts. Upstream's resource read works without roots; here the
|
|
29
|
+
// unrestricted filesystem must be asked for explicitly (see PORT.md).
|
|
30
|
+
twin.Run(t, "pi-host", "wires product services through createPiHost", func(t *testing.T) {
|
|
31
|
+
workspace, _ := filepath.EvalSymlinks(t.TempDir())
|
|
32
|
+
sessionRoot := t.TempDir()
|
|
33
|
+
if err := os.WriteFile(filepath.Join(workspace, "notes.md"), []byte("# Notes\n"), 0o644); err != nil {
|
|
34
|
+
t.Fatal(err)
|
|
35
|
+
}
|
|
36
|
+
built, err := Build(Options{
|
|
37
|
+
ServerInfo: &ahptypes.Implementation{Name: "pi-ahp"}, WorkingDirectory: workspace, SessionRoot: sessionRoot,
|
|
38
|
+
CreateSessionManager: pi.PersistentStorage(sessionRoot),
|
|
39
|
+
CreateBackend: func(*pi.LiveSession) (pi.Backend, error) { return idleBackend{}, nil },
|
|
40
|
+
DeleteFile: func(string) (pi.SessionFileDeletionResult, error) { return pi.SessionFileDeletionResult{OK: true}, nil },
|
|
41
|
+
Filesystem: &FilesystemOptions{Unrestricted: true},
|
|
42
|
+
Terminals: &TerminalOptions{},
|
|
43
|
+
})
|
|
44
|
+
if err != nil {
|
|
45
|
+
t.Fatal(err)
|
|
46
|
+
}
|
|
47
|
+
defer built.Close()
|
|
48
|
+
c := testkit.Connect(t, built.Host)
|
|
49
|
+
defer c.Close()
|
|
50
|
+
init := c.Initialize("composition-client", map[string]any{"initialSubscriptions": []string{wire.RootChannel}})
|
|
51
|
+
if !reflect.DeepEqual(init.CompletionTriggerCharacters, []string{"@"}) {
|
|
52
|
+
t.Fatalf("trigger characters %v", init.CompletionTriggerCharacters)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
var resource ahptypes.ResourceReadResult
|
|
56
|
+
c.Decode(c.Must("resourceRead", map[string]any{"channel": wire.RootChannel, "uri": wire.PathToFileURI(filepath.Join(workspace, "notes.md"))}), &resource)
|
|
57
|
+
if resource.Data != "# Notes\n" {
|
|
58
|
+
t.Fatalf("%+v", resource)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
var config struct {
|
|
62
|
+
Schema struct{ Properties map[string]any }
|
|
63
|
+
}
|
|
64
|
+
c.Decode(c.Must("resolveSessionConfig", map[string]any{"channel": wire.RootChannel, "workingDirectory": wire.PathToFileURI(workspace)}), &config)
|
|
65
|
+
if config.Schema.Properties[pi.ProjectTrustKey] == nil {
|
|
66
|
+
t.Fatalf("no project trust property in %v", config.Schema.Properties)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
id := "0a3c1e52-6b7d-4f3a-9d10-000000000001"
|
|
70
|
+
session, chat := wire.SessionURI(id), wire.ChatURI(id)
|
|
71
|
+
c.Must("createSession", map[string]any{"channel": session})
|
|
72
|
+
c.Must("subscribe", map[string]any{"channel": chat})
|
|
73
|
+
testkit.Eventually(t, "the composed session backend to become ready", func() bool {
|
|
74
|
+
s := built.Host.Store().Session(session)
|
|
75
|
+
return s != nil && s.Lifecycle == ahptypes.SessionLifecycleReady
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
var completions ahptypes.CompletionsResult
|
|
79
|
+
c.Decode(c.Must("completions", map[string]any{"channel": chat, "kind": "userMessage", "text": "see @not", "offset": 8}), &completions)
|
|
80
|
+
var inserted []string
|
|
81
|
+
for _, item := range completions.Items {
|
|
82
|
+
inserted = append(inserted, item.InsertText)
|
|
83
|
+
}
|
|
84
|
+
if !reflect.DeepEqual(inserted, []string{"@notes.md"}) {
|
|
85
|
+
raw, _ := json.Marshal(completions)
|
|
86
|
+
t.Fatalf("completions %s", raw)
|
|
87
|
+
}
|
|
88
|
+
})
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
func TestNothingIsExposedByDefault(t *testing.T) {
|
|
92
|
+
// Additions: fs and terminals are opt-in, and an unconfined filesystem must be explicit.
|
|
93
|
+
built, err := Build(Options{WorkingDirectory: t.TempDir(), CreateBackend: func(*pi.LiveSession) (pi.Backend, error) { return idleBackend{}, nil }})
|
|
94
|
+
if err != nil {
|
|
95
|
+
t.Fatal(err)
|
|
96
|
+
}
|
|
97
|
+
defer built.Close()
|
|
98
|
+
if built.Resources != nil || built.Watches != nil || built.Terminals != nil {
|
|
99
|
+
t.Fatal("no filesystem or terminal service may exist without opt-in")
|
|
100
|
+
}
|
|
101
|
+
c := testkit.Connect(t, built.Host)
|
|
102
|
+
defer c.Close()
|
|
103
|
+
c.Initialize("nothing", nil)
|
|
104
|
+
c.ExpectError("resourceRead", map[string]any{"channel": wire.RootChannel, "uri": "file:///etc/hostname"}, wire.CodeMethodNotFound)
|
|
105
|
+
c.ExpectError("createTerminal", map[string]any{"channel": "ahp-terminal:/x", "claim": map[string]any{"kind": "client", "clientId": "nothing"}}, wire.CodeMethodNotFound)
|
|
106
|
+
c.ExpectError("createResourceWatch", map[string]any{"channel": wire.RootChannel, "uri": "file:///tmp"}, wire.CodeMethodNotFound)
|
|
107
|
+
|
|
108
|
+
if _, err := Build(Options{CreateBackend: func(*pi.LiveSession) (pi.Backend, error) { return idleBackend{}, nil }, Filesystem: &FilesystemOptions{}}); err == nil {
|
|
109
|
+
t.Fatal("a filesystem with no roots and no explicit Unrestricted must be refused")
|
|
110
|
+
}
|
|
111
|
+
confined, err := Build(Options{WorkingDirectory: t.TempDir(), CreateBackend: func(*pi.LiveSession) (pi.Backend, error) { return idleBackend{}, nil }, Filesystem: &FilesystemOptions{Roots: []string{t.TempDir()}}})
|
|
112
|
+
if err != nil {
|
|
113
|
+
t.Fatal(err)
|
|
114
|
+
}
|
|
115
|
+
defer confined.Close()
|
|
116
|
+
cc := testkit.Connect(t, confined.Host)
|
|
117
|
+
defer cc.Close()
|
|
118
|
+
cc.Initialize("confined", nil)
|
|
119
|
+
cc.ExpectError("resourceRead", map[string]any{"channel": wire.RootChannel, "uri": "file:///etc/hostname"}, wire.CodePermissionDenied)
|
|
120
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// Package gaps records the upstream (pi-ahp) test cases that have no runnable Go twin, each as a
|
|
2
|
+
// named skipped twin with its reason. Nothing here is silent: the twin gate counts these, and
|
|
3
|
+
// proof/PORT.md explains every family.
|
|
4
|
+
package gaps
|
|
5
|
+
|
|
6
|
+
import (
|
|
7
|
+
"testing"
|
|
8
|
+
|
|
9
|
+
"github.com/MichaelKinsy/pigpen/ahp/internal/twin"
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
func TestGapTunnel(t *testing.T) {
|
|
13
|
+
twin.Skip(t, "tunnel", "uses the shared discovery labels and port", "dev tunnel is not bundled: an owner decision (ACP, AHP and A2A are separate extensions, tunnel management stays outside this port)")
|
|
14
|
+
twin.Skip(t, "tunnel", "keeps the identity label out of the display name", "dev tunnel is not bundled: an owner decision (ACP, AHP and A2A are separate extensions, tunnel management stays outside this port)")
|
|
15
|
+
twin.Skip(t, "tunnel", "folds a name the way VS Code does", "dev tunnel is not bundled: an owner decision (ACP, AHP and A2A are separate extensions, tunnel management stays outside this port)")
|
|
16
|
+
twin.Skip(t, "tunnel", "reports when the CLI is not installed", "dev tunnel is not bundled: an owner decision (ACP, AHP and A2A are separate extensions, tunnel management stays outside this port)")
|
|
17
|
+
twin.Skip(t, "tunnel", "requires a logged-in account", "dev tunnel is not bundled: an owner decision (ACP, AHP and A2A are separate extensions, tunnel management stays outside this port)")
|
|
18
|
+
twin.Skip(t, "tunnel", "reports account inspection failures", "dev tunnel is not bundled: an owner decision (ACP, AHP and A2A are separate extensions, tunnel management stays outside this port)")
|
|
19
|
+
twin.Skip(t, "tunnel", "finds this host's first labelled tunnel", "dev tunnel is not bundled: an owner decision (ACP, AHP and A2A are separate extensions, tunnel management stays outside this port)")
|
|
20
|
+
twin.Skip(t, "tunnel", "returns no tunnel for a successful empty listing", "dev tunnel is not bundled: an owner decision (ACP, AHP and A2A are separate extensions, tunnel management stays outside this port)")
|
|
21
|
+
twin.Skip(t, "tunnel", "reports tunnel listing failures and malformed responses", "dev tunnel is not bundled: an owner decision (ACP, AHP and A2A are separate extensions, tunnel management stays outside this port)")
|
|
22
|
+
twin.Skip(t, "tunnel", "creates a tunnel with identity, protocol, launcher, and display labels", "dev tunnel is not bundled: an owner decision (ACP, AHP and A2A are separate extensions, tunnel management stays outside this port)")
|
|
23
|
+
twin.Skip(t, "tunnel", "rejects failed or malformed tunnel creation", "dev tunnel is not bundled: an owner decision (ACP, AHP and A2A are separate extensions, tunnel management stays outside this port)")
|
|
24
|
+
twin.Skip(t, "tunnel", "renames a tunnel without disturbing reserved labels", "dev tunnel is not bundled: an owner decision (ACP, AHP and A2A are separate extensions, tunnel management stays outside this port)")
|
|
25
|
+
twin.Skip(t, "tunnel", "reports a failed rename", "dev tunnel is not bundled: an owner decision (ACP, AHP and A2A are separate extensions, tunnel management stays outside this port)")
|
|
26
|
+
twin.Skip(t, "tunnel", "creates port 31546 when a successful listing is empty", "dev tunnel is not bundled: an owner decision (ACP, AHP and A2A are separate extensions, tunnel management stays outside this port)")
|
|
27
|
+
twin.Skip(t, "tunnel", "keeps an existing HTTP port", "dev tunnel is not bundled: an owner decision (ACP, AHP and A2A are separate extensions, tunnel management stays outside this port)")
|
|
28
|
+
twin.Skip(t, "tunnel", "replaces an old HTTPS port with an HTTP port", "dev tunnel is not bundled: an owner decision (ACP, AHP and A2A are separate extensions, tunnel management stays outside this port)")
|
|
29
|
+
twin.Skip(t, "tunnel", "does not discard port-specific access control while migrating", "dev tunnel is not bundled: an owner decision (ACP, AHP and A2A are separate extensions, tunnel management stays outside this port)")
|
|
30
|
+
twin.Skip(t, "tunnel", "uses current port details when the protocol changes during inspection", "dev tunnel is not bundled: an owner decision (ACP, AHP and A2A are separate extensions, tunnel management stays outside this port)")
|
|
31
|
+
twin.Skip(t, "tunnel", "rejects malformed port inspection output", "dev tunnel is not bundled: an owner decision (ACP, AHP and A2A are separate extensions, tunnel management stays outside this port)")
|
|
32
|
+
twin.Skip(t, "tunnel", "reports listing, inspection, deletion, and creation failures", "dev tunnel is not bundled: an owner decision (ACP, AHP and A2A are separate extensions, tunnel management stays outside this port)")
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
func TestGapPiReplay(t *testing.T) {
|
|
36
|
+
twin.Skip(t, "pi-replay", "plain-text", "replays provider streams through a live Pi agent loop, which a Go extension cannot embed; the recorded-stream half is the mapper-fixtures twins and the live half is the layer-6 differential against a scripted provider")
|
|
37
|
+
twin.Skip(t, "pi-replay", "single-tool", "replays provider streams through a live Pi agent loop, which a Go extension cannot embed; the recorded-stream half is the mapper-fixtures twins and the live half is the layer-6 differential against a scripted provider")
|
|
38
|
+
twin.Skip(t, "pi-replay", "parallel-tools", "replays provider streams through a live Pi agent loop, which a Go extension cannot embed; the recorded-stream half is the mapper-fixtures twins and the live half is the layer-6 differential against a scripted provider")
|
|
39
|
+
twin.Skip(t, "pi-replay", "tool-loop", "replays provider streams through a live Pi agent loop, which a Go extension cannot embed; the recorded-stream half is the mapper-fixtures twins and the live half is the layer-6 differential against a scripted provider")
|
|
40
|
+
twin.Skip(t, "pi-replay", "tool-error", "replays provider streams through a live Pi agent loop, which a Go extension cannot embed; the recorded-stream half is the mapper-fixtures twins and the live half is the layer-6 differential against a scripted provider")
|
|
41
|
+
twin.Skip(t, "pi-replay", "abort", "replays provider streams through a live Pi agent loop, which a Go extension cannot embed; the recorded-stream half is the mapper-fixtures twins and the live half is the layer-6 differential against a scripted provider")
|
|
42
|
+
twin.Skip(t, "pi-replay", "steering", "replays provider streams through a live Pi agent loop, which a Go extension cannot embed; the recorded-stream half is the mapper-fixtures twins and the live half is the layer-6 differential against a scripted provider")
|
|
43
|
+
twin.Skip(t, "pi-replay", "tool-edit", "replays provider streams through a live Pi agent loop, which a Go extension cannot embed; the recorded-stream half is the mapper-fixtures twins and the live half is the layer-6 differential against a scripted provider")
|
|
44
|
+
twin.Skip(t, "pi-replay", "tool-write", "replays provider streams through a live Pi agent loop, which a Go extension cannot embed; the recorded-stream half is the mapper-fixtures twins and the live half is the layer-6 differential against a scripted provider")
|
|
45
|
+
twin.Skip(t, "pi-replay", "tool-bash", "replays provider streams through a live Pi agent loop, which a Go extension cannot embed; the recorded-stream half is the mapper-fixtures twins and the live half is the layer-6 differential against a scripted provider")
|
|
46
|
+
twin.Skip(t, "pi-replay", "tool-ls", "replays provider streams through a live Pi agent loop, which a Go extension cannot embed; the recorded-stream half is the mapper-fixtures twins and the live half is the layer-6 differential against a scripted provider")
|
|
47
|
+
twin.Skip(t, "pi-replay", "tool-grep", "replays provider streams through a live Pi agent loop, which a Go extension cannot embed; the recorded-stream half is the mapper-fixtures twins and the live half is the layer-6 differential against a scripted provider")
|
|
48
|
+
twin.Skip(t, "pi-replay", "tool-find", "replays provider streams through a live Pi agent loop, which a Go extension cannot embed; the recorded-stream half is the mapper-fixtures twins and the live half is the layer-6 differential against a scripted provider")
|
|
49
|
+
twin.Skip(t, "pi-replay", "compaction", "replays provider streams through a live Pi agent loop, which a Go extension cannot embed; the recorded-stream half is the mapper-fixtures twins and the live half is the layer-6 differential against a scripted provider")
|
|
50
|
+
twin.Skip(t, "pi-replay", "bash-long-output", "replays provider streams through a live Pi agent loop, which a Go extension cannot embed; the recorded-stream half is the mapper-fixtures twins and the live half is the layer-6 differential against a scripted provider")
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
func TestGapChangeset(t *testing.T) {
|
|
54
|
+
twin.Skip(t, "changeset", "keeps the latest commit separate from uncommitted work and refreshes it", "git changeset service not ported in this release (documented gap: no changeset channels are advertised, see PORT.md)")
|
|
55
|
+
twin.Skip(t, "changeset", "limits changes to the session working-directory subtree", "git changeset service not ported in this release (documented gap: no changeset channels are advertised, see PORT.md)")
|
|
56
|
+
twin.Skip(t, "changeset", "ignores ambient Git repository overrides", "git changeset service not ported in this release (documented gap: no changeset channels are advertised, see PORT.md)")
|
|
57
|
+
twin.Skip(t, "changeset", "omits changesets when Git is unavailable", "git changeset service not ported in this release (documented gap: no changeset channels are advertised, see PORT.md)")
|
|
58
|
+
twin.Skip(t, "changeset", "omits changesets outside Git workspaces", "git changeset service not ported in this release (documented gap: no changeset channels are advertised, see PORT.md)")
|
|
59
|
+
twin.Skip(t, "changeset", "omits Latest Commit before the repository has a commit", "git changeset service not ported in this release (documented gap: no changeset channels are advertised, see PORT.md)")
|
|
60
|
+
twin.Skip(t, "changeset", "resumes changeset updates when durable session deletion fails", "git changeset service not ported in this release (documented gap: no changeset channels are advertised, see PORT.md)")
|
|
61
|
+
twin.Skip(t, "changeset", "hydrates the parent session when its changeset is subscribed directly", "git changeset service not ported in this release (documented gap: no changeset channels are advertised, see PORT.md)")
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
func TestGapChangesetLifecycle(t *testing.T) {
|
|
65
|
+
twin.Skip(t, "changeset-lifecycle", "observes changes during the initial scan and rebuilds changed ignore rules", "git changeset service not ported in this release (documented gap: no changeset channels are advertised, see PORT.md)")
|
|
66
|
+
twin.Skip(t, "changeset-lifecycle", "refreshes file changes while a turn is still active", "git changeset service not ported in this release (documented gap: no changeset channels are advertised, see PORT.md)")
|
|
67
|
+
twin.Skip(t, "changeset-lifecycle", "does not recursively watch when ignored paths cannot be determined", "git changeset service not ported in this release (documented gap: no changeset channels are advertised, see PORT.md)")
|
|
68
|
+
twin.Skip(t, "changeset-lifecycle", "publishes an explicit error when Git cannot compute the changeset", "git changeset service not ported in this release (documented gap: no changeset channels are advertised, see PORT.md)")
|
|
69
|
+
twin.Skip(t, "changeset-lifecycle", "drains an in-flight scan before deleting its channel", "git changeset service not ported in this release (documented gap: no changeset channels are advertised, see PORT.md)")
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
func TestGapChangesetURI(t *testing.T) {
|
|
73
|
+
twin.Skip(t, "changeset-uri", "builds stable static catalogue channels", "git changeset service not ported in this release (documented gap: no changeset channels are advertised, see PORT.md)")
|
|
74
|
+
twin.Skip(t, "changeset-uri", "rejects channels the host did not advertise", "git changeset service not ported in this release (documented gap: no changeset channels are advertised, see PORT.md)")
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
func TestGapImageSession(t *testing.T) {
|
|
78
|
+
twin.Skip(t, "image-session", "passes and persists images while honouring preflight cancellation", "needs Pi's InProcessPiBackend with a faux model; the SDK adapter's image path is covered by its own adapter tests")
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
func TestGapLiveTurn(t *testing.T) {
|
|
82
|
+
twin.Skip(t, "live-turn", "live turn # SKIP needs a real model \u2014 set PI_AHP_LIVE_SETTINGS and PI_AHP_LIVE_AUTH", "upstream itself skips this case without a real model (PI_AHP_LIVE_SETTINGS and PI_AHP_LIVE_AUTH)")
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
func TestGapModelDiscovery(t *testing.T) {
|
|
86
|
+
twin.Skip(t, "model-discovery", "advertises extension models and uses pi's configured default", "needs an embedded Pi model registry with extension-provided models; the SDK adapter reads models through the PiG SDK and is covered by adapter tests")
|
|
87
|
+
twin.Skip(t, "model-discovery", "resolves stale and provider-qualified model selections safely", "needs an embedded Pi model registry with extension-provided models; the SDK adapter reads models through the PiG SDK and is covered by adapter tests")
|
|
88
|
+
}
|