@stigmer/server 3.22.1-dev.20260922095755 → 3.22.1

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.
Files changed (268) hide show
  1. package/dist/authorization/authorizer.d.ts +8 -4
  2. package/dist/authorization/authorizer.d.ts.map +1 -1
  3. package/dist/authorization/authorizer.js +9 -5
  4. package/dist/authorization/authorizer.js.map +1 -1
  5. package/dist/authorization/derived-tuples.d.ts.map +1 -1
  6. package/dist/authorization/derived-tuples.js +25 -10
  7. package/dist/authorization/derived-tuples.js.map +1 -1
  8. package/dist/authorization/evaluator.d.ts +8 -7
  9. package/dist/authorization/evaluator.d.ts.map +1 -1
  10. package/dist/authorization/evaluator.js +20 -4
  11. package/dist/authorization/evaluator.js.map +1 -1
  12. package/dist/authorization/list-read-scope.d.ts.map +1 -1
  13. package/dist/authorization/list-read-scope.js +9 -5
  14. package/dist/authorization/list-read-scope.js.map +1 -1
  15. package/dist/authorization/model/agent.d.ts.map +1 -1
  16. package/dist/authorization/model/agent.js +5 -4
  17. package/dist/authorization/model/agent.js.map +1 -1
  18. package/dist/authorization/model/agent_instance.d.ts.map +1 -1
  19. package/dist/authorization/model/agent_instance.js +2 -2
  20. package/dist/authorization/model/agent_instance.js.map +1 -1
  21. package/dist/authorization/model/mcp_server.d.ts.map +1 -1
  22. package/dist/authorization/model/mcp_server.js +2 -2
  23. package/dist/authorization/model/mcp_server.js.map +1 -1
  24. package/dist/authorization/model/plugin.d.ts.map +1 -1
  25. package/dist/authorization/model/plugin.js +4 -3
  26. package/dist/authorization/model/plugin.js.map +1 -1
  27. package/dist/authorization/model/rewrite.d.ts +10 -8
  28. package/dist/authorization/model/rewrite.d.ts.map +1 -1
  29. package/dist/authorization/model/rewrite.js +3 -0
  30. package/dist/authorization/model/rewrite.js.map +1 -1
  31. package/dist/authorization/model/skill.d.ts.map +1 -1
  32. package/dist/authorization/model/skill.js +2 -2
  33. package/dist/authorization/model/skill.js.map +1 -1
  34. package/dist/authorization/model/workflow.d.ts.map +1 -1
  35. package/dist/authorization/model/workflow.js +2 -2
  36. package/dist/authorization/model/workflow.js.map +1 -1
  37. package/dist/authorization/model/workflow_instance.d.ts.map +1 -1
  38. package/dist/authorization/model/workflow_instance.js +2 -2
  39. package/dist/authorization/model/workflow_instance.js.map +1 -1
  40. package/dist/authorization/organization-directory.d.ts.map +1 -1
  41. package/dist/authorization/organization-directory.js +3 -2
  42. package/dist/authorization/organization-directory.js.map +1 -1
  43. package/dist/authorization/store-test-kit.d.ts +6 -0
  44. package/dist/authorization/store-test-kit.d.ts.map +1 -1
  45. package/dist/authorization/store-test-kit.js +62 -16
  46. package/dist/authorization/store-test-kit.js.map +1 -1
  47. package/dist/authorization/tuples.d.ts +32 -13
  48. package/dist/authorization/tuples.d.ts.map +1 -1
  49. package/dist/authorization/tuples.js +11 -3
  50. package/dist/authorization/tuples.js.map +1 -1
  51. package/dist/domain/agent/controller.d.ts.map +1 -1
  52. package/dist/domain/agent/controller.js +4 -4
  53. package/dist/domain/agent/controller.js.map +1 -1
  54. package/dist/domain/agentchannel/controller.d.ts.map +1 -1
  55. package/dist/domain/agentchannel/controller.js +1 -3
  56. package/dist/domain/agentchannel/controller.js.map +1 -1
  57. package/dist/domain/agentexecution/controller.d.ts.map +1 -1
  58. package/dist/domain/agentexecution/controller.js +1 -3
  59. package/dist/domain/agentexecution/controller.js.map +1 -1
  60. package/dist/domain/agentinstance/controller.d.ts.map +1 -1
  61. package/dist/domain/agentinstance/controller.js +4 -3
  62. package/dist/domain/agentinstance/controller.js.map +1 -1
  63. package/dist/domain/agentshare/constants.d.ts +11 -6
  64. package/dist/domain/agentshare/constants.d.ts.map +1 -1
  65. package/dist/domain/agentshare/constants.js +16 -8
  66. package/dist/domain/agentshare/constants.js.map +1 -1
  67. package/dist/domain/agentshare/controller.d.ts.map +1 -1
  68. package/dist/domain/agentshare/controller.js +1 -3
  69. package/dist/domain/agentshare/controller.js.map +1 -1
  70. package/dist/domain/agentshare/steps.d.ts +25 -18
  71. package/dist/domain/agentshare/steps.d.ts.map +1 -1
  72. package/dist/domain/agentshare/steps.js +142 -41
  73. package/dist/domain/agentshare/steps.js.map +1 -1
  74. package/dist/domain/environment/controller.d.ts.map +1 -1
  75. package/dist/domain/environment/controller.js +3 -2
  76. package/dist/domain/environment/controller.js.map +1 -1
  77. package/dist/domain/executioncontext/controller.d.ts.map +1 -1
  78. package/dist/domain/executioncontext/controller.js +1 -2
  79. package/dist/domain/executioncontext/controller.js.map +1 -1
  80. package/dist/domain/mcpserver/controller.d.ts.map +1 -1
  81. package/dist/domain/mcpserver/controller.js +4 -3
  82. package/dist/domain/mcpserver/controller.js.map +1 -1
  83. package/dist/domain/plugin/controller.d.ts.map +1 -1
  84. package/dist/domain/plugin/controller.js +3 -1
  85. package/dist/domain/plugin/controller.js.map +1 -1
  86. package/dist/domain/plugin/push.d.ts +5 -7
  87. package/dist/domain/plugin/push.d.ts.map +1 -1
  88. package/dist/domain/plugin/push.js +14 -8
  89. package/dist/domain/plugin/push.js.map +1 -1
  90. package/dist/domain/schedule/controller.d.ts.map +1 -1
  91. package/dist/domain/schedule/controller.js +1 -3
  92. package/dist/domain/schedule/controller.js.map +1 -1
  93. package/dist/domain/session/controller.d.ts.map +1 -1
  94. package/dist/domain/session/controller.js +2 -3
  95. package/dist/domain/session/controller.js.map +1 -1
  96. package/dist/domain/skill/controller.d.ts.map +1 -1
  97. package/dist/domain/skill/controller.js +2 -0
  98. package/dist/domain/skill/controller.js.map +1 -1
  99. package/dist/domain/workflow/controller.d.ts.map +1 -1
  100. package/dist/domain/workflow/controller.js +6 -14
  101. package/dist/domain/workflow/controller.js.map +1 -1
  102. package/dist/domain/workflow/registry/data/task-kind-registry.json +1 -1
  103. package/dist/domain/workflow/validation/task-config-constraints.d.ts +1 -10
  104. package/dist/domain/workflow/validation/task-config-constraints.d.ts.map +1 -1
  105. package/dist/domain/workflow/validation/task-config-constraints.js +2 -3
  106. package/dist/domain/workflow/validation/task-config-constraints.js.map +1 -1
  107. package/dist/domain/workflowexecution/controller.d.ts.map +1 -1
  108. package/dist/domain/workflowexecution/controller.js +2 -4
  109. package/dist/domain/workflowexecution/controller.js.map +1 -1
  110. package/dist/domain/workflowinstance/controller.d.ts.map +1 -1
  111. package/dist/domain/workflowinstance/controller.js +4 -3
  112. package/dist/domain/workflowinstance/controller.js.map +1 -1
  113. package/dist/extensions/authorization-queries.d.ts +5 -6
  114. package/dist/extensions/authorization-queries.d.ts.map +1 -1
  115. package/dist/extensions/list-read-scope.d.ts +1 -1
  116. package/dist/extensions/resource-authorization.d.ts +2 -3
  117. package/dist/extensions/resource-authorization.d.ts.map +1 -1
  118. package/dist/index.d.ts +3 -1
  119. package/dist/index.d.ts.map +1 -1
  120. package/dist/index.js +13 -0
  121. package/dist/index.js.map +1 -1
  122. package/dist/pipeline/apiresource-meta.d.ts +3 -12
  123. package/dist/pipeline/apiresource-meta.d.ts.map +1 -1
  124. package/dist/pipeline/apiresource-meta.js +10 -21
  125. package/dist/pipeline/apiresource-meta.js.map +1 -1
  126. package/dist/pipeline/steps/authorization-tuples.d.ts +3 -9
  127. package/dist/pipeline/steps/authorization-tuples.d.ts.map +1 -1
  128. package/dist/pipeline/steps/authorization-tuples.js +11 -9
  129. package/dist/pipeline/steps/authorization-tuples.js.map +1 -1
  130. package/dist/pipeline/steps/references.d.ts +20 -178
  131. package/dist/pipeline/steps/references.d.ts.map +1 -1
  132. package/dist/pipeline/steps/references.js +43 -344
  133. package/dist/pipeline/steps/references.js.map +1 -1
  134. package/dist/pipeline/steps/visibility-gates.d.ts +27 -0
  135. package/dist/pipeline/steps/visibility-gates.d.ts.map +1 -0
  136. package/dist/pipeline/steps/visibility-gates.js +139 -0
  137. package/dist/pipeline/steps/visibility-gates.js.map +1 -0
  138. package/dist/query/search/controller.js +1 -0
  139. package/dist/query/search/controller.js.map +1 -1
  140. package/dist/query/search/criteria.d.ts +5 -1
  141. package/dist/query/search/criteria.d.ts.map +1 -1
  142. package/dist/query/search/criteria.js +13 -3
  143. package/dist/query/search/criteria.js.map +1 -1
  144. package/dist/query/search/handler.d.ts +4 -5
  145. package/dist/query/search/handler.d.ts.map +1 -1
  146. package/dist/query/search/handler.js +6 -7
  147. package/dist/query/search/handler.js.map +1 -1
  148. package/dist/query/search/query-store.d.ts.map +1 -1
  149. package/dist/query/search/query-store.js +2 -0
  150. package/dist/query/search/query-store.js.map +1 -1
  151. package/dist/store/interface.d.ts +6 -3
  152. package/dist/store/interface.d.ts.map +1 -1
  153. package/dist/store/interface.js.map +1 -1
  154. package/dist/store/postgres/migrations.d.ts +1 -3
  155. package/dist/store/postgres/migrations.d.ts.map +1 -1
  156. package/dist/store/postgres/migrations.js +1 -35
  157. package/dist/store/postgres/migrations.js.map +1 -1
  158. package/dist/store/postgres/store.d.ts.map +1 -1
  159. package/dist/store/postgres/store.js +9 -4
  160. package/dist/store/postgres/store.js.map +1 -1
  161. package/dist/store/sqlite/migrations.d.ts +1 -3
  162. package/dist/store/sqlite/migrations.d.ts.map +1 -1
  163. package/dist/store/sqlite/migrations.js +1 -36
  164. package/dist/store/sqlite/migrations.js.map +1 -1
  165. package/dist/store/sqlite/store.d.ts.map +1 -1
  166. package/dist/store/sqlite/store.js +8 -4
  167. package/dist/store/sqlite/store.js.map +1 -1
  168. package/package.json +6 -6
  169. package/src/authorization/README.md +26 -24
  170. package/src/authorization/__tests__/authorizer.test.ts +9 -10
  171. package/src/authorization/__tests__/derived-tuples.test.ts +11 -4
  172. package/src/authorization/__tests__/evaluator.test.ts +73 -14
  173. package/src/authorization/__tests__/facts.test.ts +2 -2
  174. package/src/authorization/__tests__/fixtures/fga/agent-instance-creation.fga.yaml +185 -0
  175. package/src/authorization/__tests__/fixtures/fga/blueprint-private-visibility.fga.yaml +98 -6
  176. package/src/authorization/__tests__/fixtures/fga/cross-org-share-creation.fga.yaml +98 -0
  177. package/src/authorization/__tests__/fixtures/fga/default-instance-inheritance.fga.yaml +61 -4
  178. package/src/authorization/__tests__/fixtures/fga/mcp-server-authoring.fga.yaml +143 -0
  179. package/src/authorization/__tests__/fixtures/fga/org-admin-owner-inheritance.fga.yaml +21 -1
  180. package/src/authorization/__tests__/fixtures/fga/platform-visibility.fga.yaml +25 -1
  181. package/src/authorization/__tests__/fixtures/fga/public-visibility-setter.fga.yaml +52 -0
  182. package/src/authorization/__tests__/fixtures/fga/workflow-execution-sharing.fga.yaml +3 -1
  183. package/src/authorization/__tests__/list-read-scope.test.ts +17 -18
  184. package/src/authorization/__tests__/store-tests.test.ts +8 -1
  185. package/src/authorization/__tests__/tuples.test.ts +11 -12
  186. package/src/authorization/authorizer.ts +9 -4
  187. package/src/authorization/derived-tuples.ts +31 -14
  188. package/src/authorization/evaluator.ts +44 -8
  189. package/src/authorization/list-read-scope.ts +11 -5
  190. package/src/authorization/model/agent.ts +5 -2
  191. package/src/authorization/model/agent_instance.ts +2 -0
  192. package/src/authorization/model/mcp_server.ts +2 -0
  193. package/src/authorization/model/plugin.ts +4 -1
  194. package/src/authorization/model/rewrite.ts +13 -8
  195. package/src/authorization/model/skill.ts +2 -0
  196. package/src/authorization/model/workflow.ts +2 -0
  197. package/src/authorization/model/workflow_instance.ts +2 -0
  198. package/src/authorization/organization-directory.ts +3 -1
  199. package/src/authorization/store-test-kit.ts +75 -16
  200. package/src/authorization/tuples.ts +39 -16
  201. package/src/domain/agent/__tests__/agent.test.ts +4 -11
  202. package/src/domain/agent/controller.ts +7 -7
  203. package/src/domain/agentchannel/__tests__/agentchannel.test.ts +48 -223
  204. package/src/domain/agentchannel/controller.ts +1 -6
  205. package/src/domain/agentexecution/controller.ts +1 -6
  206. package/src/domain/agentinstance/controller.ts +12 -6
  207. package/src/domain/agentshare/__tests__/agentshare.test.ts +172 -196
  208. package/src/domain/agentshare/__tests__/create-authorization.test.ts +31 -16
  209. package/src/domain/agentshare/constants.ts +26 -14
  210. package/src/domain/agentshare/controller.ts +1 -6
  211. package/src/domain/agentshare/steps.ts +194 -41
  212. package/src/domain/environment/controller.ts +8 -5
  213. package/src/domain/executioncontext/controller.ts +1 -5
  214. package/src/domain/mcpserver/__tests__/mcpserver.test.ts +28 -115
  215. package/src/domain/mcpserver/__tests__/oauth-handshake.test.ts +18 -53
  216. package/src/domain/mcpserver/controller.ts +12 -6
  217. package/src/domain/plugin/controller.ts +8 -1
  218. package/src/domain/plugin/push.ts +16 -8
  219. package/src/domain/schedule/controller.ts +1 -6
  220. package/src/domain/session/controller.ts +4 -12
  221. package/src/domain/skill/controller.ts +7 -0
  222. package/src/domain/workflow/controller.ts +10 -28
  223. package/src/domain/workflow/registry/data/task-kind-registry.json +1 -1
  224. package/src/domain/workflow/validation/task-config-constraints.ts +3 -7
  225. package/src/domain/workflowexecution/controller.ts +2 -7
  226. package/src/domain/workflowinstance/controller.ts +12 -6
  227. package/src/extensions/__tests__/built-in-authorization-composed.test.ts +19 -32
  228. package/src/extensions/__tests__/extension-composition.test.ts +4 -4
  229. package/src/extensions/__tests__/list-read-scope-composed.test.ts +6 -9
  230. package/src/extensions/authorization-queries.ts +5 -6
  231. package/src/extensions/list-read-scope.ts +1 -1
  232. package/src/extensions/resource-authorization.ts +5 -3
  233. package/src/index.ts +14 -0
  234. package/src/pipeline/apiresource-meta.ts +10 -21
  235. package/src/pipeline/steps/__tests__/authorization-tuples.test.ts +31 -18
  236. package/src/pipeline/steps/__tests__/visibility-gates.test.ts +187 -0
  237. package/src/pipeline/steps/authorization-tuples.ts +11 -9
  238. package/src/pipeline/steps/references.ts +70 -578
  239. package/src/pipeline/steps/visibility-gates.ts +174 -0
  240. package/src/query/search/__tests__/criteria.test.ts +4 -0
  241. package/src/query/search/__tests__/query-store.test.ts +40 -11
  242. package/src/query/search/controller.ts +1 -0
  243. package/src/query/search/criteria.ts +14 -0
  244. package/src/query/search/handler.ts +7 -6
  245. package/src/query/search/query-store.ts +2 -0
  246. package/src/store/__tests__/store-contract.ts +51 -6
  247. package/src/store/interface.ts +6 -3
  248. package/src/store/postgres/__tests__/migrations.test.ts +6 -187
  249. package/src/store/postgres/__tests__/store-contract.test.ts +2 -0
  250. package/src/store/postgres/migrations.ts +1 -48
  251. package/src/store/postgres/store.ts +11 -4
  252. package/src/store/sqlite/__tests__/migrations.test.ts +5 -191
  253. package/src/store/sqlite/migrations.ts +1 -45
  254. package/src/store/sqlite/store.ts +10 -4
  255. package/dist/domain/workflow/agent-call-references.d.ts +0 -54
  256. package/dist/domain/workflow/agent-call-references.d.ts.map +0 -1
  257. package/dist/domain/workflow/agent-call-references.js +0 -97
  258. package/dist/domain/workflow/agent-call-references.js.map +0 -1
  259. package/dist/store/public-visibility-retired.d.ts +0 -67
  260. package/dist/store/public-visibility-retired.d.ts.map +0 -1
  261. package/dist/store/public-visibility-retired.js +0 -55
  262. package/dist/store/public-visibility-retired.js.map +0 -1
  263. package/src/domain/workflow/__tests__/agent-call-references.test.ts +0 -222
  264. package/src/domain/workflow/agent-call-references.ts +0 -157
  265. package/src/pipeline/__tests__/supports-visibility.test.ts +0 -112
  266. package/src/pipeline/steps/__tests__/references.test.ts +0 -703
  267. package/src/store/__tests__/public-visibility-retired.test.ts +0 -127
  268. package/src/store/public-visibility-retired.ts +0 -119
