agora-skill 1.0.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/.turbo/turbo-build.log +4 -0
- package/.turbo/turbo-test.log +18 -0
- package/dist/auth/credentials.d.ts +22 -0
- package/dist/auth/credentials.d.ts.map +1 -0
- package/dist/auth/credentials.js +65 -0
- package/dist/auth/credentials.js.map +1 -0
- package/dist/bin/agora-skill.d.ts +3 -0
- package/dist/bin/agora-skill.d.ts.map +1 -0
- package/dist/bin/agora-skill.js +22 -0
- package/dist/bin/agora-skill.js.map +1 -0
- package/dist/client.d.ts +73 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +143 -0
- package/dist/client.js.map +1 -0
- package/dist/installer.d.ts +6 -0
- package/dist/installer.d.ts.map +1 -0
- package/dist/installer.js +127 -0
- package/dist/installer.js.map +1 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +50 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/bid.d.ts +26 -0
- package/dist/tools/bid.d.ts.map +1 -0
- package/dist/tools/bid.js +22 -0
- package/dist/tools/bid.js.map +1 -0
- package/dist/tools/deliver.d.ts +26 -0
- package/dist/tools/deliver.d.ts.map +1 -0
- package/dist/tools/deliver.js +22 -0
- package/dist/tools/deliver.js.map +1 -0
- package/dist/tools/publish.d.ts +35 -0
- package/dist/tools/publish.d.ts.map +1 -0
- package/dist/tools/publish.js +28 -0
- package/dist/tools/publish.js.map +1 -0
- package/dist/tools/search.d.ts +31 -0
- package/dist/tools/search.d.ts.map +1 -0
- package/dist/tools/search.js +25 -0
- package/dist/tools/search.js.map +1 -0
- package/dist/tools/status.d.ts +21 -0
- package/dist/tools/status.d.ts.map +1 -0
- package/dist/tools/status.js +18 -0
- package/dist/tools/status.js.map +1 -0
- package/package.json +26 -0
- package/src/auth/credentials.ts +83 -0
- package/src/bin/agora-skill.ts +26 -0
- package/src/client.ts +186 -0
- package/src/installer.ts +154 -0
- package/src/server.ts +85 -0
- package/src/tools/bid.ts +26 -0
- package/src/tools/deliver.ts +26 -0
- package/src/tools/publish.ts +32 -0
- package/src/tools/search.ts +29 -0
- package/src/tools/status.ts +22 -0
- package/test/client.test.ts +174 -0
- package/test/credentials.test.ts +155 -0
- package/test/installer.test.ts +99 -0
- package/test/smoke.test.ts +64 -0
- package/test/tools.test.ts +223 -0
- package/tsconfig.json +8 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export const bidSchema = z.object({
|
|
3
|
+
task_id: z.string().describe('ID of the task to bid on'),
|
|
4
|
+
price: z.number().positive().describe('Your asking price in USDC'),
|
|
5
|
+
estimated_hours: z.number().min(1).max(720).describe('Estimated hours to complete (1-720)'),
|
|
6
|
+
message: z.string().max(1000).optional().describe('Pitch or context for your bid'),
|
|
7
|
+
});
|
|
8
|
+
export async function bid(client, params) {
|
|
9
|
+
const result = await client.submitBid({
|
|
10
|
+
taskId: params.task_id,
|
|
11
|
+
price: params.price,
|
|
12
|
+
estimatedHours: params.estimated_hours,
|
|
13
|
+
message: params.message,
|
|
14
|
+
});
|
|
15
|
+
return {
|
|
16
|
+
bid_id: result.id,
|
|
17
|
+
status: result.status,
|
|
18
|
+
price: `${params.price} USDC`,
|
|
19
|
+
message: `Bid submitted at ${params.price} USDC, ${params.estimated_hours}h estimated.`,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=bid.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bid.js","sourceRoot":"","sources":["../../src/tools/bid.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC;IAChC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,0BAA0B,CAAC;IACxD,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,2BAA2B,CAAC;IAClE,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,qCAAqC,CAAC;IAC3F,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,+BAA+B,CAAC;CACnF,CAAC,CAAA;AAIF,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,MAAmB,EAAE,MAAiB;IAC9D,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC;QACpC,MAAM,EAAE,MAAM,CAAC,OAAO;QACtB,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,cAAc,EAAE,MAAM,CAAC,eAAe;QACtC,OAAO,EAAE,MAAM,CAAC,OAAO;KACxB,CAAC,CAAA;IACF,OAAO;QACL,MAAM,EAAE,MAAM,CAAC,EAAE;QACjB,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,KAAK,EAAE,GAAG,MAAM,CAAC,KAAK,OAAO;QAC7B,OAAO,EAAE,oBAAoB,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,eAAe,cAAc;KACxF,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { AgoraClient } from '../client.js';
|
|
3
|
+
export declare const deliverSchema: z.ZodObject<{
|
|
4
|
+
task_id: z.ZodString;
|
|
5
|
+
content: z.ZodOptional<z.ZodString>;
|
|
6
|
+
file_references: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
7
|
+
notes: z.ZodOptional<z.ZodString>;
|
|
8
|
+
}, "strip", z.ZodTypeAny, {
|
|
9
|
+
task_id: string;
|
|
10
|
+
content?: string | undefined;
|
|
11
|
+
file_references?: string[] | undefined;
|
|
12
|
+
notes?: string | undefined;
|
|
13
|
+
}, {
|
|
14
|
+
task_id: string;
|
|
15
|
+
content?: string | undefined;
|
|
16
|
+
file_references?: string[] | undefined;
|
|
17
|
+
notes?: string | undefined;
|
|
18
|
+
}>;
|
|
19
|
+
export type DeliverParams = z.infer<typeof deliverSchema>;
|
|
20
|
+
export declare function deliver(client: AgoraClient, params: DeliverParams): Promise<{
|
|
21
|
+
deliverable_id: string;
|
|
22
|
+
revision: number;
|
|
23
|
+
status: string;
|
|
24
|
+
message: string;
|
|
25
|
+
}>;
|
|
26
|
+
//# sourceMappingURL=deliver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deliver.d.ts","sourceRoot":"","sources":["../../src/tools/deliver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAE1C,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;EAKxB,CAAA;AAEF,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAA;AAEzD,wBAAsB,OAAO,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,aAAa;;;;;GAavE"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export const deliverSchema = z.object({
|
|
3
|
+
task_id: z.string().describe('ID of the task to deliver for'),
|
|
4
|
+
content: z.string().max(50000).optional().describe('Text content of the deliverable (max 50k chars)'),
|
|
5
|
+
file_references: z.array(z.string()).max(10).optional().describe('URLs to deliverable files (max 10)'),
|
|
6
|
+
notes: z.string().max(2000).optional().describe('Delivery notes for the publisher'),
|
|
7
|
+
});
|
|
8
|
+
export async function deliver(client, params) {
|
|
9
|
+
const result = await client.deliver({
|
|
10
|
+
taskId: params.task_id,
|
|
11
|
+
content: params.content,
|
|
12
|
+
fileReferences: params.file_references,
|
|
13
|
+
notes: params.notes,
|
|
14
|
+
});
|
|
15
|
+
return {
|
|
16
|
+
deliverable_id: result.id,
|
|
17
|
+
revision: result.revision,
|
|
18
|
+
status: result.status,
|
|
19
|
+
message: 'Deliverables submitted. Awaiting publisher review for escrow release.',
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=deliver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deliver.js","sourceRoot":"","sources":["../../src/tools/deliver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC;IACpC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,+BAA+B,CAAC;IAC7D,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,iDAAiD,CAAC;IACrG,eAAe,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,oCAAoC,CAAC;IACtG,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,kCAAkC,CAAC;CACpF,CAAC,CAAA;AAIF,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,MAAmB,EAAE,MAAqB;IACtE,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC;QAClC,MAAM,EAAE,MAAM,CAAC,OAAO;QACtB,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,cAAc,EAAE,MAAM,CAAC,eAAe;QACtC,KAAK,EAAE,MAAM,CAAC,KAAK;KACpB,CAAC,CAAA;IACF,OAAO;QACL,cAAc,EAAE,MAAM,CAAC,EAAE;QACzB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,OAAO,EAAE,uEAAuE;KACjF,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { AgoraClient } from '../client.js';
|
|
3
|
+
export declare const publishSchema: z.ZodObject<{
|
|
4
|
+
title: z.ZodString;
|
|
5
|
+
description: z.ZodString;
|
|
6
|
+
skill: z.ZodString;
|
|
7
|
+
budget: z.ZodNumber;
|
|
8
|
+
deadline: z.ZodString;
|
|
9
|
+
executor_type: z.ZodDefault<z.ZodEnum<["agent", "human", "hybrid"]>>;
|
|
10
|
+
acceptance_criteria: z.ZodOptional<z.ZodString>;
|
|
11
|
+
}, "strip", z.ZodTypeAny, {
|
|
12
|
+
title: string;
|
|
13
|
+
description: string;
|
|
14
|
+
skill: string;
|
|
15
|
+
budget: number;
|
|
16
|
+
deadline: string;
|
|
17
|
+
executor_type: "agent" | "human" | "hybrid";
|
|
18
|
+
acceptance_criteria?: string | undefined;
|
|
19
|
+
}, {
|
|
20
|
+
title: string;
|
|
21
|
+
description: string;
|
|
22
|
+
skill: string;
|
|
23
|
+
budget: number;
|
|
24
|
+
deadline: string;
|
|
25
|
+
executor_type?: "agent" | "human" | "hybrid" | undefined;
|
|
26
|
+
acceptance_criteria?: string | undefined;
|
|
27
|
+
}>;
|
|
28
|
+
export type PublishParams = z.infer<typeof publishSchema>;
|
|
29
|
+
export declare function publish(client: AgoraClient, params: PublishParams): Promise<{
|
|
30
|
+
task_id: string;
|
|
31
|
+
status: string;
|
|
32
|
+
budget: string;
|
|
33
|
+
message: string;
|
|
34
|
+
}>;
|
|
35
|
+
//# sourceMappingURL=publish.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../../src/tools/publish.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAE1C,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;EAQxB,CAAA;AAEF,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAA;AAEzD,wBAAsB,OAAO,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,aAAa;;;;;GAgBvE"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export const publishSchema = z.object({
|
|
3
|
+
title: z.string().min(5).max(200).describe('What you need done (5-200 chars)'),
|
|
4
|
+
description: z.string().min(20).max(5000).describe('Detailed requirements (20-5000 chars)'),
|
|
5
|
+
skill: z.string().describe('Required capability (e.g., "compute", "nlp-sentiment", "legal-review")'),
|
|
6
|
+
budget: z.number().positive().describe('Payment amount in USDC (min 0.01)'),
|
|
7
|
+
deadline: z.string().describe('Deadline — shorthand like "30m", "2h", "1d" or ISO 8601'),
|
|
8
|
+
executor_type: z.enum(['agent', 'human', 'hybrid']).default('agent').describe('Who can do this: agent, human, or hybrid'),
|
|
9
|
+
acceptance_criteria: z.string().optional().describe('How to verify completion (auto-generated if omitted)'),
|
|
10
|
+
});
|
|
11
|
+
export async function publish(client, params) {
|
|
12
|
+
const result = await client.publishTask({
|
|
13
|
+
title: params.title,
|
|
14
|
+
description: params.description,
|
|
15
|
+
skill: params.skill,
|
|
16
|
+
budget: params.budget,
|
|
17
|
+
deadline: params.deadline,
|
|
18
|
+
executorRequirement: params.executor_type,
|
|
19
|
+
acceptanceCriteria: params.acceptance_criteria,
|
|
20
|
+
});
|
|
21
|
+
return {
|
|
22
|
+
task_id: result.id,
|
|
23
|
+
status: result.status,
|
|
24
|
+
budget: `${params.budget} USDC`,
|
|
25
|
+
message: `Task published. Listing stake required to go live.`,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=publish.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publish.js","sourceRoot":"","sources":["../../src/tools/publish.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC;IACpC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,kCAAkC,CAAC;IAC9E,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,uCAAuC,CAAC;IAC3F,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,wEAAwE,CAAC;IACpG,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,mCAAmC,CAAC;IAC3E,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,yDAAyD,CAAC;IACxF,aAAa,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,0CAA0C,CAAC;IACzH,mBAAmB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,sDAAsD,CAAC;CAC5G,CAAC,CAAA;AAIF,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,MAAmB,EAAE,MAAqB;IACtE,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC;QACtC,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,mBAAmB,EAAE,MAAM,CAAC,aAAa;QACzC,kBAAkB,EAAE,MAAM,CAAC,mBAAmB;KAC/C,CAAC,CAAA;IACF,OAAO;QACL,OAAO,EAAE,MAAM,CAAC,EAAE;QAClB,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,OAAO;QAC/B,OAAO,EAAE,oDAAoD;KAC9D,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { AgoraClient } from '../client.js';
|
|
3
|
+
export declare const searchSchema: z.ZodObject<{
|
|
4
|
+
skill: z.ZodOptional<z.ZodString>;
|
|
5
|
+
budget_min: z.ZodOptional<z.ZodNumber>;
|
|
6
|
+
budget_max: z.ZodOptional<z.ZodNumber>;
|
|
7
|
+
executor_type: z.ZodOptional<z.ZodEnum<["agent", "human", "hybrid"]>>;
|
|
8
|
+
keyword: z.ZodOptional<z.ZodString>;
|
|
9
|
+
limit: z.ZodDefault<z.ZodNumber>;
|
|
10
|
+
}, "strip", z.ZodTypeAny, {
|
|
11
|
+
limit: number;
|
|
12
|
+
keyword?: string | undefined;
|
|
13
|
+
skill?: string | undefined;
|
|
14
|
+
executor_type?: "agent" | "human" | "hybrid" | undefined;
|
|
15
|
+
budget_min?: number | undefined;
|
|
16
|
+
budget_max?: number | undefined;
|
|
17
|
+
}, {
|
|
18
|
+
keyword?: string | undefined;
|
|
19
|
+
skill?: string | undefined;
|
|
20
|
+
executor_type?: "agent" | "human" | "hybrid" | undefined;
|
|
21
|
+
budget_min?: number | undefined;
|
|
22
|
+
budget_max?: number | undefined;
|
|
23
|
+
limit?: number | undefined;
|
|
24
|
+
}>;
|
|
25
|
+
export type SearchParams = z.infer<typeof searchSchema>;
|
|
26
|
+
export declare function search(client: AgoraClient, params: SearchParams): Promise<{
|
|
27
|
+
count: number;
|
|
28
|
+
total: number;
|
|
29
|
+
tasks: Record<string, unknown>[];
|
|
30
|
+
}>;
|
|
31
|
+
//# sourceMappingURL=search.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAE1C,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;EAOvB,CAAA;AAEF,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAA;AAEvD,wBAAsB,MAAM,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY;;;;GAcrE"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export const searchSchema = z.object({
|
|
3
|
+
skill: z.string().optional().describe('Filter by required skill (e.g., "compute", "design")'),
|
|
4
|
+
budget_min: z.number().optional().describe('Minimum budget in USDC'),
|
|
5
|
+
budget_max: z.number().optional().describe('Maximum budget in USDC'),
|
|
6
|
+
executor_type: z.enum(['agent', 'human', 'hybrid']).optional().describe('Filter by executor requirement'),
|
|
7
|
+
keyword: z.string().optional().describe('Full-text search in title and description'),
|
|
8
|
+
limit: z.number().default(10).describe('Max results to return (1-100)'),
|
|
9
|
+
});
|
|
10
|
+
export async function search(client, params) {
|
|
11
|
+
const result = await client.searchTasks({
|
|
12
|
+
skills: params.skill,
|
|
13
|
+
budgetMin: params.budget_min,
|
|
14
|
+
budgetMax: params.budget_max,
|
|
15
|
+
executorRequirement: params.executor_type,
|
|
16
|
+
keyword: params.keyword,
|
|
17
|
+
limit: params.limit,
|
|
18
|
+
});
|
|
19
|
+
return {
|
|
20
|
+
count: result.tasks.length,
|
|
21
|
+
total: result.total,
|
|
22
|
+
tasks: result.tasks,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IACnC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,sDAAsD,CAAC;IAC7F,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,wBAAwB,CAAC;IACpE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,wBAAwB,CAAC;IACpE,aAAa,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,gCAAgC,CAAC;IACzG,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,2CAA2C,CAAC;IACpF,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,+BAA+B,CAAC;CACxE,CAAC,CAAA;AAIF,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,MAAmB,EAAE,MAAoB;IACpE,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC;QACtC,MAAM,EAAE,MAAM,CAAC,KAAK;QACpB,SAAS,EAAE,MAAM,CAAC,UAAU;QAC5B,SAAS,EAAE,MAAM,CAAC,UAAU;QAC5B,mBAAmB,EAAE,MAAM,CAAC,aAAa;QACzC,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,KAAK,EAAE,MAAM,CAAC,KAAK;KACpB,CAAC,CAAA;IACF,OAAO;QACL,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM;QAC1B,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,KAAK,EAAE,MAAM,CAAC,KAAK;KACpB,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { AgoraClient } from '../client.js';
|
|
3
|
+
export declare const statusSchema: z.ZodObject<{
|
|
4
|
+
task_id: z.ZodOptional<z.ZodString>;
|
|
5
|
+
role: z.ZodDefault<z.ZodEnum<["publisher", "executor", "all"]>>;
|
|
6
|
+
}, "strip", z.ZodTypeAny, {
|
|
7
|
+
role: "publisher" | "executor" | "all";
|
|
8
|
+
task_id?: string | undefined;
|
|
9
|
+
}, {
|
|
10
|
+
task_id?: string | undefined;
|
|
11
|
+
role?: "publisher" | "executor" | "all" | undefined;
|
|
12
|
+
}>;
|
|
13
|
+
export type StatusParams = z.infer<typeof statusSchema>;
|
|
14
|
+
export declare function status(client: AgoraClient, params: StatusParams): Promise<{
|
|
15
|
+
tasks: Record<string, unknown>[];
|
|
16
|
+
count?: undefined;
|
|
17
|
+
} | {
|
|
18
|
+
count: number;
|
|
19
|
+
tasks: Record<string, unknown>[];
|
|
20
|
+
}>;
|
|
21
|
+
//# sourceMappingURL=status.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/tools/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAE1C,eAAO,MAAM,YAAY;;;;;;;;;EAGvB,CAAA;AAEF,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAA;AAEvD,wBAAsB,MAAM,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY;;;;;;GAWrE"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export const statusSchema = z.object({
|
|
3
|
+
task_id: z.string().optional().describe('Check a specific task (omit for all your tasks)'),
|
|
4
|
+
role: z.enum(['publisher', 'executor', 'all']).default('all').describe('Filter by your role'),
|
|
5
|
+
});
|
|
6
|
+
export async function status(client, params) {
|
|
7
|
+
if (params.task_id) {
|
|
8
|
+
const task = await client.getTaskStatus(params.task_id);
|
|
9
|
+
return { tasks: [task] };
|
|
10
|
+
}
|
|
11
|
+
const status = params.role === 'publisher' ? 'published' : undefined;
|
|
12
|
+
const result = await client.listTasks({ status });
|
|
13
|
+
return {
|
|
14
|
+
count: result.tasks.length,
|
|
15
|
+
tasks: result.tasks,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/tools/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IACnC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,iDAAiD,CAAC;IAC1F,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,qBAAqB,CAAC;CAC9F,CAAC,CAAA;AAIF,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,MAAmB,EAAE,MAAoB;IACpE,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;QACvD,OAAO,EAAE,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,CAAA;IAC1B,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAA;IACpE,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC,CAAA;IACjD,OAAO;QACL,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM;QAC1B,KAAK,EAAE,MAAM,CAAC,KAAK;KACpB,CAAA;AACH,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "agora-skill",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Agora marketplace skill — install once, your agent can publish, bid, and settle tasks",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"agora-skill": "./dist/bin/agora-skill.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "./dist/server.js",
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"lint": "eslint src/",
|
|
13
|
+
"test": "vitest run",
|
|
14
|
+
"test:unit": "vitest run"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
18
|
+
"@inquirer/prompts": "^7.0.0",
|
|
19
|
+
"commander": "^13.1.0",
|
|
20
|
+
"zod": "^3.24.0"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"typescript": "^5.7.0",
|
|
24
|
+
"vitest": "^3.1.0"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs'
|
|
2
|
+
import { join } from 'node:path'
|
|
3
|
+
import { homedir } from 'node:os'
|
|
4
|
+
import { randomBytes } from 'node:crypto'
|
|
5
|
+
|
|
6
|
+
export interface AgentCredentials {
|
|
7
|
+
agent_id: string
|
|
8
|
+
agent_name: string
|
|
9
|
+
api_key: string
|
|
10
|
+
api_key_live: string | null
|
|
11
|
+
api_endpoint: string
|
|
12
|
+
wallet_address: string
|
|
13
|
+
environment: 'sandbox' | 'production'
|
|
14
|
+
created_at: string
|
|
15
|
+
key_rotated_at: string | null
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const AGORA_DIR = join(homedir(), '.agora')
|
|
19
|
+
const CREDENTIALS_DIR = join(AGORA_DIR, 'credentials')
|
|
20
|
+
const WALLETS_DIR = join(AGORA_DIR, 'wallets')
|
|
21
|
+
const DEFAULT_ENDPOINT = 'https://api.agora.youlidao.ai'
|
|
22
|
+
|
|
23
|
+
export function getAgoraDir(): string {
|
|
24
|
+
return AGORA_DIR
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function ensureAgoraDirs(): void {
|
|
28
|
+
for (const dir of [AGORA_DIR, CREDENTIALS_DIR, WALLETS_DIR]) {
|
|
29
|
+
if (!existsSync(dir)) {
|
|
30
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 })
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function loadCredentials(agentName = 'default'): AgentCredentials | null {
|
|
36
|
+
const credPath = join(CREDENTIALS_DIR, `${agentName}.json`)
|
|
37
|
+
if (!existsSync(credPath)) return null
|
|
38
|
+
try {
|
|
39
|
+
const raw = readFileSync(credPath, 'utf-8')
|
|
40
|
+
return JSON.parse(raw) as AgentCredentials
|
|
41
|
+
} catch {
|
|
42
|
+
return null
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function saveCredentials(creds: AgentCredentials, agentName = 'default'): void {
|
|
47
|
+
ensureAgoraDirs()
|
|
48
|
+
const credPath = join(CREDENTIALS_DIR, `${agentName}.json`)
|
|
49
|
+
writeFileSync(credPath, JSON.stringify(creds, null, 2), { mode: 0o600 })
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function generateApiKey(environment: 'sandbox' | 'production'): string {
|
|
53
|
+
const prefix = environment === 'sandbox' ? 'agora_sk_test_' : 'agora_sk_live_'
|
|
54
|
+
return prefix + randomBytes(24).toString('hex')
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function maskApiKey(key: string): string {
|
|
58
|
+
if (key.length <= 20) return key.slice(0, 10) + '****'
|
|
59
|
+
return key.slice(0, -8) + '****' + key.slice(-4)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function getActiveEnvironment(creds: AgentCredentials): 'sandbox' | 'production' {
|
|
63
|
+
return creds.environment
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function getActiveApiKey(creds: AgentCredentials): string {
|
|
67
|
+
if (creds.environment === 'production' && creds.api_key_live) {
|
|
68
|
+
return creds.api_key_live
|
|
69
|
+
}
|
|
70
|
+
return creds.api_key
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function getApiEndpoint(creds: AgentCredentials): string {
|
|
74
|
+
return creds.api_endpoint || DEFAULT_ENDPOINT
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function listAgents(): string[] {
|
|
78
|
+
if (!existsSync(CREDENTIALS_DIR)) return []
|
|
79
|
+
const { readdirSync } = require('node:fs') as typeof import('node:fs')
|
|
80
|
+
return readdirSync(CREDENTIALS_DIR)
|
|
81
|
+
.filter((f: string) => f.endsWith('.json'))
|
|
82
|
+
.map((f: string) => f.replace('.json', ''))
|
|
83
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander'
|
|
4
|
+
import { install } from '../installer.js'
|
|
5
|
+
|
|
6
|
+
const program = new Command()
|
|
7
|
+
.name('agora-skill')
|
|
8
|
+
.description('Agora marketplace skill — install once, your agent can publish, bid, and settle tasks')
|
|
9
|
+
.version('1.0.0')
|
|
10
|
+
|
|
11
|
+
program
|
|
12
|
+
.command('install')
|
|
13
|
+
.description('Install the Agora skill for your agent')
|
|
14
|
+
.option('--endpoint <url>', 'API endpoint override')
|
|
15
|
+
.action(async (opts: { endpoint?: string }) => {
|
|
16
|
+
await install({ endpoint: opts.endpoint })
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
program
|
|
20
|
+
.command('serve')
|
|
21
|
+
.description('Start the Agora MCP server (used by agent platforms)')
|
|
22
|
+
.action(async () => {
|
|
23
|
+
await import('../server.js')
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
program.parse()
|
package/src/client.ts
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto'
|
|
2
|
+
import { type AgentCredentials, getActiveApiKey, getApiEndpoint } from './auth/credentials.js'
|
|
3
|
+
|
|
4
|
+
export class AgoraClient {
|
|
5
|
+
private readonly endpoint: string
|
|
6
|
+
private readonly apiKey: string
|
|
7
|
+
|
|
8
|
+
constructor(creds: AgentCredentials) {
|
|
9
|
+
this.endpoint = getApiEndpoint(creds)
|
|
10
|
+
this.apiKey = getActiveApiKey(creds)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
private async request<T>(method: string, path: string, body?: unknown): Promise<T> {
|
|
14
|
+
const url = `${this.endpoint}${path}`
|
|
15
|
+
const headers: Record<string, string> = {
|
|
16
|
+
'Authorization': `Bearer ${this.apiKey}`,
|
|
17
|
+
'Content-Type': 'application/json',
|
|
18
|
+
'X-Request-Id': randomUUID(),
|
|
19
|
+
'X-Timestamp': new Date().toISOString(),
|
|
20
|
+
'X-Protocol-Version': '1.0.0',
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const res = await fetch(url, {
|
|
24
|
+
method,
|
|
25
|
+
headers,
|
|
26
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
if (!res.ok) {
|
|
30
|
+
const errBody = await res.text()
|
|
31
|
+
throw new Error(`Agora API error ${res.status}: ${errBody}`)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return res.json() as Promise<T>
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// --- Registration (unauthenticated) ---
|
|
38
|
+
|
|
39
|
+
static async register(endpoint: string, params: {
|
|
40
|
+
name: string
|
|
41
|
+
capabilities: string[]
|
|
42
|
+
walletAddress: string
|
|
43
|
+
description?: string
|
|
44
|
+
}): Promise<{ agent: { id: string; apiKey: string; name: string }; protocol: Record<string, unknown> }> {
|
|
45
|
+
const url = `${endpoint}/v1/agents`
|
|
46
|
+
const res = await fetch(url, {
|
|
47
|
+
method: 'POST',
|
|
48
|
+
headers: {
|
|
49
|
+
'Content-Type': 'application/json',
|
|
50
|
+
'X-Request-Id': randomUUID(),
|
|
51
|
+
},
|
|
52
|
+
body: JSON.stringify({
|
|
53
|
+
name: params.name,
|
|
54
|
+
capabilities: params.capabilities,
|
|
55
|
+
walletAddress: params.walletAddress,
|
|
56
|
+
description: params.description || `Agent ${params.name} on Agora`,
|
|
57
|
+
}),
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
if (!res.ok) {
|
|
61
|
+
const errBody = await res.text()
|
|
62
|
+
throw new Error(`Registration failed (${res.status}): ${errBody}`)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return res.json() as Promise<{ agent: { id: string; apiKey: string; name: string }; protocol: Record<string, unknown> }>
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// --- Tasks ---
|
|
69
|
+
|
|
70
|
+
async publishTask(params: {
|
|
71
|
+
title: string
|
|
72
|
+
description: string
|
|
73
|
+
skill: string
|
|
74
|
+
budget: number
|
|
75
|
+
deadline: string
|
|
76
|
+
executorRequirement?: string
|
|
77
|
+
acceptanceCriteria?: string
|
|
78
|
+
executionEnvironment?: string
|
|
79
|
+
}): Promise<{ id: string; status: string }> {
|
|
80
|
+
// Convert deadline shorthand (e.g., "2h", "30m") to ISO 8601
|
|
81
|
+
const deadlineDate = resolveDeadline(params.deadline)
|
|
82
|
+
|
|
83
|
+
return this.request('POST', '/v1/tasks', {
|
|
84
|
+
title: params.title,
|
|
85
|
+
description: params.description,
|
|
86
|
+
requiredSkills: [params.skill],
|
|
87
|
+
budget: params.budget,
|
|
88
|
+
deadline: deadlineDate,
|
|
89
|
+
initiatorRole: 'AA',
|
|
90
|
+
executorRequirement: mapExecutorType(params.executorRequirement || 'agent'),
|
|
91
|
+
executionEnvironment: params.executionEnvironment || 'DIG',
|
|
92
|
+
taskComplexity: 'ATM',
|
|
93
|
+
acceptanceCriteria: params.acceptanceCriteria || `Complete the task as described: ${params.title}`,
|
|
94
|
+
paymentMethod: 'x402',
|
|
95
|
+
})
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async searchTasks(params: {
|
|
99
|
+
skills?: string
|
|
100
|
+
budgetMin?: number
|
|
101
|
+
budgetMax?: number
|
|
102
|
+
executorRequirement?: string
|
|
103
|
+
keyword?: string
|
|
104
|
+
limit?: number
|
|
105
|
+
}): Promise<{ tasks: Array<Record<string, unknown>>; total: number }> {
|
|
106
|
+
const query = new URLSearchParams()
|
|
107
|
+
if (params.skills) query.set('skills', params.skills)
|
|
108
|
+
if (params.budgetMin) query.set('budgetMin', String(params.budgetMin))
|
|
109
|
+
if (params.budgetMax) query.set('budgetMax', String(params.budgetMax))
|
|
110
|
+
if (params.executorRequirement) query.set('executorRequirement', params.executorRequirement)
|
|
111
|
+
if (params.keyword) query.set('keyword', params.keyword)
|
|
112
|
+
if (params.limit) query.set('pageSize', String(params.limit))
|
|
113
|
+
|
|
114
|
+
return this.request('GET', `/v1/tasks/search?${query.toString()}`)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async submitBid(params: {
|
|
118
|
+
taskId: string
|
|
119
|
+
price: number
|
|
120
|
+
estimatedHours: number
|
|
121
|
+
message?: string
|
|
122
|
+
}): Promise<{ id: string; status: string }> {
|
|
123
|
+
return this.request('POST', `/v1/tasks/${params.taskId}/bids`, {
|
|
124
|
+
price: params.price,
|
|
125
|
+
estimatedHours: params.estimatedHours,
|
|
126
|
+
message: params.message,
|
|
127
|
+
})
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async deliver(params: {
|
|
131
|
+
taskId: string
|
|
132
|
+
content?: string
|
|
133
|
+
fileReferences?: string[]
|
|
134
|
+
notes?: string
|
|
135
|
+
}): Promise<{ id: string; status: string; revision: number }> {
|
|
136
|
+
return this.request('POST', `/v1/tasks/${params.taskId}/deliverables`, {
|
|
137
|
+
content: params.content,
|
|
138
|
+
fileReferences: params.fileReferences,
|
|
139
|
+
notes: params.notes,
|
|
140
|
+
})
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async getTaskStatus(taskId: string): Promise<Record<string, unknown>> {
|
|
144
|
+
return this.request('GET', `/v1/tasks/${taskId}`)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async listTasks(params?: {
|
|
148
|
+
status?: string
|
|
149
|
+
page?: number
|
|
150
|
+
pageSize?: number
|
|
151
|
+
}): Promise<{ tasks: Array<Record<string, unknown>>; total: number }> {
|
|
152
|
+
const query = new URLSearchParams()
|
|
153
|
+
if (params?.status) query.set('status', params.status)
|
|
154
|
+
if (params?.page) query.set('page', String(params.page))
|
|
155
|
+
if (params?.pageSize) query.set('pageSize', String(params.pageSize))
|
|
156
|
+
return this.request('GET', `/v1/tasks?${query.toString()}`)
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function mapExecutorType(friendly: string): string {
|
|
161
|
+
const map: Record<string, string> = {
|
|
162
|
+
'agent': 'MX',
|
|
163
|
+
'human': 'HR',
|
|
164
|
+
'hybrid': 'FL',
|
|
165
|
+
// Also accept raw enum values
|
|
166
|
+
'MX': 'MX',
|
|
167
|
+
'HR': 'HR',
|
|
168
|
+
'FL': 'FL',
|
|
169
|
+
}
|
|
170
|
+
return map[friendly] || 'FL'
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function resolveDeadline(shorthand: string): string {
|
|
174
|
+
const now = new Date()
|
|
175
|
+
const match = shorthand.match(/^(\d+)(m|h|d)$/)
|
|
176
|
+
if (match) {
|
|
177
|
+
const [, num, unit] = match
|
|
178
|
+
const value = parseInt(num!, 10)
|
|
179
|
+
if (unit === 'm') now.setMinutes(now.getMinutes() + value)
|
|
180
|
+
else if (unit === 'h') now.setHours(now.getHours() + value)
|
|
181
|
+
else if (unit === 'd') now.setDate(now.getDate() + value)
|
|
182
|
+
return now.toISOString()
|
|
183
|
+
}
|
|
184
|
+
// Assume ISO 8601 already
|
|
185
|
+
return shorthand
|
|
186
|
+
}
|