@ziggs-ai/ziggs-mcp 0.3.2 → 0.5.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/dist/capabilityAdapter.d.ts +25 -0
- package/dist/capabilityAdapter.js +75 -0
- package/dist/inboxToolResult.d.ts +8 -8
- package/dist/inboxToolResult.js +35 -78
- package/dist/paymentTools.d.ts +9 -8
- package/dist/paymentTools.js +12 -248
- package/dist/tools.js +54 -279
- package/dist/trustTools.d.ts +4 -1
- package/dist/trustTools.js +14 -272
- package/package.json +3 -3
- package/dist/orgs.d.ts +0 -28
- package/dist/orgs.js +0 -44
package/dist/trustTools.js
CHANGED
|
@@ -1,227 +1,18 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { READ_ONLY, WRITE, DESTRUCTIVE } from './toolAnnotations.js';
|
|
2
|
+
import { ContextGrantsClient, addChatMember, contextBounds, resolveOrgScopeId, LINK_CAPABILITIES, DISCOVERY_CAPABILITIES, contextDelegateCapability, } from '@ziggs-ai/api-client';
|
|
3
|
+
import { WRITE, DESTRUCTIVE } from './toolAnnotations.js';
|
|
5
4
|
import { toolError } from './toolError.js';
|
|
6
|
-
|
|
7
|
-
return {
|
|
8
|
-
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
9
|
-
};
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* Human/LLM-readable bounds for a context grant. ZIG-646 folded a context
|
|
13
|
-
* grant's temporal mode + read watermark into the canonical `caveats` array,
|
|
14
|
-
* so pull them back out here to keep this tool's `bounds` summary stable.
|
|
15
|
-
*/
|
|
16
|
-
function contextBounds(grant) {
|
|
17
|
-
return {
|
|
18
|
-
temporal: grantCaveat(grant, 'temporal'),
|
|
19
|
-
watermarkAt: grantCaveat(grant, 'watermark_at'),
|
|
20
|
-
expiresAt: grant.expiresAt,
|
|
21
|
-
};
|
|
22
|
-
}
|
|
5
|
+
import { registerCapabilities, registerCapability, textResult } from './capabilityAdapter.js';
|
|
23
6
|
const grantScopeKindSchema = z.enum(['chat', 'agreement', 'org']);
|
|
24
7
|
const contextTemporalSchema = z.enum(['from-now', 'from-start']);
|
|
25
8
|
const DEFAULT_WEB_URL = 'https://ziggsai.com';
|
|
26
|
-
/**
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* Ambiguous names return the candidate list rather than guessing; a name that
|
|
31
|
-
* matched nothing errors with a pointer to ziggs_list_my_orgs. An org_... id
|
|
32
|
-
* that is not a membership passes through unchanged — you may hold a grant on
|
|
33
|
-
* an org you do not belong to, so the server stays the authority on the id.
|
|
34
|
-
*/
|
|
35
|
-
async function resolveOrgScope(creds, scopeId) {
|
|
36
|
-
const resolution = resolveOrgSelector(await fetchMyOrgs(creds), scopeId);
|
|
37
|
-
if (resolution.status === 'ok')
|
|
38
|
-
return { scopeId: resolution.orgId };
|
|
39
|
-
if (resolution.status === 'ambiguous') {
|
|
40
|
-
return {
|
|
41
|
-
error: toolError(`Org name "${scopeId}" matches ${resolution.matches.length} of your orgs — pass the org id: ` +
|
|
42
|
-
resolution.matches.map((m) => `${m.name} (${m.orgId})`).join(', ')),
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
if (scopeId.startsWith('org_'))
|
|
46
|
-
return { scopeId };
|
|
47
|
-
return {
|
|
48
|
-
error: toolError(`No org named "${scopeId}" in your memberships — use ziggs_list_my_orgs to see them, or pass the org id.`),
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
// ZIG-941 #7 — the link tool group, pulled out so the lean session-start
|
|
52
|
-
// tier (ZIGGS_MCP_CORE_ONLY) can skip it. Registration is unchanged.
|
|
53
|
-
function registerLinkTools(server, creds, webUrl) {
|
|
54
|
-
server.tool('ziggs_request_link', 'Request a bilateral trust link with another agent before cross-org reach (party-to-party, NOT a third-party service connection — see ziggs_list_my_connections for that). A link is just an agreement (POST /agreements {engagementKind:"link"}). The target OWNER must approve it (via ziggs_respond_to_agreement) before unpublished delegates can message each other.', {
|
|
55
|
-
providerId: z
|
|
56
|
-
.string()
|
|
57
|
-
.describe('Bare agent id to link with (the target delegate). Use ziggs_search_agents or a known delegate id — do not guess.'),
|
|
58
|
-
message: z
|
|
59
|
-
.string()
|
|
60
|
-
.optional()
|
|
61
|
-
.describe('Optional note shown to the counterparty human on approval (agreement description)'),
|
|
62
|
-
}, WRITE, async ({ providerId, message }) => {
|
|
63
|
-
try {
|
|
64
|
-
const { agreement } = await createAgreement({ engagementKind: 'link', providerId, description: message }, creds);
|
|
65
|
-
return textResult({
|
|
66
|
-
status: 'pending',
|
|
67
|
-
message: 'Link agreement created — the counterparty owner must approve (ziggs_respond_to_agreement) before cross-org reach. Surface pending state to the human.',
|
|
68
|
-
agreement,
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
catch (e) {
|
|
72
|
-
return toolError(e.message);
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
server.tool('ziggs_create_link_invite', 'Create a shareable OPEN link invite (bilateral agent-to-agent trust, NOT a third-party service connection — see ziggs_list_my_connections for that) when you do NOT have the counterparty\'s agent id (e.g. connecting across orgs). Creates an open link agreement (POST /agreements {engagementKind:"link"}, proposedTo:"everyone"). Share the returned inviteId (agreementId) out-of-band; the recipient forms the link by calling ziggs_claim_link_invite — neither side pastes an agent id. Revoke via ziggs_revoke_link to disable.', {
|
|
76
|
-
message: z
|
|
77
|
-
.string()
|
|
78
|
-
.optional()
|
|
79
|
-
.describe('Optional note shown to whoever opens the invite (agreement description)'),
|
|
80
|
-
}, WRITE, async ({ message }) => {
|
|
81
|
-
try {
|
|
82
|
-
const { agreement } = await createAgreement({ engagementKind: 'link', description: message }, creds);
|
|
83
|
-
return textResult({
|
|
84
|
-
status: 'open',
|
|
85
|
-
inviteId: agreement.agreementId,
|
|
86
|
-
claimUrl: `${webUrl}/app/link-invites/${agreement.agreementId}`,
|
|
87
|
-
message: 'Open link invite created. Share claimUrl with the counterparty — they open it in the Ziggs web app to claim and activate the link. No agent id needed on either side.',
|
|
88
|
-
agreement,
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
catch (e) {
|
|
92
|
-
return toolError(e.message);
|
|
93
|
-
}
|
|
94
|
-
});
|
|
95
|
-
server.tool('ziggs_claim_link_invite', 'Claim an open link invite by its id to form a bilateral link (agent-to-agent trust, NOT a third-party service connection — see ziggs_list_my_connections for that) (POST /agreements/:id/claim). You become the counterparty and the link activates immediately (cross-org reach + bilateral context grants). You cannot claim your own invite.', {
|
|
96
|
-
agreementId: z
|
|
97
|
-
.string()
|
|
98
|
-
.describe('The invite id (agreementId) shared by the issuer'),
|
|
99
|
-
}, WRITE, async ({ agreementId }) => {
|
|
100
|
-
try {
|
|
101
|
-
const { agreement } = await claimAgreement(agreementId, creds);
|
|
102
|
-
return textResult({
|
|
103
|
-
status: 'linked',
|
|
104
|
-
message: 'Link invite claimed — you are now linked. A link is reach-only: open a chat with the peer (ziggs_open_conversation) and grant it chat access with ziggs_issue_grant, or share a slice of a grant you already hold with ziggs_delegate_grant, before reading context.',
|
|
105
|
-
agreement,
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
catch (e) {
|
|
109
|
-
return toolError(e.message);
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
server.tool('ziggs_list_links', 'List link agreements for this delegate — bilateral agent-to-agent trust relationships, NOT third-party service connections (see ziggs_list_my_connections for those) (GET /agreements?engagementKind=link). Defaults to ACTIVE links only; pass status to see pending proposals ("open") or revoked ones ("cancelled"). Each item is a link summary: agreementId, status, proposalStatus, parties.creatorAgent (requester), parties.providerAgent (target), parties.proposedTo (target owner). Approve pending links via ziggs_respond_to_agreement.', {
|
|
113
|
-
status: z
|
|
114
|
-
.enum(['active', 'open', 'cancelled', 'all'])
|
|
115
|
-
.optional()
|
|
116
|
-
.describe('active (default) = established links; open = pending proposals/invites awaiting approval or claim; cancelled = revoked; all = every link regardless of status'),
|
|
117
|
-
}, READ_ONLY, async ({ status }) => {
|
|
118
|
-
try {
|
|
119
|
-
const resolvedStatus = status ?? 'active';
|
|
120
|
-
const links = await listAgreements({
|
|
121
|
-
engagementKind: 'link',
|
|
122
|
-
...(resolvedStatus === 'all' ? {} : { status: resolvedStatus }),
|
|
123
|
-
}, creds);
|
|
124
|
-
// ZIG-670: link-shaped summaries, not raw agreement documents — the
|
|
125
|
-
// money block, approvals array, and Mongo internals are noise here.
|
|
126
|
-
const summaries = links.map((a) => ({
|
|
127
|
-
agreementId: a.agreementId,
|
|
128
|
-
status: a.status,
|
|
129
|
-
proposalStatus: a.proposalStatus,
|
|
130
|
-
parties: {
|
|
131
|
-
creatorAgent: a.parties?.creatorAgent ?? null,
|
|
132
|
-
providerAgent: a.parties?.providerAgent ?? null,
|
|
133
|
-
creator: a.parties?.creator ?? null,
|
|
134
|
-
proposedTo: a.parties?.proposedTo ?? null,
|
|
135
|
-
},
|
|
136
|
-
...(a.description ? { description: a.description } : {}),
|
|
137
|
-
createdAt: a.createdAt,
|
|
138
|
-
}));
|
|
139
|
-
const hasActive = links.some((a) => a.status === 'active');
|
|
140
|
-
return textResult({
|
|
141
|
-
count: summaries.length,
|
|
142
|
-
status: resolvedStatus,
|
|
143
|
-
links: summaries,
|
|
144
|
-
...(hasActive
|
|
145
|
-
? {
|
|
146
|
-
nextSteps: 'A link is reach-only. Open a chat with the peer (ziggs_open_conversation, participantId = peer agent id) and grant it chat access with ziggs_issue_grant, or share a slice of a grant you hold with ziggs_delegate_grant, before reading context.',
|
|
147
|
-
}
|
|
148
|
-
: {}),
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
catch (e) {
|
|
152
|
-
return toolError(e.message);
|
|
153
|
-
}
|
|
154
|
-
});
|
|
155
|
-
server.tool('ziggs_revoke_link', 'Revoke a bilateral link agreement — agent-to-agent trust, NOT a third-party service connection (DELETE /agreements/:agreementId). Either party may revoke; cross-org reach ends immediately. For non-link agreements (hire/service/quest), use ziggs_revoke_agreement — same endpoint, different messaging.', {
|
|
156
|
-
agreementId: z
|
|
157
|
-
.string()
|
|
158
|
-
.describe('agreementId of the link agreement (from ziggs_list_links)'),
|
|
159
|
-
}, DESTRUCTIVE, async ({ agreementId }) => {
|
|
160
|
-
try {
|
|
161
|
-
const result = await revokeAgreement(agreementId, creds);
|
|
162
|
-
return textResult({
|
|
163
|
-
status: 'revoked',
|
|
164
|
-
message: 'Link revoked — unpublished cross-org reach to this peer is blocked again.',
|
|
165
|
-
agreementId,
|
|
166
|
-
agreement: result.agreement,
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
catch (e) {
|
|
170
|
-
return toolError(e.message);
|
|
171
|
-
}
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
/** ZIG-433 — agent search + context grant management through MCP. */
|
|
9
|
+
/** ZIG-433 / ZIG-956 — agent search + context grant management through MCP.
|
|
10
|
+
* The SDK-twin tools (search/get, links, delegate) come from the shared
|
|
11
|
+
* capability layer; only the human-authority grant tools (issue/revoke) stay
|
|
12
|
+
* MCP-local. */
|
|
175
13
|
export function registerTrustTools(server, creds, cfg) {
|
|
176
14
|
const webUrl = cfg?.ZIGGS_WEB_URL?.replace(/\/$/, '') ?? DEFAULT_WEB_URL;
|
|
177
|
-
server
|
|
178
|
-
query: z.string().describe('Keyword/natural-language search (published store + your org-mates + your linked delegates) OR an exact agent id (resolves that agent even if unpublished, when you can reach it)'),
|
|
179
|
-
limit: z.number().optional().describe('Max results (default server-side)'),
|
|
180
|
-
minScore: z.number().optional().describe('Minimum match score filter'),
|
|
181
|
-
}, READ_ONLY, async ({ query, limit, minScore }) => {
|
|
182
|
-
try {
|
|
183
|
-
const client = new AgentSearchClient(creds.operatorKey, creds.agentId);
|
|
184
|
-
const result = await client.searchAgents(query, { limit, minScore });
|
|
185
|
-
if (!result.success) {
|
|
186
|
-
return toolError(result.error ?? result.message ?? 'search failed');
|
|
187
|
-
}
|
|
188
|
-
if (!result.agents?.length) {
|
|
189
|
-
// ZIG-664: a bare {count: 0} reads as "discovery is down" to LLM
|
|
190
|
-
// callers — say what was searched and how to recover instead.
|
|
191
|
-
return textResult({
|
|
192
|
-
count: 0,
|
|
193
|
-
agents: [],
|
|
194
|
-
searched: ['published store', 'your org-mates', 'your linked delegates'],
|
|
195
|
-
hint: 'Zero hits means no agent profile matched these terms — discovery itself is up. ' +
|
|
196
|
-
'Matching is lexical against agent name/description/tags, so try shorter or different keywords. ' +
|
|
197
|
-
'If you already know the agent, pass its exact agent id as the query to resolve it directly.',
|
|
198
|
-
});
|
|
199
|
-
}
|
|
200
|
-
return textResult({
|
|
201
|
-
count: result.agents.length,
|
|
202
|
-
agents: result.agents,
|
|
203
|
-
});
|
|
204
|
-
}
|
|
205
|
-
catch (e) {
|
|
206
|
-
return toolError(e.message);
|
|
207
|
-
}
|
|
208
|
-
});
|
|
209
|
-
server.tool('ziggs_get_agent', 'Fetch the full profile of ONE agent by its exact id (GET /agents/:id) — name, description, tags, capabilities, reachability, and reliability. Use to confirm a candidate before ziggs_propose_agreement / ziggs_request_link, when you already hold the agent id (from ziggs_search_agents, a grant, or an agreement party). Grant-scoped: an id you cannot reach returns reachability "restricted" (id only, no profile). To find an agent by keyword instead, use ziggs_search_agents.', {
|
|
210
|
-
agentId: z.string().describe('Exact agent id to fetch — do not guess'),
|
|
211
|
-
}, READ_ONLY, async ({ agentId }) => {
|
|
212
|
-
try {
|
|
213
|
-
const client = new AgentSearchClient(creds.operatorKey, creds.agentId);
|
|
214
|
-
const result = await client.getAgentById(agentId);
|
|
215
|
-
if (!result.success) {
|
|
216
|
-
return toolError(result.error ?? 'agent not found');
|
|
217
|
-
}
|
|
218
|
-
const { success: _success, ...agent } = result;
|
|
219
|
-
return textResult({ agent });
|
|
220
|
-
}
|
|
221
|
-
catch (e) {
|
|
222
|
-
return toolError(e.message);
|
|
223
|
-
}
|
|
224
|
-
});
|
|
15
|
+
registerCapabilities(server, DISCOVERY_CAPABILITIES, creds);
|
|
225
16
|
server.tool('ziggs_issue_grant', 'Issue bounded context access. Chat scope: admits agent via POST /chats/:id/members (agent-invite → pending_approval until humans consent) — this works for you as a delegate. Agreement/org scope: issuing a NEW root grant is a human-authority action; if you are acting for a principal you are denied (AGENT_LACKS_HUMAN_AUTHORITY) — instead use ziggs_delegate_grant to hand a peer a narrower slice of a grant you already hold, or ask your human to issue it. Defaults: from-now, narrow scope.', {
|
|
226
17
|
holderId: z.string().describe('Bare agent id receiving the grant'),
|
|
227
18
|
scopeKind: grantScopeKindSchema,
|
|
@@ -269,10 +60,7 @@ export function registerTrustTools(server, creds, cfg) {
|
|
|
269
60
|
// ZIG-941 #6 — an org scope may be named rather than pasted as org_… id.
|
|
270
61
|
let resolvedScopeId = scopeId;
|
|
271
62
|
if (scopeKind === 'org') {
|
|
272
|
-
|
|
273
|
-
if ('error' in resolved)
|
|
274
|
-
return resolved.error;
|
|
275
|
-
resolvedScopeId = resolved.scopeId;
|
|
63
|
+
resolvedScopeId = await resolveOrgScopeId({ creds, surface: 'mcp' }, scopeId);
|
|
276
64
|
}
|
|
277
65
|
const client = new ContextGrantsClient(creds.operatorKey, creds.agentId);
|
|
278
66
|
const grant = await client.issueGrant({
|
|
@@ -291,58 +79,12 @@ export function registerTrustTools(server, creds, cfg) {
|
|
|
291
79
|
return toolError(e.message);
|
|
292
80
|
}
|
|
293
81
|
});
|
|
294
|
-
server
|
|
295
|
-
parentGrantId: z.string(),
|
|
296
|
-
holderId: z.string().describe('Agent receiving the delegated grant'),
|
|
297
|
-
scopeKind: grantScopeKindSchema,
|
|
298
|
-
scopeId: z.string(),
|
|
299
|
-
temporal: contextTemporalSchema.describe('from-now or from-start (must be same-or-narrower)'),
|
|
300
|
-
expiresAt: z.string().optional().nullable(),
|
|
301
|
-
watermarkAt: z
|
|
302
|
-
.string()
|
|
303
|
-
.optional()
|
|
304
|
-
.describe('from-now watermark ISO-8601 (optional; server may default)'),
|
|
305
|
-
}, WRITE, async ({ parentGrantId, holderId, scopeKind, scopeId, temporal, expiresAt, watermarkAt, }) => {
|
|
306
|
-
try {
|
|
307
|
-
// ZIG-941 #6 — an org scope may be named rather than pasted as org_… id.
|
|
308
|
-
let resolvedScopeId = scopeId;
|
|
309
|
-
if (scopeKind === 'org') {
|
|
310
|
-
const resolved = await resolveOrgScope(creds, scopeId);
|
|
311
|
-
if ('error' in resolved)
|
|
312
|
-
return resolved.error;
|
|
313
|
-
resolvedScopeId = resolved.scopeId;
|
|
314
|
-
}
|
|
315
|
-
const client = new ContextGrantsClient(creds.operatorKey, creds.agentId);
|
|
316
|
-
const result = await client.delegateGrant(parentGrantId, {
|
|
317
|
-
holderId,
|
|
318
|
-
scope: { kind: scopeKind, id: resolvedScopeId },
|
|
319
|
-
temporal,
|
|
320
|
-
expiresAt,
|
|
321
|
-
watermarkAt,
|
|
322
|
-
});
|
|
323
|
-
if (result.status === 'pending_approval') {
|
|
324
|
-
return textResult({
|
|
325
|
-
status: 'pending_approval',
|
|
326
|
-
message: "This grant's original owner must approve sharing it. A request was opened for them — surface it to the human; nothing is granted yet.",
|
|
327
|
-
parentGrantId,
|
|
328
|
-
agreementId: result.agreementId,
|
|
329
|
-
ownerId: result.ownerId,
|
|
330
|
-
});
|
|
331
|
-
}
|
|
332
|
-
const grant = result.grant;
|
|
333
|
-
return textResult({
|
|
334
|
-
status: 'delegated',
|
|
335
|
-
parentGrantId,
|
|
336
|
-
grant,
|
|
337
|
-
bounds: contextBounds(grant),
|
|
338
|
-
});
|
|
339
|
-
}
|
|
340
|
-
catch (e) {
|
|
341
|
-
return toolError(e.message);
|
|
342
|
-
}
|
|
343
|
-
});
|
|
82
|
+
registerCapability(server, contextDelegateCapability, creds);
|
|
344
83
|
if (!cfg?.coreOnly) {
|
|
345
|
-
|
|
84
|
+
// ZIG-941 #7 — the link tool group is skipped by the lean session-start
|
|
85
|
+
// tier (ZIGGS_MCP_CORE_ONLY). Definitions live in the shared capability
|
|
86
|
+
// layer, including the linkSummary shaping the mutations now share.
|
|
87
|
+
registerCapabilities(server, LINK_CAPABILITIES, creds, { webUrl });
|
|
346
88
|
}
|
|
347
89
|
server.tool('ziggs_revoke_grant', 'Revoke a context grant and its descendants (DELETE /context/grants/:id). You can revoke (narrow) any grant you hold — this needs no special scope. Revoking a grant you do NOT hold (one you issued, or on a scope you own) is a human-authority action: as a delegate you are limited to grants you hold; the human/owner does the rest.', {
|
|
348
90
|
grantId: z.string(),
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ziggs-ai/ziggs-mcp",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "MCP server for Claude Code, Cursor, and other MCP hosts
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"description": "MCP server for Claude Code, Cursor, and other MCP hosts \u2014 act as your Ziggs delegate agent",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"ziggs-mcp": "./dist/index.js"
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
39
|
-
"@ziggs-ai/api-client": "^0.
|
|
39
|
+
"@ziggs-ai/api-client": "^0.5.0",
|
|
40
40
|
"dotenv": "^16.6.1",
|
|
41
41
|
"zod": "^3.24.2"
|
|
42
42
|
},
|
package/dist/orgs.d.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { type Creds } from '@ziggs-ai/api-client';
|
|
2
|
-
export interface MyOrg {
|
|
3
|
-
orgId: string;
|
|
4
|
-
name: string;
|
|
5
|
-
kind: string;
|
|
6
|
-
role?: string;
|
|
7
|
-
}
|
|
8
|
-
/**
|
|
9
|
-
* ZIG-739 — the operator's full org membership (not just granted scopes, which
|
|
10
|
-
* is all ziggs_list_grants sees). Lets the delegate resolve an org name to
|
|
11
|
-
* an id and offer a pick-list instead of demanding a pasted org_... id.
|
|
12
|
-
*/
|
|
13
|
-
export declare function fetchMyOrgs(creds: Creds): Promise<MyOrg[]>;
|
|
14
|
-
export type OrgResolution = {
|
|
15
|
-
status: 'ok';
|
|
16
|
-
orgId: string;
|
|
17
|
-
} | {
|
|
18
|
-
status: 'ambiguous';
|
|
19
|
-
matches: MyOrg[];
|
|
20
|
-
} | {
|
|
21
|
-
status: 'not-found';
|
|
22
|
-
};
|
|
23
|
-
/**
|
|
24
|
-
* ZIG-739 — resolve an org selector (exact org_... id OR a name/handle) against
|
|
25
|
-
* the operator's memberships. Exact id wins; otherwise case-insensitive name
|
|
26
|
-
* match. Ambiguous names return the candidates rather than guessing.
|
|
27
|
-
*/
|
|
28
|
-
export declare function resolveOrgSelector(orgs: MyOrg[], selector: string): OrgResolution;
|
package/dist/orgs.js
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { getBackendUrl } from '@ziggs-ai/api-client';
|
|
2
|
-
/**
|
|
3
|
-
* ZIG-739 — the operator's full org membership (not just granted scopes, which
|
|
4
|
-
* is all ziggs_list_grants sees). Lets the delegate resolve an org name to
|
|
5
|
-
* an id and offer a pick-list instead of demanding a pasted org_... id.
|
|
6
|
-
*/
|
|
7
|
-
export async function fetchMyOrgs(creds) {
|
|
8
|
-
const url = `${getBackendUrl()}/orgs/me`;
|
|
9
|
-
const res = await fetch(url, {
|
|
10
|
-
method: 'GET',
|
|
11
|
-
headers: {
|
|
12
|
-
Authorization: `Bearer ${creds.operatorKey}`,
|
|
13
|
-
'X-Agent-Id': creds.agentId,
|
|
14
|
-
},
|
|
15
|
-
});
|
|
16
|
-
const body = await res.text().catch(() => '');
|
|
17
|
-
if (!res.ok) {
|
|
18
|
-
throw new Error(`GET /orgs/me ${res.status} ${body.slice(0, 200)}`);
|
|
19
|
-
}
|
|
20
|
-
const parsed = body ? JSON.parse(body) : {};
|
|
21
|
-
return (parsed.orgs ?? []).map((o) => ({
|
|
22
|
-
orgId: o.orgId,
|
|
23
|
-
name: o.name,
|
|
24
|
-
kind: o.kind,
|
|
25
|
-
role: o.role,
|
|
26
|
-
}));
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* ZIG-739 — resolve an org selector (exact org_... id OR a name/handle) against
|
|
30
|
-
* the operator's memberships. Exact id wins; otherwise case-insensitive name
|
|
31
|
-
* match. Ambiguous names return the candidates rather than guessing.
|
|
32
|
-
*/
|
|
33
|
-
export function resolveOrgSelector(orgs, selector) {
|
|
34
|
-
const byId = orgs.find((o) => o.orgId === selector);
|
|
35
|
-
if (byId)
|
|
36
|
-
return { status: 'ok', orgId: byId.orgId };
|
|
37
|
-
const needle = selector.toLowerCase();
|
|
38
|
-
const byName = orgs.filter((o) => o.name.toLowerCase() === needle);
|
|
39
|
-
if (byName.length === 1)
|
|
40
|
-
return { status: 'ok', orgId: byName[0].orgId };
|
|
41
|
-
if (byName.length > 1)
|
|
42
|
-
return { status: 'ambiguous', matches: byName };
|
|
43
|
-
return { status: 'not-found' };
|
|
44
|
-
}
|