@@ -33,10 +33,8 @@ import { AgentCommandController } from "@stigmer/protos/ai/stigmer/agentic/agent
33
33
  import type { Agent } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/api_pb";
34
34
  import { AgentShareCommandController } from "@stigmer/protos/ai/stigmer/agentic/agentshare/v1/command_pb";
35
35
  import { AgentShareQueryController } from "@stigmer/protos/ai/stigmer/agentic/agentshare/v1/query_pb";
36
- import { AgentShareSchema } from "@stigmer/protos/ai/stigmer/agentic/agentshare/v1/api_pb";
37
36
  import type { AgentShare } from "@stigmer/protos/ai/stigmer/agentic/agentshare/v1/api_pb";
38
37
  import { AgentShareAudience } from "@stigmer/protos/ai/stigmer/agentic/agentshare/v1/spec_pb";
39
- import { EnvironmentSchema } from "@stigmer/protos/ai/stigmer/agentic/environment/v1/api_pb";
40
38
  import { SkillSchema } from "@stigmer/protos/ai/stigmer/agentic/skill/v1/api_pb";
41
39
  import { ApiResourceVisibility } from "@stigmer/protos/ai/stigmer/commons/apiresource/enum_pb";
42
40
  import { ApiResourceReferenceSchema } from "@stigmer/protos/ai/stigmer/commons/apiresource/io_pb";
