@anchrd/intel-contract 0.18.0 → 0.20.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/README.md CHANGED
@@ -95,10 +95,15 @@ edge and the tool ends up in the chain. The graph is then refused with
95
95
  `Node <id> is a link and must be attached to a step` — in `title`, per the first item above. A step
96
96
  may hold several links; one link belongs to exactly one step.
97
97
 
98
- ### A flow is not a node, and carries no grants of its own
98
+ ### A flow is not a node, and has its own grant calls
99
99
 
100
- `node_grant_create` addresses nodes. A flow has no grants; it inherits those of the folder it lives
101
- in. To change who reaches a flow, share its folder or move the flow.
100
+ `node_grant_create` addresses nodes; `flow_grant_create` addresses flows. A flow is reached by both:
101
+ the folder it is filed in passes its grants down, and a grant may sit on the flow itself. The two
102
+ add up — the flow grant never replaces what the folder passes down.
103
+
104
+ ⚠️ A grant on one flow reaches **that flow** and nothing else — not the folder, and not the flows it
105
+ calls. `ShareResult` says so: `unrunnable` names the sub-flows the new principal could not start,
106
+ by title where you may see them and by count where you may not.
102
107
 
103
108
  ### Import takes its idempotency key as a header
104
109
 
@@ -899,6 +899,21 @@ export declare const FlowPublishCall: z.ZodObject<{
899
899
  available: z.ZodBoolean;
900
900
  }, z.core.$strict>;
901
901
  export type FlowPublishCall = z.infer<typeof FlowPublishCall>;
902
+ /**
903
+ * What a tool step will be allowed to reach once this version is published (#517).
904
+ *
905
+ * ⚠️ It is in the preview because publishing FREEZES it: from that moment the step's surface is
906
+ * pinned, and a function the provider adds later is not inherited. An author who cannot see the
907
+ * surface before confirming is asked to freeze something they were never shown.
908
+ */
909
+ export declare const FlowPublishTool: z.ZodObject<{
910
+ nodeId: z.ZodString;
911
+ nodeLabel: z.ZodString;
912
+ server: z.ZodString;
913
+ allow: z.ZodNullable<z.ZodArray<z.ZodString>>;
914
+ available: z.ZodBoolean;
915
+ }, z.core.$strict>;
916
+ export type FlowPublishTool = z.infer<typeof FlowPublishTool>;
902
917
  export declare const FlowPublishPreview: z.ZodObject<{
903
918
  flowId: z.ZodString;
904
919
  versionId: z.ZodString;
@@ -917,6 +932,13 @@ export declare const FlowPublishPreview: z.ZodObject<{
917
932
  freezes: z.ZodBoolean;
918
933
  available: z.ZodBoolean;
919
934
  }, z.core.$strict>>;
935
+ tools: z.ZodArray<z.ZodObject<{
936
+ nodeId: z.ZodString;
937
+ nodeLabel: z.ZodString;
938
+ server: z.ZodString;
939
+ allow: z.ZodNullable<z.ZodArray<z.ZodString>>;
940
+ available: z.ZodBoolean;
941
+ }, z.core.$strict>>;
920
942
  }, z.core.$strict>;
921
943
  export type FlowPublishPreview = z.infer<typeof FlowPublishPreview>;
