@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,222 @@
|
|
|
1
|
+
package pi
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"bytes"
|
|
5
|
+
"encoding/json"
|
|
6
|
+
"fmt"
|
|
7
|
+
"os"
|
|
8
|
+
"path/filepath"
|
|
9
|
+
"sort"
|
|
10
|
+
"time"
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
// Project trust (port of src/pi/project-trust.ts and the parts of Pi's trust-manager it uses).
|
|
14
|
+
//
|
|
15
|
+
// A project directory can carry resources that run code when Pi loads them (extensions, skills,
|
|
16
|
+
// prompts, themes, settings). Whether to load them is a security decision, and a host takes the
|
|
17
|
+
// working directory from a client over the network, so the policy matters:
|
|
18
|
+
//
|
|
19
|
+
// trust - load them (what raw Pi SDK construction does; the default)
|
|
20
|
+
// inherit - follow the decision the user recorded with Pi's own CLI; unknown = untrusted
|
|
21
|
+
// never - never load them, whatever was recorded
|
|
22
|
+
|
|
23
|
+
// ProjectTrustPolicy selects how project resources are trusted.
|
|
24
|
+
type ProjectTrustPolicy string
|
|
25
|
+
|
|
26
|
+
const (
|
|
27
|
+
TrustPolicyTrust ProjectTrustPolicy = "trust"
|
|
28
|
+
TrustPolicyInherit ProjectTrustPolicy = "inherit"
|
|
29
|
+
TrustPolicyNever ProjectTrustPolicy = "never"
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
// TrustDecision is the outcome of a trust resolution.
|
|
33
|
+
type TrustDecision struct {
|
|
34
|
+
Trusted bool
|
|
35
|
+
// Reason is "no-project-resources", "user-trusted", "user-untrusted", "policy" or
|
|
36
|
+
// "unknown-project".
|
|
37
|
+
Reason string
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// trustRequiringConfigResources are the entries of a project's config directory that Pi gates.
|
|
41
|
+
var trustRequiringConfigResources = []string{"settings.json", "extensions", "skills", "prompts", "themes", "SYSTEM.md", "APPEND_SYSTEM.md"}
|
|
42
|
+
|
|
43
|
+
// projectConfigDirs are the project config directory names checked: Pi's ".pi" and PiG's ".pig".
|
|
44
|
+
var projectConfigDirs = []string{".pi", ".pig"}
|
|
45
|
+
|
|
46
|
+
func canonical(path string) string {
|
|
47
|
+
abs, err := filepath.Abs(path)
|
|
48
|
+
if err != nil {
|
|
49
|
+
abs = path
|
|
50
|
+
}
|
|
51
|
+
if real, err := filepath.EvalSymlinks(abs); err == nil {
|
|
52
|
+
return real
|
|
53
|
+
}
|
|
54
|
+
return abs
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
func exists(path string) bool { _, err := os.Stat(path); return err == nil }
|
|
58
|
+
|
|
59
|
+
// HasTrustRequiringProjectResources reports whether cwd has project-local resources that must be
|
|
60
|
+
// gated: trust-requiring entries under its config directory, or .agents/skills in cwd or one of
|
|
61
|
+
// its ancestors. The user's own ~/.agents/skills is a trusted user resource and is ignored, even
|
|
62
|
+
// when cwd is the home directory.
|
|
63
|
+
func HasTrustRequiringProjectResources(cwd string) bool {
|
|
64
|
+
home := os.Getenv("HOME")
|
|
65
|
+
if home == "" {
|
|
66
|
+
home, _ = os.UserHomeDir()
|
|
67
|
+
}
|
|
68
|
+
userSkills := filepath.Join(canonical(home), ".agents", "skills")
|
|
69
|
+
dir := canonical(cwd)
|
|
70
|
+
for _, name := range projectConfigDirs {
|
|
71
|
+
for _, entry := range trustRequiringConfigResources {
|
|
72
|
+
if exists(filepath.Join(dir, name, entry)) {
|
|
73
|
+
return true
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
for {
|
|
78
|
+
skills := filepath.Join(dir, ".agents", "skills")
|
|
79
|
+
if skills != userSkills && exists(skills) {
|
|
80
|
+
return true
|
|
81
|
+
}
|
|
82
|
+
parent := filepath.Dir(dir)
|
|
83
|
+
if parent == dir {
|
|
84
|
+
return false
|
|
85
|
+
}
|
|
86
|
+
dir = parent
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// ProjectTrustStore is Pi's trust store (<agentDir>/trust.json): the very same file Pi's CLI
|
|
91
|
+
// writes, so a decision made in either tool holds in both.
|
|
92
|
+
type ProjectTrustStore struct{ path string }
|
|
93
|
+
|
|
94
|
+
// NewProjectTrustStore opens the store of an agent directory.
|
|
95
|
+
func NewProjectTrustStore(agentDir string) *ProjectTrustStore {
|
|
96
|
+
return &ProjectTrustStore{path: filepath.Join(agentDir, "trust.json")}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
func (s *ProjectTrustStore) read() (map[string]*bool, error) {
|
|
100
|
+
raw, err := os.ReadFile(s.path)
|
|
101
|
+
if os.IsNotExist(err) {
|
|
102
|
+
return map[string]*bool{}, nil
|
|
103
|
+
}
|
|
104
|
+
if err != nil {
|
|
105
|
+
return nil, err
|
|
106
|
+
}
|
|
107
|
+
raw = bytes.TrimPrefix(raw, []byte("\xef\xbb\xbf"))
|
|
108
|
+
var data map[string]*bool
|
|
109
|
+
if err := json.Unmarshal(raw, &data); err != nil || data == nil {
|
|
110
|
+
return nil, fmt.Errorf("Invalid trust store %s: expected an object of true, false or null values", s.path)
|
|
111
|
+
}
|
|
112
|
+
return data, nil
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// withLock serialises store access with Pi's lock convention: a "<path>.lock" directory.
|
|
116
|
+
func (s *ProjectTrustStore) withLock(fn func() error) error {
|
|
117
|
+
if err := os.MkdirAll(filepath.Dir(s.path), 0o755); err != nil {
|
|
118
|
+
return err
|
|
119
|
+
}
|
|
120
|
+
lock := s.path + ".lock"
|
|
121
|
+
var err error
|
|
122
|
+
for attempt := 0; attempt < 10; attempt++ {
|
|
123
|
+
if err = os.Mkdir(lock, 0o755); err == nil {
|
|
124
|
+
defer os.Remove(lock)
|
|
125
|
+
return fn()
|
|
126
|
+
}
|
|
127
|
+
if !os.IsExist(err) {
|
|
128
|
+
return err
|
|
129
|
+
}
|
|
130
|
+
time.Sleep(20 * time.Millisecond)
|
|
131
|
+
}
|
|
132
|
+
return fmt.Errorf("Failed to acquire trust store lock: %w", err)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Get is the decision recorded for cwd or its nearest ancestor: true, false, or nil when none.
|
|
136
|
+
func (s *ProjectTrustStore) Get(cwd string) (*bool, error) {
|
|
137
|
+
var out *bool
|
|
138
|
+
err := s.withLock(func() error {
|
|
139
|
+
data, err := s.read()
|
|
140
|
+
if err != nil {
|
|
141
|
+
return err
|
|
142
|
+
}
|
|
143
|
+
for dir := canonical(cwd); ; {
|
|
144
|
+
if v := data[dir]; v != nil {
|
|
145
|
+
out = v
|
|
146
|
+
return nil
|
|
147
|
+
}
|
|
148
|
+
parent := filepath.Dir(dir)
|
|
149
|
+
if parent == dir {
|
|
150
|
+
return nil
|
|
151
|
+
}
|
|
152
|
+
dir = parent
|
|
153
|
+
}
|
|
154
|
+
})
|
|
155
|
+
return out, err
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Set records (or with nil clears) the decision for cwd.
|
|
159
|
+
func (s *ProjectTrustStore) Set(cwd string, decision *bool) error {
|
|
160
|
+
return s.withLock(func() error {
|
|
161
|
+
data, err := s.read()
|
|
162
|
+
if err != nil {
|
|
163
|
+
return err
|
|
164
|
+
}
|
|
165
|
+
key := canonical(cwd)
|
|
166
|
+
if decision == nil {
|
|
167
|
+
delete(data, key)
|
|
168
|
+
} else {
|
|
169
|
+
data[key] = decision
|
|
170
|
+
}
|
|
171
|
+
keys := make([]string, 0, len(data))
|
|
172
|
+
for k := range data {
|
|
173
|
+
keys = append(keys, k)
|
|
174
|
+
}
|
|
175
|
+
sort.Strings(keys)
|
|
176
|
+
var buf bytes.Buffer
|
|
177
|
+
buf.WriteString("{")
|
|
178
|
+
for i, k := range keys {
|
|
179
|
+
if i > 0 {
|
|
180
|
+
buf.WriteString(",")
|
|
181
|
+
}
|
|
182
|
+
kj, _ := json.Marshal(k)
|
|
183
|
+
vj, _ := json.Marshal(data[k])
|
|
184
|
+
fmt.Fprintf(&buf, "\n %s: %s", kj, vj)
|
|
185
|
+
}
|
|
186
|
+
if len(keys) > 0 {
|
|
187
|
+
buf.WriteString("\n")
|
|
188
|
+
}
|
|
189
|
+
buf.WriteString("}\n")
|
|
190
|
+
return os.WriteFile(s.path, buf.Bytes(), 0o644)
|
|
191
|
+
})
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// ResolveProjectTrust decides whether a working directory's project resources may load. An empty
|
|
195
|
+
// policy means "trust". A store that cannot be read is an error, not a decision.
|
|
196
|
+
func ResolveProjectTrust(cwd string, policy ProjectTrustPolicy, agentDir string) (TrustDecision, error) {
|
|
197
|
+
if policy == "" {
|
|
198
|
+
policy = TrustPolicyTrust
|
|
199
|
+
}
|
|
200
|
+
if policy == TrustPolicyNever {
|
|
201
|
+
return TrustDecision{false, "policy"}, nil
|
|
202
|
+
}
|
|
203
|
+
// Nothing in the directory needs gating: trusting it grants nothing.
|
|
204
|
+
if !HasTrustRequiringProjectResources(cwd) {
|
|
205
|
+
return TrustDecision{true, "no-project-resources"}, nil
|
|
206
|
+
}
|
|
207
|
+
if policy == TrustPolicyTrust {
|
|
208
|
+
return TrustDecision{true, "policy"}, nil
|
|
209
|
+
}
|
|
210
|
+
stored, err := NewProjectTrustStore(agentDir).Get(cwd)
|
|
211
|
+
if err != nil {
|
|
212
|
+
return TrustDecision{}, err
|
|
213
|
+
}
|
|
214
|
+
switch {
|
|
215
|
+
case stored != nil && *stored:
|
|
216
|
+
return TrustDecision{true, "user-trusted"}, nil
|
|
217
|
+
case stored != nil:
|
|
218
|
+
return TrustDecision{false, "user-untrusted"}, nil
|
|
219
|
+
}
|
|
220
|
+
// No recorded decision, and a host has no user to ask.
|
|
221
|
+
return TrustDecision{false, "unknown-project"}, nil
|
|
222
|
+
}
|