@@ -49,15 +47,11 @@ import { createLogger } from "../../../boot/logger.js";
49
47
  import type { Store } from "../../../store/interface.js";
50
48
  import {
51
49
  ORG_REQUIRED_FOR_LOOKUP_MESSAGE,
52
- sameOrgInvariantMessage,
50
+ crossOrgAudienceMessage,
53
51
  } from "../constants.js";
54
52
  import { findShareByOrgAndSlug, sharingLinkTokenAllowed } from "../steps.js";
55
53
 
56
- const silentLogger = createLogger({
57
- level: "error",
58
- pretty: false,
59
- write: () => {},
60
- });
54
+ const silentLogger = createLogger({ level: "error", pretty: false, write: () => {} });
61
55
 
62
56
  const API_VERSION = "agentic.stigmer.ai/v1";
63
57
 
@@ -74,10 +68,7 @@ let dir: string;
74
68
  beforeAll(async () => {
75
69
  dir = mkdtempSync(path.join(tmpdir(), "agentshare-domain-test-"));
76
70
  vi.stubEnv("STIGMER_ENCRYPTION_KEY", Buffer.alloc(32, 7).toString("base64"));
77
- vi.stubEnv(
78
- "STIGMER_RUNNER_TOKEN_KEY",
79
- Buffer.alloc(32, 8).toString("base64"),
80
- );
71
+ vi.stubEnv("STIGMER_RUNNER_TOKEN_KEY", Buffer.alloc(32, 8).toString("base64"));
81
72
  server = await composeServer({
82
73
  config: loadConfig({
83
74
  STIGMER_MODEL_REGISTRY_REFRESH: "off",
@@ -127,6 +118,13 @@ async function createTestAgent(name: string, org: string): Promise<Agent> {
127
118
  }
128
119
 
129
120
  /** Flips the agent marketplace-public through the real pipeline (D1). */
121
+ async function makeAgentPublic(agent: Agent): Promise<void> {
122
+ await agents.updateVisibility({
123
+ resourceId: agent.metadata!.id,
124
+ visibility: ApiResourceVisibility.visibility_public,
125
+ });
126
+ }
127
+
130
128
  /**
131
129
  * Writes a skill fixture directly to the store — the established
132
130
  * cross-domain fixture pattern (the skill domain is not ported yet, and
@@ -144,12 +142,7 @@ async function saveSkill(
144
142
  kind: "Skill",
145
143
  metadata: { id, name: slug, slug, org, visibility },
146
144
  });
147
- await server.store.saveResource(
148
- ApiResourceKind.skill,
149
- id,
150
- SkillSchema,
151
- skill,
152
- );
145
+ await server.store.saveResource(ApiResourceKind.skill, id, SkillSchema, skill);
153
146
  }
154
147
 
155
148
  /** Minimal canonical share: no slug, no name — both default from the agent. */
@@ -185,10 +178,7 @@ describe("agentshare create", () => {
185
178
  const ORG = "create-test-org";
186
179
 
187
180
  it("canonical share defaults slug and name from the agent; ash_ id; ref normalized", async () => {
188
- const agent = await createTestAgent(
189
- uniqueName("Canonical Default Agent"),
190
- ORG,
191
- );
181
+ const agent = await createTestAgent(uniqueName("Canonical Default Agent"), ORG);
192
182
  const share = await shares.create(shareFor(agent, true));
193
183
 
194
184
  expect(share.metadata?.slug).toBe(agent.metadata!.slug);
@@ -212,20 +202,13 @@ describe("agentshare create", () => {
212
202
  expect(err.rawMessage).toBe("Agent not found: no-such-agent");
213
203
  });
214
204
 
215
- it("an agent_ref naming another organization is FAILED_PRECONDITION with the same-organization copy, before any lookup", async () => {
216
- const agent = await createTestAgent(
217
- uniqueName("Cross Org Ghost Agent"),
218
- ORG,
219
- );
205
+ it("cross-org ref to a nonexistent agent is NOT_FOUND — no cross-org fallback", async () => {
206
+ const agent = await createTestAgent(uniqueName("Cross Org Ghost Agent"), ORG);
220
207
  const share = shareFor(agent, true);
221
- share.spec.agentRef = {
222
- ...share.spec.agentRef,
223
- org: "some-other-org",
224
- } as never;
208
+ share.spec.agentRef = { ...share.spec.agentRef, org: "some-other-org" } as never;
225
209
 
226
210
  const err = await grpcError(() => shares.create(share));
227
- expect(err.code).toBe(Code.FailedPrecondition);
228
- expect(err.rawMessage).toBe(sameOrgInvariantMessage("some-other-org"));
211
+ expect(err.code).toBe(Code.NotFound);
229
212
  });
230
213
 
231
214
  it("stamps the agent-id pin on the created share", async () => {
@@ -253,10 +236,7 @@ describe("agentshare create", () => {
253
236
  });
254
237
 
255
238
  it("second canonical share for the same agent is ALREADY_EXISTS", async () => {
256
- const agent = await createTestAgent(
257
- uniqueName("Duplicate Share Agent"),
258
- ORG,
259
- );
239
+ const agent = await createTestAgent(uniqueName("Duplicate Share Agent"), ORG);
260
240
  await shares.create(shareFor(agent, true));
261
241
 
262
242
  const err = await grpcError(() => shares.create(shareFor(agent, true)));
@@ -268,8 +248,7 @@ describe("agentshare create", () => {
268
248
  await shares.create(shareFor(agent, true));
269
249
 
270
250
  const named = shareFor(agent, true);
271
- (named.metadata as Record<string, string>).name =
272
- uniqueName("Docs Site Channel");
251
+ (named.metadata as Record<string, string>).name = uniqueName("Docs Site Channel");
273
252
  const second = await shares.create(named);
274
253
  expect(second.metadata?.slug).not.toBe(agent.metadata!.slug);
275
254
  });
@@ -285,10 +264,7 @@ describe("launch-gate config", () => {
285
264
  const ORG = "launchgate-test-org";
286
265
 
287
266
  it("allowed_origins and messages persist and round-trip", async () => {
288
- const agent = await createTestAgent(
289
- uniqueName("Launch Gate Config Agent"),
290
- ORG,
291
- );
267
+ const agent = await createTestAgent(uniqueName("Launch Gate Config Agent"), ORG);
292
268
  const created = await shares.create({
293
269
  ...shareFor(agent, true),
294
270
  spec: {
@@ -313,10 +289,7 @@ describe("launch-gate config", () => {
313
289
  });
314
290
 
315
291
  it("malformed origins are INVALID_ARGUMENT", async () => {
316
- const agent = await createTestAgent(
317
- uniqueName("Origin Validation Agent"),
318
- ORG,
319
- );
292
+ const agent = await createTestAgent(uniqueName("Origin Validation Agent"), ORG);
320
293
  for (const origin of [
321
294
  "docs.example.com", // missing scheme
322
295
  "https://example.com/path", // path not allowed
@@ -335,10 +308,7 @@ describe("launch-gate config", () => {
335
308
  });
336
309
 
337
310
  it("overlong custom message is INVALID_ARGUMENT", async () => {
338
- const agent = await createTestAgent(
339
- uniqueName("Message Length Agent"),
340
- ORG,
341
- );
311
+ const agent = await createTestAgent(uniqueName("Message Length Agent"), ORG);
342
312
  const err = await grpcError(() =>
343
313
  shares.create({
344
314
  ...shareFor(agent, true),
@@ -352,27 +322,7 @@ describe("launch-gate config", () => {
352
322
  });
353
323
 
354
324
  it("environment_refs on an org-audience share is INVALID_ARGUMENT; public persists", async () => {
355
- const agent = await createTestAgent(
356
- uniqueName("Env Refs Audience Agent"),
357
- ORG,
358
- );
359
- // The environment must exist when the share is written (the reference rule).
360
- await server.store.saveResource(
361
- ApiResourceKind.environment,
362
- "env_shared_credentials",
363
- EnvironmentSchema,
364
- create(EnvironmentSchema, {
365
- apiVersion: "agentic.stigmer.ai/v1",
366
- kind: "Environment",
367
- metadata: {
368
- id: "env_shared_credentials",
369
- name: "shared-credentials",
370
- slug: "shared-credentials",
371
- org: ORG,
372
- visibility: ApiResourceVisibility.visibility_org,
373
- },
374
- }),
375
- );
325
+ const agent = await createTestAgent(uniqueName("Env Refs Audience Agent"), ORG);
376
326
  const envRef = {
377
327
  kind: ApiResourceKind.environment,
378
328
  org: ORG,
@@ -428,14 +378,8 @@ describe("agentshare update", () => {
428
378
  });
429
379
 
430
380
  it("agent_ref is immutable — FAILED_PRECONDITION with the pinned copy", async () => {
431
- const agentA = await createTestAgent(
432
- uniqueName("Immutable Ref Agent A"),
433
- ORG,
434
- );
435
- const agentB = await createTestAgent(
436
- uniqueName("Immutable Ref Agent B"),
437
- ORG,
438
- );
381
+ const agentA = await createTestAgent(uniqueName("Immutable Ref Agent A"), ORG);
382
+ const agentB = await createTestAgent(uniqueName("Immutable Ref Agent B"), ORG);
439
383
  const created = await shares.create(shareFor(agentA, true));
440
384
 
441
385
  created.spec!.agentRef = create(ApiResourceReferenceSchema, {
@@ -453,83 +397,146 @@ describe("agentshare update", () => {
453
397
  // Cross-org contract (Go TestAgentShareController_CrossOrg, decision 013).
454
398
  // ---------------------------------------------------------------------------
455
399
 
456
- describe("the same-organization invariant", () => {
400
+ describe("cross-org shares (decision 013)", () => {
457
401
  const PROVIDER = "provider-org";
458
402
  const CONSUMER = "consumer-org";
459
403
 
460
- function shareInAnotherOrg(agent: Agent, enabled: boolean) {
404
+ function crossOrgShare(agent: Agent, enabled: boolean) {
461
405
  const share = shareFor(agent, enabled);
462
406
  share.metadata.org = CONSUMER;
463
- share.spec.agentRef = {
464
- ...share.spec.agentRef,
465
- org: agent.metadata!.org,
466
- } as never;
407
+ share.spec.agentRef = { ...share.spec.agentRef, org: agent.metadata!.org } as never;
467
408
  return share;
468
409
  }
469
410
 
470
- it("another organization's agent cannot be shared — the same sentence whether the agent exists or not, at any level", async () => {
471
- const existing = await createTestAgent(
472
- uniqueName("Provider Agent"),
473
- PROVIDER,
474
- );
475
- const err = await grpcError(() =>
476
- shares.create(shareInAnotherOrg(existing, true)),
477
- );
478
- expect(err.code).toBe(Code.FailedPrecondition);
479
- expect(err.rawMessage).toBe(sameOrgInvariantMessage(PROVIDER));
480
-
481
- const ghost = shareFor(existing, true);
482
- ghost.metadata.org = CONSUMER;
483
- ghost.spec.agentRef = {
484
- ...ghost.spec.agentRef,
485
- org: PROVIDER,
486
- slug: "no-such-agent",
487
- } as never;
411
+ it("public agent is shareable cross-org: pin stamped, slug defaulted, profile resolves", async () => {
412
+ const agent = await createTestAgent(uniqueName("Public Provider Agent"), PROVIDER);
413
+ await makeAgentPublic(agent);
414
+
415
+ const created = await shares.create(crossOrgShare(agent, true));
416
+ expect(created.metadata?.org).toBe(CONSUMER);
417
+ expect(created.spec?.agentRef?.org).toBe(PROVIDER);
418
+ expect(created.metadata?.slug).toBe(agent.metadata!.slug);
419
+ expect(created.status?.agentId).toBe(agent.metadata!.id);
420
+
421
+ const profile = await query.getSharedProfile({
422
+ org: CONSUMER,
423
+ slug: created.metadata!.slug,
424
+ });
425
+ expect(profile.org).toBe(CONSUMER);
426
+ expect(profile.name).toBe(agent.metadata!.name);
427
+ });
428
+
429
+ it("non-public agent is NOT_FOUND, indistinguishable from absence", async () => {
430
+ const agent = await createTestAgent(uniqueName("Private Provider Agent"), PROVIDER);
431
+
432
+ const err = await grpcError(() => shares.create(crossOrgShare(agent, true)));
433
+ expect(err.code).toBe(Code.NotFound);
434
+
435
+ // The refusal must match a genuinely missing agent — no existence
436
+ // probe for private slugs (the T09 indistinguishability contract).
437
+ const ghost = crossOrgShare(agent, true);
438
+ ghost.spec.agentRef = { ...ghost.spec.agentRef, org: "empty-provider-org" } as never;
488
439
  const ghostErr = await grpcError(() => shares.create(ghost));
489
- expect(ghostErr.code).toBe(Code.FailedPrecondition);
490
- expect(ghostErr.rawMessage).toBe(sameOrgInvariantMessage(PROVIDER));
440
+ expect(err.rawMessage).toBe(ghostErr.rawMessage);
491
441
  });
492
442
 
493
- it("a stored share whose agent is in another organization fails the profile closed, like a dangling reference", async () => {
494
- const agent = await createTestAgent(
495
- uniqueName("Legacy Provider Agent"),
443
+ it("org audience is refused cross-org, on create and on update", async () => {
444
+ const agent = await createTestAgent(uniqueName("Audience Rule Agent"), PROVIDER);
445
+ await makeAgentPublic(agent);
446
+
447
+ const orgAudience = crossOrgShare(agent, true);
448
+ (orgAudience.spec as Record<string, unknown>).audience = AgentShareAudience.org;
449
+ const createErr = await grpcError(() => shares.create(orgAudience));
450
+ expect(createErr.code).toBe(Code.FailedPrecondition);
451
+ expect(createErr.rawMessage).toBe(crossOrgAudienceMessage(PROVIDER));
452
+
453
+ const created = await shares.create(crossOrgShare(agent, true));
454
+ created.spec!.audience = AgentShareAudience.org;
455
+ const updateErr = await grpcError(() => shares.update(created));
456
+ expect(updateErr.code).toBe(Code.FailedPrecondition);
457
+ expect(updateErr.rawMessage).toBe(crossOrgAudienceMessage(PROVIDER));
458
+ });
459
+
460
+ it("non-public dependencies block creation, naming every blocker sorted", async () => {
461
+ await saveSkill(
462
+ "skl_private_dep",
496
463
  PROVIDER,
464
+ "private-skill",
465
+ ApiResourceVisibility.visibility_private,
497
466
  );
498
- // A row from before the invariant, written straight to the store.
499
- const legacy = create(AgentShareSchema, {
467
+ await saveSkill(
468
+ "skl_public_dep",
469
+ PROVIDER,
470
+ "public-skill",
471
+ ApiResourceVisibility.visibility_public,
472
+ );
473
+
474
+ const agent = await agents.create({
500
475
  apiVersion: API_VERSION,
501
- kind: "AgentShare",
502
- metadata: {
503
- id: "ash_legacy_cross_org",
504
- name: "legacy-cross-org",
505
- slug: "legacy-cross-org",
506
- org: CONSUMER,
507
- },
476
+ kind: "Agent",
477
+ metadata: { name: uniqueName("Tooling Agent"), org: PROVIDER },
508
478
  spec: {
509
- agentRef: {
510
- kind: ApiResourceKind.agent,
511
- org: PROVIDER,
512
- slug: agent.metadata!.slug,
513
- },
514
- enabled: true,
515
- audience: AgentShareAudience.public,
479
+ instructions: "You are a tool-using cross-org test agent.",
480
+ skillRefs: [
481
+ { kind: ApiResourceKind.skill, slug: "private-skill" },
482
+ { kind: ApiResourceKind.skill, slug: "public-skill" },
483
+ ],
516
484
  },
517
- status: { agentId: agent.metadata!.id },
518
485
  });
519
- await server.store.saveResource(
520
- ApiResourceKind.agent_share,
521
- legacy.metadata!.id,
522
- AgentShareSchema,
523
- legacy,
524
- );
486
+ await makeAgentPublic(agent);
525
487
 
526
- const err = await grpcError(() =>
527
- query.getSharedProfile({ org: CONSUMER, slug: "legacy-cross-org" }),
528
- );
488
+ const err = await grpcError(() => shares.create(crossOrgShare(agent, true)));
489
+ expect(err.code).toBe(Code.FailedPrecondition);
490
+ expect(err.rawMessage).toContain("provider-org/private-skill");
491
+ expect(err.rawMessage).not.toContain("public-skill");
492
+
493
+ // Same-org sharing of the same agent stays unaffected — the sweep is
494
+ // a cross-org rule only.
495
+ await shares.create(shareFor(agent, true));
496
+ });
497
+
498
+ it("visibility flip fails the profile closed", async () => {
499
+ const agent = await createTestAgent(uniqueName("Revocable Agent"), PROVIDER);
500
+ await makeAgentPublic(agent);
501
+ const created = await shares.create(crossOrgShare(agent, true));
502
+
503
+ const ref = { org: CONSUMER, slug: created.metadata!.slug };
504
+ await query.getSharedProfile(ref);
505
+
506
+ await agents.updateVisibility({
507
+ resourceId: agent.metadata!.id,
508
+ visibility: ApiResourceVisibility.visibility_private,
509
+ });
510
+
511
+ const err = await grpcError(() => query.getSharedProfile(ref));
529
512
  expect(err.code).toBe(Code.NotFound);
530
- // The row itself is still readable by id — nothing is deleted.
531
- const row = await query.get({ value: legacy.metadata!.id });
532
- expect(row.status?.agentId).toBe(agent.metadata!.id);
513
+ });
514
+
515
+ it("agent delete leaves the cross-org share failing closed; recreate never rebinds", async () => {
516
+ const name = uniqueName("Ephemeral Provider Agent");
517
+ const agent = await createTestAgent(name, PROVIDER);
518
+ await makeAgentPublic(agent);
519
+ const created = await shares.create(crossOrgShare(agent, true));
520
+ const ref = { org: CONSUMER, slug: created.metadata!.slug };
521
+
522
+ await agents.delete({ value: agent.metadata!.id });
523
+
524
+ // The consumer org's share survives the provider's delete (cross-org
525
+ // shares are NOT cascaded — not the provider's resource to destroy)
526
+ // but fails closed.
527
+ const survived = await query.get({ value: created.metadata!.id });
528
+ expect(survived.status?.agentId).toBe(agent.metadata!.id);
529
+ const danglingErr = await grpcError(() => query.getSharedProfile(ref));
530
+ expect(danglingErr.code).toBe(Code.NotFound);
531
+
532
+ // A DIFFERENT public agent later claims the same org/slug: the pin
533
+ // must keep the old share dark.
534
+ const recreated = await createTestAgent(name, PROVIDER);
535
+ await makeAgentPublic(recreated);
536
+ expect(recreated.metadata!.slug).toBe(agent.metadata!.slug);
537
+
538
+ const rebindErr = await grpcError(() => query.getSharedProfile(ref));
539
+ expect(rebindErr.code).toBe(Code.NotFound);
533
540
  });
534
541
  });
535
542
 
@@ -541,18 +548,13 @@ describe("getSharedProfile (anonymous lane)", () => {
541
548
  const ORG = "profile-test-org";
542
549
 
543
550
  it("uniform NotFound across no-share / disabled / deleted; enabled resolves trimmed", async () => {
544
- const agent = await createTestAgent(
545
- uniqueName("Shared Profile Agent"),
546
- ORG,
547
- );
551
+ const agent = await createTestAgent(uniqueName("Shared Profile Agent"), ORG);
548
552
  const ref = { org: ORG, slug: agent.metadata!.slug };
549
553
 
550
554
  // No share yet.
551
555
  const noShareErr = await grpcError(() => query.getSharedProfile(ref));
552
556
  expect(noShareErr.code).toBe(Code.NotFound);
553
- expect(noShareErr.rawMessage).toBe(
554
- `Agent not found: ${agent.metadata!.slug}`,
555
- );
557
+ expect(noShareErr.rawMessage).toBe(`Agent not found: ${agent.metadata!.slug}`);
556
558
 
557
559
  // Enabled share resolves to the trimmed profile — display fields from
558
560
  // the AGENT, URL identity from the SHARE, never the full Agent.
@@ -607,10 +609,7 @@ describe("audience and the member resolution lane", () => {
607
609
  const ORG = "audience-test-org";
608
610
 
609
611
  it("audience persists and round-trips", async () => {
610
- const agent = await createTestAgent(
611
- uniqueName("Audience Round Trip Agent"),
612
- ORG,
613
- );
612
+ const agent = await createTestAgent(uniqueName("Audience Round Trip Agent"), ORG);
614
613
  const created = await shares.create({
615
614
  ...shareFor(agent, true),
616
615
  spec: { ...shareFor(agent, true).spec, audience: AgentShareAudience.org },
@@ -622,15 +621,10 @@ describe("audience and the member resolution lane", () => {
622
621
  });
623
622
 
624
623
  it("member path resolves shares in either audience (OSS: membership always holds)", async () => {
625
- const agent = await createTestAgent(
626
- uniqueName("Member Resolution Agent"),
627
- ORG,
628
- );
624
+ const agent = await createTestAgent(uniqueName("Member Resolution Agent"), ORG);
629
625
  const ref = { org: ORG, slug: agent.metadata!.slug };
630
626
 
631
- const noShareErr = await grpcError(() =>
632
- query.getSharedProfileForMember(ref),
633
- );
627
+ const noShareErr = await grpcError(() => query.getSharedProfileForMember(ref));
634
628
  expect(noShareErr.code).toBe(Code.NotFound);
635
629
 
636
630
  await shares.create({
@@ -643,10 +637,7 @@ describe("audience and the member resolution lane", () => {
643
637
  });
644
638
 
645
639
  it("the ANONYMOUS path collapses an org-audience share to the uniform NotFound (C2 close-out — the proto's audience contract)", async () => {
646
- const agent = await createTestAgent(
647
- uniqueName("Org Audience Anon Agent"),
648
- ORG,
649
- );
640
+ const agent = await createTestAgent(uniqueName("Org Audience Anon Agent"), ORG);
650
641
  await shares.create({
651
642
  ...shareFor(agent, true),
652
643
  spec: { ...shareFor(agent, true).spec, audience: AgentShareAudience.org },
@@ -715,9 +706,7 @@ describe("rotateShareLink", () => {
715
706
 
716
707
  // Capture the no-share NOT_FOUND before creating — the locked-link
717
708
  // refusal must be byte-identical to it.
718
- const noShareErr = await grpcError(() =>
719
- query.getSharedProfile(request("")),
720
- );
709
+ const noShareErr = await grpcError(() => query.getSharedProfile(request("")));
721
710
 
722
711
  const share = await shares.create(shareFor(agent, true));
723
712
 
@@ -725,31 +714,23 @@ describe("rotateShareLink", () => {
725
714
  await query.getSharedProfile(request("stray-token"));
726
715
 
727
716
  // Rotation locks the link: 27 url-safe chars, status-resident.
728
- const rotated = await shares.rotateShareLink({
729
- resourceId: share.metadata!.id,
730
- });
717
+ const rotated = await shares.rotateShareLink({ resourceId: share.metadata!.id });
731
718
  const firstToken = rotated.status?.shareLinkToken ?? "";
732
719
  expect(firstToken).toHaveLength(27);
733
720
  expect(firstToken).toMatch(/^[A-Za-z0-9_-]+$/);
734
721
 
735
- const lockedErr = await grpcError(() =>
736
- query.getSharedProfile(request("")),
737
- );
722
+ const lockedErr = await grpcError(() => query.getSharedProfile(request("")));
738
723
  expect(lockedErr.code).toBe(Code.NotFound);
739
724
  expect(lockedErr.rawMessage).toBe(noShareErr.rawMessage);
740
725
 
741
726
  await query.getSharedProfile(request(firstToken));
742
727
 
743
728
  // Re-rotation kills the previous token.
744
- const reRotated = await shares.rotateShareLink({
745
- resourceId: share.metadata!.id,
746
- });
729
+ const reRotated = await shares.rotateShareLink({ resourceId: share.metadata!.id });
747
730
  const secondToken = reRotated.status?.shareLinkToken ?? "";
748
731
  expect(secondToken).not.toBe(firstToken);
749
732
 
750
- const deadErr = await grpcError(() =>
751
- query.getSharedProfile(request(firstToken)),
752
- );
733
+ const deadErr = await grpcError(() => query.getSharedProfile(request(firstToken)));
753
734
  expect(deadErr.code).toBe(Code.NotFound);
754
735
  await query.getSharedProfile(request(secondToken));
755
736
 
@@ -776,10 +757,7 @@ describe("rotateShareLink", () => {
776
757
  });
777
758
 
778
759
  it("member path stays open for org-audience shares even when a token exists", async () => {
779
- const agent = await createTestAgent(
780
- uniqueName("Org Audience Rotate Agent"),
781
- ORG,
782
- );
760
+ const agent = await createTestAgent(uniqueName("Org Audience Rotate Agent"), ORG);
783
761
  const created = await shares.create({
784
762
  ...shareFor(agent, true),
785
763
  spec: { ...shareFor(agent, true).spec, audience: AgentShareAudience.org },
@@ -800,15 +778,11 @@ describe("rotateShareLink", () => {
800
778
 
801
779
  describe("getByAgent", () => {
802
780
  it("finds the canonical share and a renamed share", async () => {
803
- const agent = await createTestAgent(
804
- uniqueName("Get By Agent Agent"),
805
- "gba-org",
806
- );
781
+ const agent = await createTestAgent(uniqueName("Get By Agent Agent"), "gba-org");
807
782
  const canonical = await shares.create(shareFor(agent, true));
808
783
 
809
784
  const renamed = shareFor(agent, true);
810
- (renamed.metadata as Record<string, string>).name =
811
- uniqueName("Renamed Channel");
785
+ (renamed.metadata as Record<string, string>).name = uniqueName("Renamed Channel");
812
786
  const second = await shares.create(renamed);
813
787
 
814
788
  const list = await query.getByAgent({ agentId: agent.metadata!.id });
@@ -828,21 +802,25 @@ describe("getByAgent", () => {
828
802
  uniqueName("Org Scoped List Agent"),
829
803
  "gba-provider-org",
830
804
  );
805
+ await makeAgentPublic(agent);
831
806
  await shares.create(shareFor(agent, true));
832
- const named = shareFor(agent, true);
833
- named.metadata = { ...named.metadata, name: "second link" } as never;
834
- await shares.create(named);
807
+
808
+ const crossOrg = shareFor(agent, true);
809
+ crossOrg.metadata.org = "gba-consumer-org";
810
+ crossOrg.spec.agentRef = {
811
+ ...crossOrg.spec.agentRef,
812
+ org: agent.metadata!.org,
813
+ } as never;
814
+ await shares.create(crossOrg);
835
815
 
836
816
  const cases: Array<{ org: string; want: number; wantOrg: string }> = [
837
817
  { org: "", want: 2, wantOrg: "" },
838
- { org: "gba-provider-org", want: 2, wantOrg: "gba-provider-org" },
818
+ { org: "gba-provider-org", want: 1, wantOrg: "gba-provider-org" },
819
+ { org: "gba-consumer-org", want: 1, wantOrg: "gba-consumer-org" },
839
820
  { org: "gba-bystander-org", want: 0, wantOrg: "" },
840
821
  ];
841
822
  for (const tt of cases) {
842
- const list = await query.getByAgent({
843
- agentId: agent.metadata!.id,
844
- org: tt.org,
845
- });
823
+ const list = await query.getByAgent({ agentId: agent.metadata!.id, org: tt.org });
846
824
  expect(list.totalCount, `org ${tt.org}`).toBe(tt.want);
847
825
  for (const item of list.items) {
848
826
  if (tt.wantOrg !== "") {
@@ -870,9 +848,7 @@ describe("apply semantics", () => {
870
848
  expect(created.metadata?.id).not.toBe("");
871
849
 
872
850
  const again = shareFor(agent, true);
873
- (again.spec as Record<string, unknown>).allowedOrigins = [
874
- "https://docs.example.com",
875
- ];
851
+ (again.spec as Record<string, unknown>).allowedOrigins = ["https://docs.example.com"];
876
852
  const updated = await shares.apply(again);
877
853
  expect(updated.metadata?.id).toBe(created.metadata!.id);
878
854
  expect(updated.spec?.allowedOrigins).toHaveLength(1);