922
944
  export declare const RelationNodeKind: z.ZodEnum<{
@@ -86,8 +86,18 @@ export const FlowNode = z.discriminatedUnion("kind", [
86
86
  * step's instruction and can only be known while the flow runs.
87
87
  *
88
88
  * `allow: null` means every function of that server. A list narrows it, and every entry has to
89
- * belong to `server` — checked below, because a name from another server would silently widen
90
- * the step past the one thing this configuration is supposed to bound.
89
+ * belong to `server` — checked below, because a name from another server would make the step ask
90
+ * for something the portal routes somewhere else entirely.
91
+ *
92
+ * ⚠️ `allow` is an INSTRUCTION to the agent, not a boundary Intel enforces (#518). Intel is a
93
+ * library: it says what is to be done, it does not execute. A flow is carried out by an agent
94
+ * that reaches the portal with its OWN token, and that agent may call the portal directly —
95
+ * Intel never sees the call. What bounds it is the agent's own portal grant, checked by the
96
+ * portal on every call; what `allow` does is tell the agent which of those functions this step
97
+ * is meant to use, the same way an instruction step tells it what to write.
98
+ *
99
+ * That is not a gap to be closed by adding a check here. Enforcing it would mean routing every
100
+ * call through Intel and making it the executor — the one thing this product is not.
91
101
  *
92
102
  * ⚠️ There is deliberately no `arguments` field any more. Arguments are produced at run time and
93
103
  * validated against the tool's own `inputSchema` from a live `tools/list`; a stored copy would be
@@ -405,14 +415,32 @@ export const FlowPublishCall = z.strictObject({
405
415
  // The callee has a published version to be called at all. `false` is what publishing will refuse.
406
416
  available: z.boolean(),
407
417
  });
418
+ /**
419
+ * What a tool step will be allowed to reach once this version is published (#517).
420
+ *
421
+ * ⚠️ It is in the preview because publishing FREEZES it: from that moment the step's surface is
422
+ * pinned, and a function the provider adds later is not inherited. An author who cannot see the
423
+ * surface before confirming is asked to freeze something they were never shown.
424
+ */
425
+ export const FlowPublishTool = z.strictObject({
426
+ nodeId: FlowNodeId,
427
+ nodeLabel: z.string().min(1).max(160),
428
+ server: ToolServerHandle,
429
+ // `null` is "every function of that server". A list is what the step narrowed itself to, and it
430
+ // is spelled out rather than counted: the whole point of the preview is that a human can read it.
431
+ allow: z.array(ToolName).nullable(),
432
+ // The server is reachable for the person publishing. `false` is what publishing will refuse.
433
+ available: z.boolean(),
434
+ });
408
435
  export const FlowPublishPreview = z.strictObject({
409
436
  flowId: IntelId,
410
437
  versionId: IntelId,
411
438
  calls: z.array(FlowPublishCall),
439
+ tools: z.array(FlowPublishTool),
412
440
  });
413
- // A flow has no share schema of its own. A grant sits on the folder a flow is filed in and inherits
414
- // down from there (ADR-0004 §2); a narrower grant beside it would destroy the subtree guarantee
415
- // section 3 rests on, so per-flow grants were removed rather than deprecated.
441
+ // A flow's own sharing schemas live in `share.ts` beside the node's (#530): `ShareFlowInput`,
442
+ // `RevokeFlowGrantInput`, `ListFlowGrantsInput`. They are there rather than here because a grant is
443
+ // one subject with two kinds of target, not two features and `ShareResult` answers for both.
416
444
  // What accesses what, for one level of the shared tree (#19). A folder answers it for its contents,
417
445
  // a single flow for itself. Documents and flows are two kinds of thing that share one tree
418
446
  // (ADR-0004 §1), so the graph carries both and says which of them it is.
@@ -20,6 +20,10 @@ export declare const ListGrantsInput: z.ZodObject<{
20
20
  resourceId: z.ZodString;
21
21
  }, z.core.$strict>;
22
22
  export type ListGrantsInput = z.infer<typeof ListGrantsInput>;
23
+ export declare const ListFlowGrantsInput: z.ZodObject<{
24
+ flowId: z.ZodString;
25
+ }, z.core.$strict>;
26
+ export type ListFlowGrantsInput = z.infer<typeof ListFlowGrantsInput>;
23
27
  export declare const ResourceGrant: z.ZodObject<{
24
28
  id: z.ZodString;
25
29
  resourceId: z.ZodString;
@@ -70,6 +74,33 @@ export declare const RevokeGrantInput: z.ZodObject<{
70
74
  idempotencyKey: z.ZodString;
71
75
  }, z.core.$strict>;
72
76
  export type RevokeGrantInput = z.infer<typeof RevokeGrantInput>;
77
+ export declare const ShareFlowInput: z.ZodObject<{
78
+ flowId: z.ZodString;
79
+ principal: z.ZodDiscriminatedUnion<[z.ZodObject<{
80
+ type: z.ZodLiteral<"user">;
81
+ id: z.ZodString;
82
+ }, z.core.$strict>, z.ZodObject<{
83
+ type: z.ZodLiteral<"email">;
84
+ email: z.ZodEmail;
85
+ }, z.core.$strict>, z.ZodObject<{
86
+ type: z.ZodLiteral<"organization">;
87
+ }, z.core.$strict>], "type">;
88
+ verb: z.ZodEnum<{
89
+ read: "read";
90
+ write: "write";
91
+ execute: "execute";
92
+ share: "share";
93
+ }>;
94
+ expiresAt: z.ZodDefault<z.ZodNullable<z.ZodISODateTime>>;
95
+ idempotencyKey: z.ZodString;
96
+ }, z.core.$strict>;
97
+ export type ShareFlowInput = z.infer<typeof ShareFlowInput>;
98
+ export declare const RevokeFlowGrantInput: z.ZodObject<{
99
+ flowId: z.ZodString;
100
+ grantId: z.ZodString;
101
+ idempotencyKey: z.ZodString;
102
+ }, z.core.$strict>;
103
+ export type RevokeFlowGrantInput = z.infer<typeof RevokeFlowGrantInput>;
73
104
  export declare const UnreadableNodes: z.ZodObject<{
74
105
  titles: z.ZodArray<z.ZodString>;
75
106
  hidden: z.ZodNumber;
@@ -102,6 +133,10 @@ export declare const ShareResult: z.ZodObject<{
102
133
  titles: z.ZodArray<z.ZodString>;
103
134
  hidden: z.ZodNumber;
104
135
  }, z.core.$strict>;
136
+ unrunnable: z.ZodDefault<z.ZodObject<{
137
+ titles: z.ZodArray<z.ZodString>;
138
+ hidden: z.ZodNumber;
139
+ }, z.core.$strict>>;
105
140
  }, z.core.$strict>;
106
141
  export type ShareResult = z.infer<typeof ShareResult>;
107
142
  export declare const ResourceGrantList: z.ZodObject<{
@@ -17,6 +17,12 @@ export const SharePrincipal = z.discriminatedUnion("type", [
17
17
  export const ListGrantsInput = z.strictObject({
18
18
  resourceId: IntelId.describe("Node whose direct grants to list. Access inherited from a folder above is not a grant on this node and is not listed here."),
19
19
  });
20
+ // The same three shapes for a flow (#530). Separate inputs rather than a widened `resourceId`,
21
+ // because the id names a different table and a caller that passes the wrong kind should be told so
22
+ // by the route it called rather than by a lookup that finds nothing.
23
+ export const ListFlowGrantsInput = z.strictObject({
24
+ flowId: IntelId.describe("Flow whose direct grants to list. Access inherited from the folder it is filed in is not a grant on this flow and is not listed here."),
25
+ });
20
26
  export const ResourceGrant = z.strictObject({
21
27
  id: IntelId,
22
28
  resourceId: IntelId,
@@ -40,6 +46,20 @@ export const RevokeGrantInput = z.strictObject({
40
46
  grantId: IntelId.describe("The grant to withdraw, from node_grant_list."),
41
47
  idempotencyKey: IdempotencyKey,
42
48
  });
49
+ export const ShareFlowInput = z.strictObject({
50
+ flowId: IntelId.describe("Flow to grant access to. A grant here reaches this flow and nothing else — not the folder it is filed in, and not the flows it calls."),
51
+ principal: SharePrincipal.describe("Who gets the access: a Gate user by id, someone by verified email address, or the whole organization."),
52
+ verb: ResourceVerb.describe("What they may do. Each verb is granted on its own and none implies another: `read` opens the flow, `write` edits it, `execute` runs it, `share` passes access on."),
53
+ expiresAt: IsoDateTime.nullable()
54
+ .default(null)
55
+ .describe("When the grant stops working, or `null` for one that does not expire on its own."),
56
+ idempotencyKey: IdempotencyKey,
57
+ });
58
+ export const RevokeFlowGrantInput = z.strictObject({
59
+ flowId: IntelId.describe("Flow the grant sits on. Named alongside the grant id so access is decided on the flow."),
60
+ grantId: IntelId.describe("The grant to withdraw, from flow_grant_list."),
61
+ idempotencyKey: IdempotencyKey,
62
+ });
43
63
  // What a grant does not cover, reported to whoever just made it. A flow in the shared folder may
44
64
  // read a document outside it, and the run is re-authorized against the person running it — so the
45
65
  // grant can be complete and the flow still stop for them (ADR-0004 §4).
@@ -53,9 +73,17 @@ export const UnreadableNodes = z.strictObject({
53
73
  // The grant is in the answer, so the warning cannot be mistaken for a refusal: it is written first
54
74
  // and described afterwards. Blocking would force everyone who uses a central policy document to
55
75
  // duplicate it, which is the opposite of what one tree is for (ADR-0004 §4).
76
+ //
77
+ // ⚠️ `unrunnable` is the second half of the same sentence and belongs to the flow grant (#530). A
78
+ // grant on a folder covered every flow beneath it, so there was nothing to say; a grant on one flow
79
+ // reaches that flow and stops, and the sub-flows it calls are then somebody else's to grant. It
80
+ // carries the shape of `UnreadableNodes` because it answers the same question — what this grant
81
+ // does NOT reach, named where the sharer may see it and counted where they may not — and it is
82
+ // empty for every node grant.
56
83
  export const ShareResult = z.strictObject({
57
84
  grant: ResourceGrant,
58
85
  unreadable: UnreadableNodes,
86
+ unrunnable: UnreadableNodes.default({ titles: [], hidden: 0 }),
59
87
  });
60
88
  // `applicableVerbs` travels with the list because the answer is the business layer's, not the
61
89
  // screen's: a document has nothing to execute, so `execute` is not offered on one (ADR-0004 §2).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anchrd/intel-contract",
3
- "version": "0.18.0",
3
+ "version": "0.20.0",
4
4
  "type": "module",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {