@synadia-ai/agent-fabric-pi 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.
@@ -0,0 +1,367 @@
1
+ {
2
+ "schema": 1,
3
+ "config": {
4
+ "schema": 1,
5
+ "release": "sp-v0.1.6",
6
+ "source_commit": "5e518519d1f9af47364cdf5ab01d518c8a195d33",
7
+ "go_version": "go1.26.7",
8
+ "targets": [
9
+ "darwin/arm64",
10
+ "darwin/amd64",
11
+ "linux/arm64",
12
+ "linux/amd64"
13
+ ]
14
+ },
15
+ "distribution_repository": "synadia-ai/agent-fabric-sdk",
16
+ "license": "Apache-2.0",
17
+ "files": {
18
+ "sp-darwin-arm64": {
19
+ "sha256": "c4d85f758490a50271b581a42cc78fd9318f7c2393cc97cbd4525773c3107bfe",
20
+ "bytes": 6968994
21
+ },
22
+ "sp-darwin-amd64": {
23
+ "sha256": "3d84751719e555218c4f977cdd5b9a5ef149d26421fc7dc6c6ec7b54586d4915",
24
+ "bytes": 7599504
25
+ },
26
+ "sp-linux-arm64": {
27
+ "sha256": "41e2ae7dfdc614ba3fa8a17ef51da5b8e02d29d4a36b718f428274c6804f9eb3",
28
+ "bytes": 6881442
29
+ },
30
+ "sp-linux-amd64": {
31
+ "sha256": "d03dde699244a13ef24675189dd3452805732d331b92505c120fad0da391b23e",
32
+ "bytes": 7454882
33
+ }
34
+ },
35
+ "build_info": {
36
+ "darwin/arm64": {
37
+ "Deps": [
38
+ {
39
+ "Path": "github.com/klauspost/compress",
40
+ "Sum": "h1:hMRETovs/pu/dVWN7zIT1PGG8t509MwT6bO7XSi26R8=",
41
+ "Version": "v1.19.2"
42
+ },
43
+ {
44
+ "Path": "github.com/nats-io/nats.go",
45
+ "Replace": {
46
+ "Path": "./third_party/nats-go",
47
+ "Version": "(devel)"
48
+ },
49
+ "Version": "v1.53.1"
50
+ },
51
+ {
52
+ "Path": "github.com/nats-io/nkeys",
53
+ "Sum": "h1:rd5oAuLOb8mnAycB0xleuEBNS1pVVnN0fv/FF34Eypg=",
54
+ "Version": "v0.4.16"
55
+ },
56
+ {
57
+ "Path": "github.com/nats-io/nuid",
58
+ "Sum": "h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=",
59
+ "Version": "v1.0.1"
60
+ },
61
+ {
62
+ "Path": "golang.org/x/crypto",
63
+ "Sum": "h1:+KWHjbgOaAQ66dh/YlkZKHlz9ZUlq61AFirAR9ntP8M=",
64
+ "Version": "v0.55.0"
65
+ },
66
+ {
67
+ "Path": "golang.org/x/sys",
68
+ "Sum": "h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=",
69
+ "Version": "v0.47.0"
70
+ },
71
+ {
72
+ "Path": "golang.org/x/text",
73
+ "Sum": "h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8=",
74
+ "Version": "v0.41.0"
75
+ }
76
+ ],
77
+ "GoVersion": "go1.26.7",
78
+ "Main": {
79
+ "Path": "github.com/synadia-ai/agent-fabric-sdk/sp",
80
+ "Version": "(devel)"
81
+ },
82
+ "Path": "github.com/synadia-ai/agent-fabric-sdk/sp/cmd/sp",
83
+ "Settings": [
84
+ {
85
+ "Key": "-buildmode",
86
+ "Value": "exe"
87
+ },
88
+ {
89
+ "Key": "-compiler",
90
+ "Value": "gc"
91
+ },
92
+ {
93
+ "Key": "-trimpath",
94
+ "Value": "true"
95
+ },
96
+ {
97
+ "Key": "CGO_ENABLED",
98
+ "Value": "0"
99
+ },
100
+ {
101
+ "Key": "GOARCH",
102
+ "Value": "arm64"
103
+ },
104
+ {
105
+ "Key": "GOOS",
106
+ "Value": "darwin"
107
+ },
108
+ {
109
+ "Key": "GOARM64",
110
+ "Value": "v8.0"
111
+ }
112
+ ]
113
+ },
114
+ "darwin/amd64": {
115
+ "Deps": [
116
+ {
117
+ "Path": "github.com/klauspost/compress",
118
+ "Sum": "h1:hMRETovs/pu/dVWN7zIT1PGG8t509MwT6bO7XSi26R8=",
119
+ "Version": "v1.19.2"
120
+ },
121
+ {
122
+ "Path": "github.com/nats-io/nats.go",
123
+ "Replace": {
124
+ "Path": "./third_party/nats-go",
125
+ "Version": "(devel)"
126
+ },
127
+ "Version": "v1.53.1"
128
+ },
129
+ {
130
+ "Path": "github.com/nats-io/nkeys",
131
+ "Sum": "h1:rd5oAuLOb8mnAycB0xleuEBNS1pVVnN0fv/FF34Eypg=",
132
+ "Version": "v0.4.16"
133
+ },
134
+ {
135
+ "Path": "github.com/nats-io/nuid",
136
+ "Sum": "h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=",
137
+ "Version": "v1.0.1"
138
+ },
139
+ {
140
+ "Path": "golang.org/x/crypto",
141
+ "Sum": "h1:+KWHjbgOaAQ66dh/YlkZKHlz9ZUlq61AFirAR9ntP8M=",
142
+ "Version": "v0.55.0"
143
+ },
144
+ {
145
+ "Path": "golang.org/x/sys",
146
+ "Sum": "h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=",
147
+ "Version": "v0.47.0"
148
+ },
149
+ {
150
+ "Path": "golang.org/x/text",
151
+ "Sum": "h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8=",
152
+ "Version": "v0.41.0"
153
+ }
154
+ ],
155
+ "GoVersion": "go1.26.7",
156
+ "Main": {
157
+ "Path": "github.com/synadia-ai/agent-fabric-sdk/sp",
158
+ "Version": "(devel)"
159
+ },
160
+ "Path": "github.com/synadia-ai/agent-fabric-sdk/sp/cmd/sp",
161
+ "Settings": [
162
+ {
163
+ "Key": "-buildmode",
164
+ "Value": "exe"
165
+ },
166
+ {
167
+ "Key": "-compiler",
168
+ "Value": "gc"
169
+ },
170
+ {
171
+ "Key": "-trimpath",
172
+ "Value": "true"
173
+ },
174
+ {
175
+ "Key": "CGO_ENABLED",
176
+ "Value": "0"
177
+ },
178
+ {
179
+ "Key": "GOARCH",
180
+ "Value": "amd64"
181
+ },
182
+ {
183
+ "Key": "GOOS",
184
+ "Value": "darwin"
185
+ },
186
+ {
187
+ "Key": "GOAMD64",
188
+ "Value": "v1"
189
+ }
190
+ ]
191
+ },
192
+ "linux/arm64": {
193
+ "Deps": [
194
+ {
195
+ "Path": "github.com/klauspost/compress",
196
+ "Sum": "h1:hMRETovs/pu/dVWN7zIT1PGG8t509MwT6bO7XSi26R8=",
197
+ "Version": "v1.19.2"
198
+ },
199
+ {
200
+ "Path": "github.com/nats-io/nats.go",
201
+ "Replace": {
202
+ "Path": "./third_party/nats-go",
203
+ "Version": "(devel)"
204
+ },
205
+ "Version": "v1.53.1"
206
+ },
207
+ {
208
+ "Path": "github.com/nats-io/nkeys",
209
+ "Sum": "h1:rd5oAuLOb8mnAycB0xleuEBNS1pVVnN0fv/FF34Eypg=",
210
+ "Version": "v0.4.16"
211
+ },
212
+ {
213
+ "Path": "github.com/nats-io/nuid",
214
+ "Sum": "h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=",
215
+ "Version": "v1.0.1"
216
+ },
217
+ {
218
+ "Path": "golang.org/x/crypto",
219
+ "Sum": "h1:+KWHjbgOaAQ66dh/YlkZKHlz9ZUlq61AFirAR9ntP8M=",
220
+ "Version": "v0.55.0"
221
+ },
222
+ {
223
+ "Path": "golang.org/x/sys",
224
+ "Sum": "h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=",
225
+ "Version": "v0.47.0"
226
+ },
227
+ {
228
+ "Path": "golang.org/x/text",
229
+ "Sum": "h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8=",
230
+ "Version": "v0.41.0"
231
+ }
232
+ ],
233
+ "GoVersion": "go1.26.7",
234
+ "Main": {
235
+ "Path": "github.com/synadia-ai/agent-fabric-sdk/sp",
236
+ "Version": "(devel)"
237
+ },
238
+ "Path": "github.com/synadia-ai/agent-fabric-sdk/sp/cmd/sp",
239
+ "Settings": [
240
+ {
241
+ "Key": "-buildmode",
242
+ "Value": "exe"
243
+ },
244
+ {
245
+ "Key": "-compiler",
246
+ "Value": "gc"
247
+ },
248
+ {
249
+ "Key": "-trimpath",
250
+ "Value": "true"
251
+ },
252
+ {
253
+ "Key": "CGO_ENABLED",
254
+ "Value": "0"
255
+ },
256
+ {
257
+ "Key": "GOARCH",
258
+ "Value": "arm64"
259
+ },
260
+ {
261
+ "Key": "GOOS",
262
+ "Value": "linux"
263
+ },
264
+ {
265
+ "Key": "GOARM64",
266
+ "Value": "v8.0"
267
+ }
268
+ ]
269
+ },
270
+ "linux/amd64": {
271
+ "Deps": [
272
+ {
273
+ "Path": "github.com/klauspost/compress",
274
+ "Sum": "h1:hMRETovs/pu/dVWN7zIT1PGG8t509MwT6bO7XSi26R8=",
275
+ "Version": "v1.19.2"
276
+ },
277
+ {
278
+ "Path": "github.com/nats-io/nats.go",
279
+ "Replace": {
280
+ "Path": "./third_party/nats-go",
281
+ "Version": "(devel)"
282
+ },
283
+ "Version": "v1.53.1"
284
+ },
285
+ {
286
+ "Path": "github.com/nats-io/nkeys",
287
+ "Sum": "h1:rd5oAuLOb8mnAycB0xleuEBNS1pVVnN0fv/FF34Eypg=",
288
+ "Version": "v0.4.16"
289
+ },
290
+ {
291
+ "Path": "github.com/nats-io/nuid",
292
+ "Sum": "h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=",
293
+ "Version": "v1.0.1"
294
+ },
295
+ {
296
+ "Path": "golang.org/x/crypto",
297
+ "Sum": "h1:+KWHjbgOaAQ66dh/YlkZKHlz9ZUlq61AFirAR9ntP8M=",
298
+ "Version": "v0.55.0"
299
+ },
300
+ {
301
+ "Path": "golang.org/x/sys",
302
+ "Sum": "h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=",
303
+ "Version": "v0.47.0"
304
+ },
305
+ {
306
+ "Path": "golang.org/x/text",
307
+ "Sum": "h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8=",
308
+ "Version": "v0.41.0"
309
+ }
310
+ ],
311
+ "GoVersion": "go1.26.7",
312
+ "Main": {
313
+ "Path": "github.com/synadia-ai/agent-fabric-sdk/sp",
314
+ "Version": "(devel)"
315
+ },
316
+ "Path": "github.com/synadia-ai/agent-fabric-sdk/sp/cmd/sp",
317
+ "Settings": [
318
+ {
319
+ "Key": "-buildmode",
320
+ "Value": "exe"
321
+ },
322
+ {
323
+ "Key": "-compiler",
324
+ "Value": "gc"
325
+ },
326
+ {
327
+ "Key": "-trimpath",
328
+ "Value": "true"
329
+ },
330
+ {
331
+ "Key": "CGO_ENABLED",
332
+ "Value": "0"
333
+ },
334
+ {
335
+ "Key": "GOARCH",
336
+ "Value": "amd64"
337
+ },
338
+ {
339
+ "Key": "GOOS",
340
+ "Value": "linux"
341
+ },
342
+ {
343
+ "Key": "GOAMD64",
344
+ "Value": "v1"
345
+ }
346
+ ]
347
+ }
348
+ },
349
+ "archives": {
350
+ "darwin/amd64": {
351
+ "archive_sha256": "45061077fd8cd50133b309b0ea49126de938de71f710a6da49e9b236154cd343",
352
+ "binary_sha256": "3d84751719e555218c4f977cdd5b9a5ef149d26421fc7dc6c6ec7b54586d4915"
353
+ },
354
+ "darwin/arm64": {
355
+ "archive_sha256": "995664f10144c170d7ffeb806aef7cfd7110bc2a79c500624028c9122602af2c",
356
+ "binary_sha256": "c4d85f758490a50271b581a42cc78fd9318f7c2393cc97cbd4525773c3107bfe"
357
+ },
358
+ "linux/amd64": {
359
+ "archive_sha256": "cbfd1a6b00c6925edbdda6ea2d62343c86061b5b1412912422850438e390f5e6",
360
+ "binary_sha256": "d03dde699244a13ef24675189dd3452805732d331b92505c120fad0da391b23e"
361
+ },
362
+ "linux/arm64": {
363
+ "archive_sha256": "ad5beca53e15339e9b4505285273a6260730bc52e9dd82c9f01665348432a9d7",
364
+ "binary_sha256": "41e2ae7dfdc614ba3fa8a17ef51da5b8e02d29d4a36b718f428274c6804f9eb3"
365
+ }
366
+ }
367
+ }
@@ -0,0 +1 @@
1
+ 5e518519d1f9af47364cdf5ab01d518c8a195d33
@@ -0,0 +1,231 @@
1
+ #!/bin/sh
2
+ # scripts/sp: the sp command line for an agent on the fabric
3
+ # (`docs/plugins.md` §9.1 in agent-fabric-sdk).
4
+ #
5
+ # Picks the sp binary for this machine from ../bin (`uname -s`, `uname -m`),
6
+ # or takes SCRATCHPAD_BIN, and runs it with what the model must not handle,
7
+ # from the environment the add-on set up at start:
8
+ #
9
+ # --url "$SP_NATS_URL" --creds "$SP_NATS_CREDS" every call
10
+ # --dir "$SCRATCHPAD_DIR" every call, when set
11
+ # --volume "$SCRATCHPAD_VOLUME" `init` only: `read` and `hydrate`
12
+ # refuse a volume other than the
13
+ # reference's
14
+ # --thread-id "$SP_THREAD_ID" every call, when both are set:
15
+ # --root-id "$SP_ROOT_ID" the prompt being served
16
+ # --creator "$SP_CREATOR" `publish-file`, when set
17
+ # --grantee-account "$SP_CALLER_ACCOUNT" `grant`: the agent whose prompt
18
+ # --grantee-user "$SP_CALLER_USER" is being served, and no other
19
+ #
20
+ # A call that passes any of these flags itself is refused, and so is a
21
+ # `grant` with no caller to grant to. Refusals have sp's own shape and exit
22
+ # code: one JSON error on stderr, exit 2, no request sent. Otherwise this
23
+ # runs sp, so sp's exit codes and output pass through.
24
+ #
25
+ # One exception: a `publish-file` while a prompt with a verified caller is
26
+ # served also grants that caller read on what it published, first-hand, as
27
+ # an SDK-built agent grants the caller its reply. The grant's operation id
28
+ # is the publication's with `-caller`, its expiry the publication's. The
29
+ # result is the publication's JSON with `granted_to_caller` (the grant's
30
+ # result) or `caller_grant_error` (sp's error) added; the exit code is the
31
+ # publication's.
32
+ #
33
+ # Every grant this makes and sp confirms, that one or a `grant` of the
34
+ # model's, is recorded in SP_GRANTS_FILE, when set, as one line:
35
+ # `<expires_at> <account> <user> <reference>`. The add-on reads the file
36
+ # when another agent asks it for a grant on this agent's content: the caller
37
+ # granted here may have one more agent granted, as an SDK-built agent's
38
+ # caller may (`grant-request.ts` in the fabric package).
39
+ #
40
+ # Where the add-on cannot set the shell tool's environment (Claude Code's,
41
+ # whose Bash tool is no child of the add-on's process), it writes these
42
+ # variables to a file instead, and SP_ENV_FILE names it: `NAME=value` lines,
43
+ # read on every call, the names above and no others. When the file exists
44
+ # it is the truth: a served prompt's variable it does not name is unset.
45
+
46
+ refuse() {
47
+ msg=$(printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g')
48
+ printf '{"error":{"code":"usage","message":"scripts/sp: %s","unknown":false}}\n' "$msg" >&2
49
+ exit 2
50
+ }
51
+
52
+ # The command: the first argument that is not a flag or a flag's value, as
53
+ # sp itself finds it. Every sp flag but --apply and --help takes a value.
54
+ # On the way, the operation id and the expiry, for the caller's grant after
55
+ # a publication, and the reference, for the record of a grant.
56
+ command=
57
+ operation=
58
+ ttl=600
59
+ given_ref=
60
+ skip=
61
+ for arg in "$@"; do
62
+ if [ -n "$skip" ]; then
63
+ case $skip in
64
+ operation-id) operation=$arg ;;
65
+ ttl-seconds) ttl=$arg ;;
66
+ ref) given_ref=$arg ;;
67
+ esac
68
+ skip=
69
+ continue
70
+ fi
71
+ case $arg in
72
+ --) break ;;
73
+ -apply | --apply | -help | --help | -h) ;;
74
+ -*=*)
75
+ name=${arg%%=*}
76
+ case ${name#-} in
77
+ -operation-id | operation-id) operation=${arg#*=} ;;
78
+ -ttl-seconds | ttl-seconds) ttl=${arg#*=} ;;
79
+ -ref | ref) given_ref=${arg#*=} ;;
80
+ esac
81
+ ;;
82
+ -*) skip=${arg#-}; skip=${skip#-} ;;
83
+ *) [ -z "$command" ] && command=$arg ;;
84
+ esac
85
+ done
86
+
87
+ for arg in "$@"; do
88
+ case $arg in
89
+ --) break ;;
90
+ esac
91
+ name=${arg%%=*}
92
+ name=${name#-}
93
+ name=${name#-}
94
+ case $arg in
95
+ -*)
96
+ case $name in
97
+ url | creds | dir | volume | thread-id | root-id | tool-call-id | creator | grantee-account | grantee-user)
98
+ refuse "--$name is set by the agent, not passed; run the command without it" ;;
99
+ esac
100
+ ;;
101
+ esac
102
+ done
103
+
104
+ if [ -n "${SP_ENV_FILE:-}" ] && [ -f "$SP_ENV_FILE" ]; then
105
+ unset SP_THREAD_ID SP_ROOT_ID SP_CALLER_ACCOUNT SP_CALLER_USER
106
+ while IFS= read -r line || [ -n "$line" ]; do
107
+ case $line in
108
+ *=*)
109
+ case ${line%%=*} in
110
+ SP_NATS_URL | SP_NATS_CREDS | SCRATCHPAD_DIR | SCRATCHPAD_VOLUME | SP_CREATOR | \
111
+ SP_THREAD_ID | SP_ROOT_ID | SP_CALLER_ACCOUNT | SP_CALLER_USER | SP_GRANTS_FILE)
112
+ # The name is one of these; the value is assigned as it is.
113
+ eval "${line%%=*}=\${line#*=}"
114
+ ;;
115
+ esac
116
+ ;;
117
+ esac
118
+ done <"$SP_ENV_FILE"
119
+ fi
120
+
121
+ if [ -n "${SCRATCHPAD_BIN:-}" ]; then
122
+ bin=$SCRATCHPAD_BIN
123
+ else
124
+ case $(uname -s) in
125
+ Darwin) os=darwin ;;
126
+ Linux) os=linux ;;
127
+ *) refuse "unsupported platform $(uname -s) $(uname -m); sp is built for darwin and linux on arm64 and amd64" ;;
128
+ esac
129
+ case $(uname -m) in
130
+ arm64 | aarch64) arch=arm64 ;;
131
+ x86_64 | amd64) arch=amd64 ;;
132
+ *) refuse "unsupported platform $(uname -s) $(uname -m); sp is built for darwin and linux on arm64 and amd64" ;;
133
+ esac
134
+ here=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) || refuse "cannot find the skill directory"
135
+ bin=$here/../bin/sp-$os-$arch
136
+ fi
137
+ [ -x "$bin" ] || refuse "no sp binary at $bin; the add-on package ships one per platform (npm run build:sp)"
138
+
139
+ if [ -z "${SP_NATS_URL:-}" ] || [ -z "${SP_NATS_CREDS:-}" ]; then
140
+ refuse "ScratchPad is not configured for this agent: SP_NATS_URL and SP_NATS_CREDS are unset"
141
+ fi
142
+
143
+ set -- --url "$SP_NATS_URL" --creds "$SP_NATS_CREDS" "$@"
144
+ if [ -n "${SCRATCHPAD_DIR:-}" ]; then
145
+ set -- --dir "$SCRATCHPAD_DIR" "$@"
146
+ fi
147
+ if [ -n "${SP_THREAD_ID:-}" ] && [ -n "${SP_ROOT_ID:-}" ]; then
148
+ set -- --thread-id "$SP_THREAD_ID" --root-id "$SP_ROOT_ID" "$@"
149
+ fi
150
+
151
+ case $command in
152
+ init)
153
+ [ -n "${SCRATCHPAD_VOLUME:-}" ] || refuse "ScratchPad has no volume for this agent: SCRATCHPAD_VOLUME is unset"
154
+ set -- --volume "$SCRATCHPAD_VOLUME" "$@"
155
+ ;;
156
+ publish-file)
157
+ if [ -n "${SP_CREATOR:-}" ]; then
158
+ set -- --creator "$SP_CREATOR" "$@"
159
+ fi
160
+ ;;
161
+ grant)
162
+ if [ -z "${SP_CALLER_ACCOUNT:-}" ] || [ -z "${SP_CALLER_USER:-}" ]; then
163
+ refuse "grant goes only to the agent whose prompt is being served, and no prompt with a verified caller is"
164
+ fi
165
+ set -- --grantee-account "$SP_CALLER_ACCOUNT" --grantee-user "$SP_CALLER_USER" "$@"
166
+ ;;
167
+ esac
168
+
169
+ # Records a grant sp confirmed: $1 the reference, $2 sp's result. A
170
+ # reference that is not one token, or a result without its expiry, is not
171
+ # recorded; nor is anything when the file cannot be written.
172
+ record() {
173
+ [ -n "${SP_GRANTS_FILE:-}" ] || return 0
174
+ case $1 in
175
+ sp-ref:*[!A-Za-z0-9_-]* | sp-ref: | sp-r1:*[!A-Za-z0-9_-]* | sp-r1:) return 0 ;;
176
+ sp-ref:* | sp-r1:*) ;;
177
+ *) return 0 ;;
178
+ esac
179
+ expires=$(printf '%s' "$2" | sed -n 's/.*"expires_at":\([0-9][0-9]*\).*/\1/p')
180
+ [ -n "$expires" ] || return 0
181
+ { printf '%s %s %s %s\n' "$expires" "$SP_CALLER_ACCOUNT" "$SP_CALLER_USER" "$1" \
182
+ >>"$SP_GRANTS_FILE"; } 2>/dev/null || true
183
+ }
184
+
185
+ if [ "$command" = grant ] && [ -n "${SP_GRANTS_FILE:-}" ]; then
186
+ out=$("$bin" "$@")
187
+ status=$?
188
+ [ -n "$out" ] && printf '%s\n' "$out"
189
+ [ $status -eq 0 ] && record "$given_ref" "$out"
190
+ exit $status
191
+ fi
192
+
193
+ if [ "$command" != publish-file ] || [ -z "${SP_CALLER_ACCOUNT:-}" ] || [ -z "${SP_CALLER_USER:-}" ]; then
194
+ exec "$bin" "$@"
195
+ fi
196
+
197
+ # Publish, then grant the served prompt's caller read on it.
198
+ out=$("$bin" "$@")
199
+ status=$?
200
+ if [ $status -ne 0 ]; then
201
+ [ -n "$out" ] && printf '%s\n' "$out"
202
+ exit $status
203
+ fi
204
+ ref=$(printf '%s' "$out" | sed -En 's/.*"reference":"(sp-(ref|r1):[A-Za-z0-9_-]+)".*/\1/p')
205
+ if [ -z "$ref" ]; then
206
+ printf '%s\n' "$out"
207
+ exit 0
208
+ fi
209
+ set -- --url "$SP_NATS_URL" --creds "$SP_NATS_CREDS"
210
+ if [ -n "${SCRATCHPAD_DIR:-}" ]; then
211
+ set -- "$@" --dir "$SCRATCHPAD_DIR"
212
+ fi
213
+ if [ -n "${SP_THREAD_ID:-}" ] && [ -n "${SP_ROOT_ID:-}" ]; then
214
+ set -- "$@" --thread-id "$SP_THREAD_ID" --root-id "$SP_ROOT_ID"
215
+ fi
216
+ errfile=$(mktemp "${TMPDIR:-/tmp}/sp-grant.XXXXXX")
217
+ granted=$("$bin" "$@" grant --ref "$ref" \
218
+ --grantee-account "$SP_CALLER_ACCOUNT" --grantee-user "$SP_CALLER_USER" \
219
+ --operation-id "${operation:-publication}-caller" --ttl-seconds "$ttl" 2>"$errfile")
220
+ gstatus=$?
221
+ gerr=$(cat "$errfile")
222
+ rm -f "$errfile"
223
+ head=$(printf '%s' "$out" | sed 's/}[[:space:]]*$//')
224
+ if [ $gstatus -eq 0 ] && [ -n "$granted" ]; then
225
+ record "$ref" "$granted"
226
+ printf '%s,"granted_to_caller":%s}\n' "$head" "$granted"
227
+ else
228
+ [ -n "$gerr" ] || gerr='{"error":{"code":"unknown","message":"the grant printed nothing","unknown":true}}'
229
+ printf '%s,"caller_grant_error":%s}\n' "$head" "$gerr"
230
+ fi
231
+ exit 0