@agent-wire/terminal 1.7.7 → 1.7.10
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 +519 -435
- package/dist/api-token.d.ts +9 -0
- package/dist/api-token.js +46 -0
- package/dist/api-token.js.map +1 -0
- package/dist/api.d.ts +50 -10
- package/dist/api.js +78 -31
- package/dist/api.js.map +1 -1
- package/dist/b107-copy.d.ts +68 -0
- package/dist/b107-copy.js +69 -0
- package/dist/b107-copy.js.map +1 -0
- package/dist/catalog-follow.d.ts +32 -0
- package/dist/catalog-follow.js +184 -0
- package/dist/catalog-follow.js.map +1 -0
- package/dist/cli-projection.js +20 -5
- package/dist/cli-projection.js.map +1 -1
- package/dist/cli.js +32 -19
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +14 -1
- package/dist/config.js +54 -9
- package/dist/config.js.map +1 -1
- package/dist/mcp-server.d.ts +1 -6
- package/dist/mcp-server.js +161 -144
- package/dist/mcp-server.js.map +1 -1
- package/dist/read-tool-input.d.ts +15 -0
- package/dist/read-tool-input.js +15 -0
- package/dist/read-tool-input.js.map +1 -0
- package/dist/response-shaper.js +76 -15
- package/dist/response-shaper.js.map +1 -1
- package/dist/resume.d.ts +7 -0
- package/dist/resume.js +15 -0
- package/dist/resume.js.map +1 -0
- package/dist/slots.d.ts +1 -0
- package/dist/slots.js +1 -1
- package/dist/slots.js.map +1 -1
- package/dist/sync/diff.js +7 -1
- package/dist/sync/diff.js.map +1 -1
- package/dist/sync/pull.d.ts +1 -0
- package/dist/sync/pull.js +17 -9
- package/dist/sync/pull.js.map +1 -1
- package/dist/sync/types.d.ts +2 -1
- package/dist/tool-projection.d.ts +19 -2
- package/dist/tool-projection.js +544 -8
- package/dist/tool-projection.js.map +1 -1
- package/package.json +58 -58
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
interface TokenConfig {
|
|
2
|
+
apiToken: string;
|
|
3
|
+
apiTokenFile?: string;
|
|
4
|
+
}
|
|
5
|
+
/** Shared saved credentials are never a server's own MCP identity. */
|
|
6
|
+
export declare function hasExplicitApiToken(): boolean;
|
|
7
|
+
/** Explicit environment token > environment file > saved configuration. */
|
|
8
|
+
export declare function resolveApiToken(config: TokenConfig, allowInvalidTokenFile?: boolean): TokenConfig;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { isAbsolute } from 'node:path';
|
|
3
|
+
// Capture credentials for this process; rotating a token file requires a restart.
|
|
4
|
+
const envToken = process.env.WIRE_API_TOKEN;
|
|
5
|
+
const envTokenFile = process.env.WIRE_API_TOKEN_FILE;
|
|
6
|
+
const fileTokens = new Map();
|
|
7
|
+
/** Shared saved credentials are never a server's own MCP identity. */
|
|
8
|
+
export function hasExplicitApiToken() {
|
|
9
|
+
return !!envToken || envTokenFile !== undefined;
|
|
10
|
+
}
|
|
11
|
+
/** Explicit environment token > environment file > saved configuration. */
|
|
12
|
+
export function resolveApiToken(config, allowInvalidTokenFile = false) {
|
|
13
|
+
if (envToken)
|
|
14
|
+
return { apiToken: envToken, apiTokenFile: undefined };
|
|
15
|
+
const path = envTokenFile ?? config.apiTokenFile;
|
|
16
|
+
if (path === undefined)
|
|
17
|
+
return { apiToken: config.apiToken, apiTokenFile: undefined };
|
|
18
|
+
let token = fileTokens.get(path);
|
|
19
|
+
if (token === undefined) {
|
|
20
|
+
if (!isAbsolute(path)) {
|
|
21
|
+
token = new Error('WIRE_API_TOKEN_FILE must be an absolute path to a file containing only your token');
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
try {
|
|
25
|
+
token = readFileSync(path, 'utf8').trim();
|
|
26
|
+
if (!token)
|
|
27
|
+
token = new Error('The file referenced by WIRE_API_TOKEN_FILE is empty; it must contain only your token');
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
// Only expose the OS code, never file contents or an arbitrary error message.
|
|
31
|
+
const code = error.code ?? 'read failed';
|
|
32
|
+
token = new Error(`Cannot read the file referenced by WIRE_API_TOKEN_FILE (${code}); set it to an absolute path to a file containing only your token`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
fileTokens.set(path, token);
|
|
36
|
+
}
|
|
37
|
+
if (token instanceof Error) {
|
|
38
|
+
// Public help/discovery may proceed anonymously; authenticated callers retry
|
|
39
|
+
// this same cached result and receive the error without exposing the value.
|
|
40
|
+
if (allowInvalidTokenFile)
|
|
41
|
+
return { apiToken: '', apiTokenFile: path };
|
|
42
|
+
throw token;
|
|
43
|
+
}
|
|
44
|
+
return { apiToken: token, apiTokenFile: path };
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=api-token.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-token.js","sourceRoot":"","sources":["../src/api-token.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAOvC,kFAAkF;AAClF,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;AAC5C,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;AACrD,MAAM,UAAU,GAAG,IAAI,GAAG,EAA0B,CAAC;AAErD,sEAAsE;AACtE,MAAM,UAAU,mBAAmB;IACjC,OAAO,CAAC,CAAC,QAAQ,IAAI,YAAY,KAAK,SAAS,CAAC;AAClD,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,eAAe,CAAC,MAAmB,EAAE,qBAAqB,GAAG,KAAK;IAChF,IAAI,QAAQ;QAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,SAAS,EAAE,CAAC;IACrE,MAAM,IAAI,GAAG,YAAY,IAAI,MAAM,CAAC,YAAY,CAAC;IACjD,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,YAAY,EAAE,SAAS,EAAE,CAAC;IAEtF,IAAI,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACjC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACtB,KAAK,GAAG,IAAI,KAAK,CAAC,mFAAmF,CAAC,CAAC;QACzG,CAAC;aAAM,CAAC;YACN,IAAI,CAAC;gBACH,KAAK,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;gBAC1C,IAAI,CAAC,KAAK;oBAAE,KAAK,GAAG,IAAI,KAAK,CAAC,sFAAsF,CAAC,CAAC;YACxH,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,8EAA8E;gBAC9E,MAAM,IAAI,GAAI,KAA+B,CAAC,IAAI,IAAI,aAAa,CAAC;gBACpE,KAAK,GAAG,IAAI,KAAK,CAAC,2DAA2D,IAAI,oEAAoE,CAAC,CAAC;YACzJ,CAAC;QACH,CAAC;QACD,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC9B,CAAC;IACD,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,6EAA6E;QAC7E,4EAA4E;QAC5E,IAAI,qBAAqB;YAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;QACvE,MAAM,KAAK,CAAC;IACd,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;AACjD,CAAC"}
|
package/dist/api.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { CreditAmount } from './contracts/credit-amount.js';
|
|
2
2
|
import type { WireNodeConfig } from './config.js';
|
|
3
3
|
import type { MarketNativeDocsIngestMode, RemoteDocument } from './sync/types.js';
|
|
4
|
+
export declare function normalizeWireApiUrl(value: string): string;
|
|
4
5
|
export declare class RegistrationError extends Error {
|
|
5
6
|
readonly status: number;
|
|
6
7
|
constructor(status: number, message: string);
|
|
@@ -21,6 +22,7 @@ export interface MeshScopeParams {
|
|
|
21
22
|
circle_id?: string;
|
|
22
23
|
}
|
|
23
24
|
export interface QueryParams {
|
|
25
|
+
count?: 'exact';
|
|
24
26
|
text?: string;
|
|
25
27
|
types?: string | string[];
|
|
26
28
|
type?: string;
|
|
@@ -39,6 +41,7 @@ export interface QueryParams {
|
|
|
39
41
|
}
|
|
40
42
|
export interface ContributeParams {
|
|
41
43
|
type: string;
|
|
44
|
+
original?: boolean;
|
|
42
45
|
contribution_type?: 'mechanical' | 'intelligence';
|
|
43
46
|
title: string;
|
|
44
47
|
body: string;
|
|
@@ -84,6 +87,7 @@ export interface ContributeParams {
|
|
|
84
87
|
}>;
|
|
85
88
|
}
|
|
86
89
|
export interface ActionCreateParams {
|
|
90
|
+
scope?: 'fleet' | 'unscoped';
|
|
87
91
|
title: string;
|
|
88
92
|
body: string;
|
|
89
93
|
action_definition: Record<string, unknown>;
|
|
@@ -103,6 +107,9 @@ export interface BrowseParams {
|
|
|
103
107
|
include_definition?: boolean;
|
|
104
108
|
definition_purpose?: string;
|
|
105
109
|
definition_scope?: string;
|
|
110
|
+
cursor?: string;
|
|
111
|
+
limit?: number;
|
|
112
|
+
offset?: number;
|
|
106
113
|
}
|
|
107
114
|
export interface FlagParams {
|
|
108
115
|
item_id: string;
|
|
@@ -178,6 +185,15 @@ export interface PinPreview {
|
|
|
178
185
|
derivative_count: number;
|
|
179
186
|
}
|
|
180
187
|
export interface RetractionResult {
|
|
188
|
+
deposit_fee?: CreditAmount;
|
|
189
|
+
deposit_refunded_amount?: CreditAmount;
|
|
190
|
+
deposit_fee_payers?: Array<{
|
|
191
|
+
operator_id: string;
|
|
192
|
+
refunded_amount: CreditAmount;
|
|
193
|
+
fee: CreditAmount;
|
|
194
|
+
}>;
|
|
195
|
+
deposit_case?: string;
|
|
196
|
+
deposit_message?: string | null;
|
|
181
197
|
retracted: boolean;
|
|
182
198
|
contribution_id: string;
|
|
183
199
|
deposit_refund: CreditAmount;
|
|
@@ -293,7 +309,14 @@ export declare const __wireApiTestInternals: {
|
|
|
293
309
|
parseSseBlock: typeof parseSseBlock;
|
|
294
310
|
};
|
|
295
311
|
declare function parseSseBlock(block: string): WireEventStreamMessage | null;
|
|
312
|
+
/** Keep actionable server refusals intact across MCP and terminal transports. */
|
|
313
|
+
export declare class WireApiRefusal extends Error {
|
|
314
|
+
readonly status: number;
|
|
315
|
+
readonly body: Record<string, unknown>;
|
|
316
|
+
constructor(status: number, body: Record<string, unknown>);
|
|
317
|
+
}
|
|
296
318
|
export declare class WireAPI {
|
|
319
|
+
private httpFetch?;
|
|
297
320
|
claims(params: Record<string, unknown>): Promise<unknown>;
|
|
298
321
|
private baseUrl;
|
|
299
322
|
private token;
|
|
@@ -303,7 +326,7 @@ export declare class WireAPI {
|
|
|
303
326
|
private localNodeEnabled;
|
|
304
327
|
private localNodeToken;
|
|
305
328
|
private localContributionRouteStatus;
|
|
306
|
-
constructor(config: WireNodeConfig, threadId?: string);
|
|
329
|
+
constructor(config: WireNodeConfig, threadId?: string, httpFetch?: typeof fetch | undefined);
|
|
307
330
|
/** Set or update the thread ID (used for mesh coordination) */
|
|
308
331
|
setThreadId(id: string): void;
|
|
309
332
|
request<T>(method: string, path: string, body?: unknown, timeoutMs?: number): Promise<T>;
|
|
@@ -314,10 +337,15 @@ export declare class WireAPI {
|
|
|
314
337
|
requestUnwrap<T>(method: string, path: string, body?: unknown, timeoutMs?: number): Promise<T>;
|
|
315
338
|
unwrapEnvelopeOrPlain<T>(response: unknown): T;
|
|
316
339
|
getMe(): Promise<Record<string, unknown>>;
|
|
317
|
-
registerNode(name: string, capabilities: string[]
|
|
340
|
+
registerNode(name: string, capabilities: string[], options?: {
|
|
341
|
+
node_handle?: string;
|
|
342
|
+
app_version?: string;
|
|
343
|
+
}): Promise<{
|
|
318
344
|
node_id: string;
|
|
319
345
|
name: string;
|
|
320
346
|
status: string;
|
|
347
|
+
registration_notice?: string;
|
|
348
|
+
legacy_nodes_not_resumed?: number;
|
|
321
349
|
}>;
|
|
322
350
|
/**
|
|
323
351
|
* Register a new Wire agent (unauthenticated — no token required).
|
|
@@ -334,6 +362,8 @@ export declare class WireAPI {
|
|
|
334
362
|
pseudo_id: string;
|
|
335
363
|
agent_id: string;
|
|
336
364
|
verification_status: string;
|
|
365
|
+
welcome_grant?: Record<string, unknown>;
|
|
366
|
+
pool_credits?: number;
|
|
337
367
|
}>;
|
|
338
368
|
pollWork(nodeId: string): Promise<{
|
|
339
369
|
work: {
|
|
@@ -367,13 +397,16 @@ export declare class WireAPI {
|
|
|
367
397
|
flag(params: FlagParams): Promise<Record<string, unknown>>;
|
|
368
398
|
/**
|
|
369
399
|
* Retract your own contribution (voluntary self-takedown).
|
|
370
|
-
* Economics:
|
|
400
|
+
* Economics: held deposits use the age-based forfeit and cap; refunded deposits apply the same rule to each actual refund recipient. No refund leg means no fee. Bounty recovery still applies.
|
|
371
401
|
*/
|
|
372
402
|
retract(contributionId: string): Promise<Record<string, unknown>>;
|
|
373
403
|
/**
|
|
374
404
|
* Access a contribution (detail endpoint). Accessing IS purchasing for priced items.
|
|
375
405
|
*/
|
|
376
|
-
accessContribution(
|
|
406
|
+
accessContribution(input: string | {
|
|
407
|
+
contribution_id: string;
|
|
408
|
+
[key: string]: unknown;
|
|
409
|
+
}, acceptPrice?: CreditAmount): Promise<Record<string, unknown>>;
|
|
377
410
|
private verifyLocalContributionReadRoute;
|
|
378
411
|
private localHeaders;
|
|
379
412
|
private localAuthToken;
|
|
@@ -547,11 +580,13 @@ export declare class WireAPI {
|
|
|
547
580
|
*/
|
|
548
581
|
previewPin(nodeId: string, targetType: string, targetId: string): Promise<PinPreview>;
|
|
549
582
|
/**
|
|
550
|
-
* Retract a contribution as an operator
|
|
551
|
-
*
|
|
552
|
-
*
|
|
583
|
+
* Retract a contribution as an operator at any age. To correct a contribution,
|
|
584
|
+
* supersede it. Retraction uses the current window, rates and late refund cap.
|
|
585
|
+
* After settlement, the same rule applies to each actual refund recipient.
|
|
586
|
+
* Use operator authentication or the specific author agent token;
|
|
587
|
+
* sibling agent tokens cannot retract another agent's contribution.
|
|
553
588
|
*
|
|
554
|
-
* Economics:
|
|
589
|
+
* Economics: held deposits use the age-based forfeit and cap; refunded deposits apply the same rule to each actual refund recipient. No refund leg means no fee. Bounty recovery still applies.
|
|
555
590
|
*
|
|
556
591
|
* @param agentId - The agent that owns the contribution
|
|
557
592
|
* @param contributionId - The contribution to retract
|
|
@@ -639,6 +674,7 @@ export declare class WireAPI {
|
|
|
639
674
|
input?: Record<string, unknown>;
|
|
640
675
|
chain_id?: string;
|
|
641
676
|
quote_id?: string;
|
|
677
|
+
idempotency_key?: string;
|
|
642
678
|
max_credits?: number;
|
|
643
679
|
entry_mode?: 'start' | 'direct';
|
|
644
680
|
entry?: {
|
|
@@ -651,7 +687,7 @@ export declare class WireAPI {
|
|
|
651
687
|
pollChainRun(params: {
|
|
652
688
|
run_id?: string;
|
|
653
689
|
run_handle_path?: string;
|
|
654
|
-
chain
|
|
690
|
+
chain?: string;
|
|
655
691
|
include_steps?: boolean;
|
|
656
692
|
}): Promise<Record<string, unknown>>;
|
|
657
693
|
resolveHandlePath(handlePath: string): Promise<Record<string, unknown>>;
|
|
@@ -728,6 +764,10 @@ export declare class WireAPI {
|
|
|
728
764
|
offset?: number;
|
|
729
765
|
}): Promise<Record<string, unknown>>;
|
|
730
766
|
getDocumentBody(documentId: string): Promise<string>;
|
|
767
|
+
downloadDocumentBody(documentId: string): Promise<{
|
|
768
|
+
body: string;
|
|
769
|
+
content_sha256: string | null;
|
|
770
|
+
}>;
|
|
731
771
|
getDocumentGraph(documentId: string): Promise<Record<string, unknown>>;
|
|
732
772
|
listDocumentSpans(documentId: string): Promise<Record<string, unknown>>;
|
|
733
773
|
createDocumentSpan(documentId: string, span: {
|
|
@@ -745,7 +785,7 @@ export declare class WireAPI {
|
|
|
745
785
|
material_class?: string;
|
|
746
786
|
visibility?: string;
|
|
747
787
|
themes?: string[];
|
|
748
|
-
attestation_tier
|
|
788
|
+
attestation_tier: 'ownership' | 'authorization' | 'good_faith';
|
|
749
789
|
authorizing_party?: string;
|
|
750
790
|
authorization_basis?: string;
|
|
751
791
|
rights_basis?: string;
|
package/dist/api.js
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
const normalizedUrlNotices = new Set();
|
|
2
|
+
export function normalizeWireApiUrl(value) {
|
|
3
|
+
const url = new URL(value);
|
|
4
|
+
if (url.pathname === '/' || !url.pathname) {
|
|
5
|
+
url.pathname = '/api/v1';
|
|
6
|
+
if (!normalizedUrlNotices.has(value)) {
|
|
7
|
+
console.error('[wire] WIRE_API_URL has no API path; appended /api/v1.');
|
|
8
|
+
normalizedUrlNotices.add(value);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
return url.toString().replace(/\/+$/, '');
|
|
12
|
+
}
|
|
1
13
|
const DEFAULT_TRUSTED_CHAIN_TIMEOUT_MS = 600_000;
|
|
2
14
|
const TRUSTED_CHAIN_CLIENT_GRACE_MS = 5_000;
|
|
3
15
|
const DEFAULT_WIRE_SYNC_TIMEOUT_MS = DEFAULT_TRUSTED_CHAIN_TIMEOUT_MS + TRUSTED_CHAIN_CLIENT_GRACE_MS;
|
|
@@ -145,7 +157,18 @@ function parseSseBlock(block) {
|
|
|
145
157
|
return { event, data: rawData };
|
|
146
158
|
}
|
|
147
159
|
}
|
|
160
|
+
/** Keep actionable server refusals intact across MCP and terminal transports. */
|
|
161
|
+
export class WireApiRefusal extends Error {
|
|
162
|
+
status;
|
|
163
|
+
body;
|
|
164
|
+
constructor(status, body) {
|
|
165
|
+
super(JSON.stringify(body));
|
|
166
|
+
this.status = status;
|
|
167
|
+
this.body = body;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
148
170
|
export class WireAPI {
|
|
171
|
+
httpFetch;
|
|
149
172
|
async claims(params) {
|
|
150
173
|
const { action, claim_id } = params;
|
|
151
174
|
if (action === 'get' || action === 'list') {
|
|
@@ -161,8 +184,9 @@ export class WireAPI {
|
|
|
161
184
|
localNodeEnabled;
|
|
162
185
|
localNodeToken;
|
|
163
186
|
localContributionRouteStatus;
|
|
164
|
-
constructor(config, threadId) {
|
|
165
|
-
this.
|
|
187
|
+
constructor(config, threadId, httpFetch) {
|
|
188
|
+
this.httpFetch = httpFetch;
|
|
189
|
+
this.baseUrl = normalizeWireApiUrl(config.apiUrl);
|
|
166
190
|
this.token = config.apiToken;
|
|
167
191
|
this.nodeId = config.nodeId;
|
|
168
192
|
this.threadId = threadId || null;
|
|
@@ -184,7 +208,7 @@ export class WireAPI {
|
|
|
184
208
|
if (this.threadId) {
|
|
185
209
|
headers['X-Wire-Thread'] = this.threadId;
|
|
186
210
|
}
|
|
187
|
-
const res = await fetch(url, {
|
|
211
|
+
const res = await (this.httpFetch ?? fetch)(url, {
|
|
188
212
|
method,
|
|
189
213
|
headers,
|
|
190
214
|
body: body ? JSON.stringify(body) : undefined,
|
|
@@ -192,6 +216,8 @@ export class WireAPI {
|
|
|
192
216
|
});
|
|
193
217
|
if (!res.ok) {
|
|
194
218
|
const err = await res.json().catch(() => ({ error: res.statusText }));
|
|
219
|
+
if (err.code === 'confirm_original' || err.code === 'source_hash_selector_private')
|
|
220
|
+
throw new WireApiRefusal(res.status, err);
|
|
195
221
|
throw new Error(`API ${method} ${path} failed (${res.status}): ${err.error || res.statusText}`);
|
|
196
222
|
}
|
|
197
223
|
return res.json();
|
|
@@ -205,7 +231,7 @@ export class WireAPI {
|
|
|
205
231
|
if (this.threadId) {
|
|
206
232
|
headers['X-Wire-Thread'] = this.threadId;
|
|
207
233
|
}
|
|
208
|
-
const res = await fetch(url, {
|
|
234
|
+
const res = await (this.httpFetch ?? fetch)(url, {
|
|
209
235
|
method,
|
|
210
236
|
headers,
|
|
211
237
|
body: body ? JSON.stringify(body) : undefined,
|
|
@@ -213,6 +239,8 @@ export class WireAPI {
|
|
|
213
239
|
});
|
|
214
240
|
if (!res.ok) {
|
|
215
241
|
const err = await res.json().catch(() => ({ error: res.statusText }));
|
|
242
|
+
if (err.code === 'source_hash_selector_private')
|
|
243
|
+
throw new WireApiRefusal(res.status, err);
|
|
216
244
|
const msg = err.error || res.statusText;
|
|
217
245
|
if (res.status === 429 && msg.toLowerCase().includes('pending')) {
|
|
218
246
|
const retryAfter = res.headers.get('Retry-After') || '60';
|
|
@@ -246,8 +274,8 @@ export class WireAPI {
|
|
|
246
274
|
async getMe() {
|
|
247
275
|
return this.unwrapEnvelopeOrPlain(await this.request('GET', '/me'));
|
|
248
276
|
}
|
|
249
|
-
async registerNode(name, capabilities) {
|
|
250
|
-
return this.request('POST', '/node/register', { name, capabilities });
|
|
277
|
+
async registerNode(name, capabilities, options = {}) {
|
|
278
|
+
return this.request('POST', '/node/register', { name, capabilities, ...options });
|
|
251
279
|
}
|
|
252
280
|
/**
|
|
253
281
|
* Register a new Wire agent (unauthenticated — no token required).
|
|
@@ -256,7 +284,7 @@ export class WireAPI {
|
|
|
256
284
|
async registerAgent(params) {
|
|
257
285
|
// Registration doesn't require auth — use a raw fetch
|
|
258
286
|
const url = `${this.baseUrl}/register`;
|
|
259
|
-
const res = await fetch(url, {
|
|
287
|
+
const res = await (this.httpFetch ?? fetch)(url, {
|
|
260
288
|
method: 'POST',
|
|
261
289
|
headers: { 'Content-Type': 'application/json' },
|
|
262
290
|
body: JSON.stringify(params),
|
|
@@ -348,6 +376,8 @@ export class WireAPI {
|
|
|
348
376
|
return results;
|
|
349
377
|
}
|
|
350
378
|
async browse(params) {
|
|
379
|
+
if (params.cursor && (params.item_id || params.entity))
|
|
380
|
+
throw new Error('cursor applies to item-list browsing; omit item_id/entity.');
|
|
351
381
|
if (params.item_id) {
|
|
352
382
|
if (params.include_definition) {
|
|
353
383
|
const qs = new URLSearchParams({ mode: 'inspect', include_definition: 'true' });
|
|
@@ -365,17 +395,23 @@ export class WireAPI {
|
|
|
365
395
|
qs.set('arc', params.arc);
|
|
366
396
|
return this.request('GET', `/wire/entities?${qs.toString()}`);
|
|
367
397
|
}
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
398
|
+
const qs = new URLSearchParams();
|
|
399
|
+
if (params.arc)
|
|
400
|
+
qs.set('arc', params.arc);
|
|
401
|
+
if (params.cursor)
|
|
402
|
+
qs.set('cursor', params.cursor);
|
|
403
|
+
if (params.limit !== undefined)
|
|
404
|
+
qs.set('limit', String(params.limit));
|
|
405
|
+
if (params.offset !== undefined)
|
|
406
|
+
qs.set('offset', String(params.offset));
|
|
407
|
+
return this.request('GET', `/wire/items${qs.size ? '?' + qs : ''}`);
|
|
372
408
|
}
|
|
373
409
|
async flag(params) {
|
|
374
410
|
return this.request('POST', '/flag', params);
|
|
375
411
|
}
|
|
376
412
|
/**
|
|
377
413
|
* Retract your own contribution (voluntary self-takedown).
|
|
378
|
-
* Economics:
|
|
414
|
+
* Economics: held deposits use the age-based forfeit and cap; refunded deposits apply the same rule to each actual refund recipient. No refund leg means no fee. Bounty recovery still applies.
|
|
379
415
|
*/
|
|
380
416
|
async retract(contributionId) {
|
|
381
417
|
return this.request('POST', '/retract', { contribution_id: contributionId });
|
|
@@ -383,7 +419,9 @@ export class WireAPI {
|
|
|
383
419
|
/**
|
|
384
420
|
* Access a contribution (detail endpoint). Accessing IS purchasing for priced items.
|
|
385
421
|
*/
|
|
386
|
-
async accessContribution(
|
|
422
|
+
async accessContribution(input, acceptPrice) {
|
|
423
|
+
const { contribution_id: contributionId, ...readParams } = typeof input === 'string'
|
|
424
|
+
? { contribution_id: input, ...(acceptPrice === undefined ? {} : { accept_price: acceptPrice }) } : input;
|
|
387
425
|
let identifier = contributionId;
|
|
388
426
|
const localResult = await this.tryLocalContributionRead(identifier);
|
|
389
427
|
if (localResult) {
|
|
@@ -412,7 +450,8 @@ export class WireAPI {
|
|
|
412
450
|
return localResolvedResult;
|
|
413
451
|
}
|
|
414
452
|
}
|
|
415
|
-
|
|
453
|
+
const query = new URLSearchParams(Object.entries(readParams).filter(([, value]) => value !== undefined).map(([key, value]) => [key, String(value)]));
|
|
454
|
+
return this.request('GET', `/wire/contribution/${encodeURIComponent(identifier)}${query.size ? `?${query}` : ''}`);
|
|
416
455
|
}
|
|
417
456
|
async verifyLocalContributionReadRoute() {
|
|
418
457
|
if (!this.localNodeEnabled)
|
|
@@ -422,7 +461,7 @@ export class WireAPI {
|
|
|
422
461
|
if (this.localContributionRouteStatus)
|
|
423
462
|
return this.localContributionRouteStatus;
|
|
424
463
|
try {
|
|
425
|
-
const health = await fetch(`${this.localNodeUrl}/health`, {
|
|
464
|
+
const health = await (this.httpFetch ?? fetch)(`${this.localNodeUrl}/health`, {
|
|
426
465
|
method: 'GET',
|
|
427
466
|
signal: AbortSignal.timeout(2_000),
|
|
428
467
|
});
|
|
@@ -430,7 +469,7 @@ export class WireAPI {
|
|
|
430
469
|
this.localContributionRouteStatus = 'unavailable';
|
|
431
470
|
return this.localContributionRouteStatus;
|
|
432
471
|
}
|
|
433
|
-
const probe = await fetch(`${this.localNodeUrl}${localContributionReadPath('__wire_terminal_route_probe__')}`, {
|
|
472
|
+
const probe = await (this.httpFetch ?? fetch)(`${this.localNodeUrl}${localContributionReadPath('__wire_terminal_route_probe__')}`, {
|
|
434
473
|
method: 'GET',
|
|
435
474
|
headers: this.localHeaders(),
|
|
436
475
|
signal: AbortSignal.timeout(2_000),
|
|
@@ -464,7 +503,7 @@ export class WireAPI {
|
|
|
464
503
|
return null;
|
|
465
504
|
const path = localContributionReadPath(identifier);
|
|
466
505
|
try {
|
|
467
|
-
const res = await fetch(`${this.localNodeUrl}${path}`, {
|
|
506
|
+
const res = await (this.httpFetch ?? fetch)(`${this.localNodeUrl}${path}`, {
|
|
468
507
|
method: 'GET',
|
|
469
508
|
headers: this.localHeaders(),
|
|
470
509
|
signal: AbortSignal.timeout(10_000),
|
|
@@ -498,7 +537,7 @@ export class WireAPI {
|
|
|
498
537
|
* parsed JSON body on success, throws a descriptive error on non-2xx.
|
|
499
538
|
*/
|
|
500
539
|
async localNodeFetch(method, path, body, timeoutMs = 15_000) {
|
|
501
|
-
const res = await fetch(`${this.localNodeUrl}${path}`, {
|
|
540
|
+
const res = await (this.httpFetch ?? fetch)(`${this.localNodeUrl}${path}`, {
|
|
502
541
|
method,
|
|
503
542
|
headers: this.localHeaders(),
|
|
504
543
|
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
@@ -796,11 +835,13 @@ export class WireAPI {
|
|
|
796
835
|
}
|
|
797
836
|
// ── Operator Methods ───────────────────────────────────────
|
|
798
837
|
/**
|
|
799
|
-
* Retract a contribution as an operator
|
|
800
|
-
*
|
|
801
|
-
*
|
|
838
|
+
* Retract a contribution as an operator at any age. To correct a contribution,
|
|
839
|
+
* supersede it. Retraction uses the current window, rates and late refund cap.
|
|
840
|
+
* After settlement, the same rule applies to each actual refund recipient.
|
|
841
|
+
* Use operator authentication or the specific author agent token;
|
|
842
|
+
* sibling agent tokens cannot retract another agent's contribution.
|
|
802
843
|
*
|
|
803
|
-
* Economics:
|
|
844
|
+
* Economics: held deposits use the age-based forfeit and cap; refunded deposits apply the same rule to each actual refund recipient. No refund leg means no fee. Bounty recovery still applies.
|
|
804
845
|
*
|
|
805
846
|
* @param agentId - The agent that owns the contribution
|
|
806
847
|
* @param contributionId - The contribution to retract
|
|
@@ -884,7 +925,7 @@ export class WireAPI {
|
|
|
884
925
|
if (this.threadId) {
|
|
885
926
|
headers['X-Wire-Thread'] = this.threadId;
|
|
886
927
|
}
|
|
887
|
-
const res = await fetch(url.toString(), {
|
|
928
|
+
const res = await (this.httpFetch ?? fetch)(url.toString(), {
|
|
888
929
|
method: 'GET',
|
|
889
930
|
headers,
|
|
890
931
|
signal: options.signal,
|
|
@@ -923,6 +964,7 @@ export class WireAPI {
|
|
|
923
964
|
}
|
|
924
965
|
}
|
|
925
966
|
finally {
|
|
967
|
+
await reader.cancel().catch(() => { });
|
|
926
968
|
reader.releaseLock();
|
|
927
969
|
}
|
|
928
970
|
}
|
|
@@ -1047,7 +1089,9 @@ export class WireAPI {
|
|
|
1047
1089
|
const runIdentifier = params.run_handle_path ?? params.run_id;
|
|
1048
1090
|
if (!runIdentifier)
|
|
1049
1091
|
throw new Error('pollChainRun requires run_handle_path or run_id');
|
|
1050
|
-
const qs = new URLSearchParams(
|
|
1092
|
+
const qs = new URLSearchParams();
|
|
1093
|
+
if (params.chain)
|
|
1094
|
+
qs.set('chain', params.chain);
|
|
1051
1095
|
if (params.include_steps)
|
|
1052
1096
|
qs.set('include_steps', 'true');
|
|
1053
1097
|
return this.request('GET', `/wire/chains/runs/${encodeURIComponent(runIdentifier)}?${qs.toString()}`, undefined, 30_000);
|
|
@@ -1072,7 +1116,7 @@ export class WireAPI {
|
|
|
1072
1116
|
async executeSupersession(targetId, newContributionId, allowTypeChange) {
|
|
1073
1117
|
// allow_type_change forwards to the REST endpoint (which already honors it) so a CROSS-TYPE
|
|
1074
1118
|
// supersession is reachable via the CLI/MCP, not only via raw REST (WI playful/170/177).
|
|
1075
|
-
const body = {
|
|
1119
|
+
const body = { contribution_id: newContributionId };
|
|
1076
1120
|
if (allowTypeChange)
|
|
1077
1121
|
body.allow_type_change = true;
|
|
1078
1122
|
return this.request('POST', `/wire/contributions/${encodeURIComponent(targetId)}/supersede`, body);
|
|
@@ -1244,6 +1288,9 @@ export class WireAPI {
|
|
|
1244
1288
|
return this.requestUnwrap('GET', `/wire/documents${queryString ? '?' + queryString : ''}`);
|
|
1245
1289
|
}
|
|
1246
1290
|
async getDocumentBody(documentId) {
|
|
1291
|
+
return (await this.downloadDocumentBody(documentId)).body;
|
|
1292
|
+
}
|
|
1293
|
+
async downloadDocumentBody(documentId) {
|
|
1247
1294
|
const url = `${this.baseUrl}/wire/documents/${documentId}/body`;
|
|
1248
1295
|
const headers = {
|
|
1249
1296
|
'Authorization': `Bearer ${this.token}`,
|
|
@@ -1251,12 +1298,12 @@ export class WireAPI {
|
|
|
1251
1298
|
if (this.threadId) {
|
|
1252
1299
|
headers['X-Wire-Thread'] = this.threadId;
|
|
1253
1300
|
}
|
|
1254
|
-
const res = await fetch(url, { method: 'GET', headers, signal: AbortSignal.timeout(30_000) });
|
|
1301
|
+
const res = await (this.httpFetch ?? fetch)(url, { method: 'GET', headers, signal: AbortSignal.timeout(30_000) });
|
|
1255
1302
|
if (!res.ok) {
|
|
1256
1303
|
const err = await res.json().catch(() => ({ error: res.statusText }));
|
|
1257
1304
|
throw new Error(`API GET /wire/documents/${documentId}/body failed (${res.status}): ${err.error || res.statusText}`);
|
|
1258
1305
|
}
|
|
1259
|
-
return res.text();
|
|
1306
|
+
return { body: await res.text(), content_sha256: res.headers.get('X-Body-Hash') };
|
|
1260
1307
|
}
|
|
1261
1308
|
async getDocumentGraph(documentId) {
|
|
1262
1309
|
return this.request('GET', `/wire/documents/${documentId}/graph`);
|
|
@@ -1314,7 +1361,7 @@ export class WireAPI {
|
|
|
1314
1361
|
const body = { email, device_fingerprint: deviceFingerprint };
|
|
1315
1362
|
if (agentMessage)
|
|
1316
1363
|
body.agent_message = agentMessage;
|
|
1317
|
-
const res = await fetch(url, {
|
|
1364
|
+
const res = await (this.httpFetch ?? fetch)(url, {
|
|
1318
1365
|
method: 'POST',
|
|
1319
1366
|
headers: { 'Content-Type': 'application/json' },
|
|
1320
1367
|
body: JSON.stringify(body),
|
|
@@ -1330,7 +1377,7 @@ export class WireAPI {
|
|
|
1330
1377
|
async verifyDeviceCode(email, deviceFingerprint, code) {
|
|
1331
1378
|
// No auth required — raw fetch
|
|
1332
1379
|
const url = `${this.baseUrl}/wire/device-auth`;
|
|
1333
|
-
const res = await fetch(url, {
|
|
1380
|
+
const res = await (this.httpFetch ?? fetch)(url, {
|
|
1334
1381
|
method: 'PUT',
|
|
1335
1382
|
headers: { 'Content-Type': 'application/json' },
|
|
1336
1383
|
body: JSON.stringify({ email, device_fingerprint: deviceFingerprint, code }),
|
|
@@ -1348,7 +1395,7 @@ export class WireAPI {
|
|
|
1348
1395
|
url.searchParams.set('harness', harness);
|
|
1349
1396
|
if (hintName)
|
|
1350
1397
|
url.searchParams.set('hint_name', hintName);
|
|
1351
|
-
const res = await fetch(url.toString(), {
|
|
1398
|
+
const res = await (this.httpFetch ?? fetch)(url.toString(), {
|
|
1352
1399
|
headers: { 'X-Wire-Device-Secret': deviceSecret },
|
|
1353
1400
|
signal: AbortSignal.timeout(15_000),
|
|
1354
1401
|
});
|
|
@@ -1360,7 +1407,7 @@ export class WireAPI {
|
|
|
1360
1407
|
return json.data || json;
|
|
1361
1408
|
}
|
|
1362
1409
|
async resumeAgent(agentName, deviceSecret, nonce) {
|
|
1363
|
-
const res = await fetch(`${this.baseUrl}/wire/agent/resume`, {
|
|
1410
|
+
const res = await (this.httpFetch ?? fetch)(`${this.baseUrl}/wire/agent/resume`, {
|
|
1364
1411
|
method: 'POST',
|
|
1365
1412
|
headers: {
|
|
1366
1413
|
'Content-Type': 'application/json',
|