crewpay-goat-plugin 0.1.1 → 0.2.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
@@ -15,23 +15,21 @@ const dry = await plugin.service.crewpay_launch_dry_run({
15
15
  ticker: 'DCAT',
16
16
  autoHire: { seats: 3 },
17
17
  })
18
- // human confirms…
18
+ // human opens dry.approvalUrl…
19
19
  await plugin.service.crewpay_launch({
20
20
  name: 'Desk Cat',
21
21
  ticker: 'DCAT',
22
22
  autoHire: { seats: 3 },
23
- dryRunToken: dry.dryRunToken,
24
- humanConfirmed: true,
25
- confirmPhrase: 'APPROVE_SOL_SPEND',
23
+ dryRunId: dry.dryRunId,
26
24
  })
27
25
  ```
28
26
 
29
- Prefer `npx -y crewpay-mcp@1.2.1` for local signing; hosted MCP `https://mcp.crewpay.dev/mcp` for discover/autohire without a launcher secret.
27
+ Prefer `npx -y crewpay-mcp@1.2.3` for local signing; hosted MCP `https://mcp.crewpay.dev/mcp` for discover/autohire without a launcher secret.
30
28
 
31
29
  ## Safety
32
30
 
33
31
  - Fee map **60/15/25**; buyback cron not live yet
34
- - Launch/wire require dry-run token + exact phrase `APPROVE_SOL_SPEND`
32
+ - Launch requires server `dryRunId` after human approval on `approvalUrl`
35
33
 
36
34
  ## Links
37
35
 
package/dist/client.d.ts CHANGED
@@ -2,21 +2,17 @@
2
2
  * Minimal CrewPay REST client for framework plugins.
3
3
  * Keys from env only — never accept private keys as function arguments.
4
4
  *
5
- * Spend gates: dry-run issues a short-lived dryRunToken; launch/wire require that
6
- * token (launch) plus the exact confirmPhrase APPROVE_SOL_SPEND (not a free-form
7
- * boolean the model can invent from chat alone).
5
+ * Spend gate: POST /api/agent/launch/dry-run returns dryRunId + approvalUrl
6
+ * (no approve secret). Operator opens approvalUrl and wallet-signs.
7
+ * Launch/wire require dryRunId after approval. Image content is bound by sha256.
8
8
  */
9
9
  export declare const DEFAULT_API_URL = "https://api.crewpay.dev";
10
- /** Exact phrase a human must supply for SOL-spending calls. */
11
- export declare const SOL_SPEND_CONFIRM_PHRASE = "APPROVE_SOL_SPEND";
12
10
  export type CrewPayEnv = {
13
11
  apiUrl?: string;
14
12
  apiKey?: string;
15
13
  launcherKey?: string;
16
14
  };
17
15
  export declare function loadCrewPayEnv(overrides?: CrewPayEnv): Required<Pick<CrewPayEnv, 'apiUrl'>> & CrewPayEnv;
18
- /** Canonical hash of launch fields so dry-run and launch bodies must match. */
19
- export declare function hashLaunchBody(body: Record<string, unknown>): string;
20
16
  export declare class CrewPayClient {
21
17
  private readonly env;
22
18
  constructor(env?: ReturnType<typeof loadCrewPayEnv>);
@@ -32,27 +28,19 @@ export declare class CrewPayClient {
32
28
  model?: string;
33
29
  }): Promise<unknown>;
34
30
  autohire(body: Record<string, unknown>): Promise<unknown>;
35
- dryRun(body: Record<string, unknown>): Promise<{
36
- dryRunToken: string;
37
- confirmPhraseRequired: string;
38
- tip: string;
39
- }>;
40
- /**
41
- * Real launch — spends SOL. Requires a prior dryRunToken for this body plus
42
- * humanConfirmed and confirmPhrase APPROVE_SOL_SPEND.
43
- */
31
+ /** Server dry-run — returns plan + dryRunId + approvalUrl (no approve secret). */
32
+ dryRun(body: Record<string, unknown>): Promise<unknown>;
44
33
  launch(body: Record<string, unknown>, opts: {
45
- humanConfirmed: boolean;
46
- confirmPhrase: string;
47
- dryRunToken: string;
34
+ dryRunId: string;
48
35
  }): Promise<unknown>;
49
36
  wireFees(body: {
50
37
  mint: string;
51
38
  mode?: string;
52
39
  crew?: unknown[];
40
+ name?: string;
41
+ ticker?: string;
53
42
  }, opts: {
54
- humanConfirmed: boolean;
55
- confirmPhrase: string;
43
+ dryRunId: string;
56
44
  }): Promise<unknown>;
57
45
  crank(body: {
58
46
  mint: string;
package/dist/client.js CHANGED
@@ -2,16 +2,11 @@
2
2
  * Minimal CrewPay REST client for framework plugins.
3
3
  * Keys from env only — never accept private keys as function arguments.
4
4
  *
5
- * Spend gates: dry-run issues a short-lived dryRunToken; launch/wire require that
6
- * token (launch) plus the exact confirmPhrase APPROVE_SOL_SPEND (not a free-form
7
- * boolean the model can invent from chat alone).
5
+ * Spend gate: POST /api/agent/launch/dry-run returns dryRunId + approvalUrl
6
+ * (no approve secret). Operator opens approvalUrl and wallet-signs.
7
+ * Launch/wire require dryRunId after approval. Image content is bound by sha256.
8
8
  */
9
- import { createHash, randomBytes } from 'node:crypto';
10
9
  export const DEFAULT_API_URL = 'https://api.crewpay.dev';
11
- /** Exact phrase a human must supply for SOL-spending calls. */
12
- export const SOL_SPEND_CONFIRM_PHRASE = 'APPROVE_SOL_SPEND';
13
- const pendingDryRuns = new Map();
14
- const DRY_RUN_TTL_MS = 30 * 60 * 1000;
15
10
  export function loadCrewPayEnv(overrides = {}) {
16
11
  return {
17
12
  apiUrl: (overrides.apiUrl || process.env.CREW_API_URL || DEFAULT_API_URL).replace(/\/$/, ''),
@@ -24,29 +19,6 @@ export function loadCrewPayEnv(overrides = {}) {
24
19
  '',
25
20
  };
26
21
  }
27
- /** Canonical hash of launch fields so dry-run and launch bodies must match. */
28
- export function hashLaunchBody(body) {
29
- const pick = {
30
- name: body.name,
31
- ticker: body.ticker,
32
- description: body.description ?? null,
33
- mode: body.mode ?? 'agent',
34
- initialBuySol: body.initialBuySol ?? 0,
35
- imageUrl: body.imageUrl ?? null,
36
- autoHire: body.autoHire ?? null,
37
- crew: body.crew ?? null,
38
- holderKol: body.holderKol ?? false,
39
- };
40
- return createHash('sha256').update(JSON.stringify(pick)).digest('hex');
41
- }
42
- function assertSpendConfirm(opts, action) {
43
- if (opts.humanConfirmed !== true) {
44
- throw new Error(`${action} blocked: humanConfirmed must be true after an explicit human approval`);
45
- }
46
- if (opts.confirmPhrase !== SOL_SPEND_CONFIRM_PHRASE) {
47
- throw new Error(`${action} blocked: confirmPhrase must be exactly "${SOL_SPEND_CONFIRM_PHRASE}" (human-supplied; do not invent)`);
48
- }
49
- }
50
22
  export class CrewPayClient {
51
23
  env;
52
24
  constructor(env = loadCrewPayEnv()) {
@@ -102,52 +74,36 @@ export class CrewPayClient {
102
74
  body: JSON.stringify(body),
103
75
  });
104
76
  }
105
- async dryRun(body) {
106
- const data = await this.fetch('/api/agent/launch/dry-run', {
77
+ /** Server dry-run — returns plan + dryRunId + approvalUrl (no approve secret). */
78
+ dryRun(body) {
79
+ return this.fetch('/api/agent/launch/dry-run', {
107
80
  method: 'POST',
108
81
  auth: true,
109
82
  body: JSON.stringify(body),
110
83
  });
111
- const dryRunToken = randomBytes(16).toString('hex');
112
- pendingDryRuns.set(dryRunToken, {
113
- bodyHash: hashLaunchBody(body),
114
- expiresAt: Date.now() + DRY_RUN_TTL_MS,
115
- });
116
- return {
117
- ...(typeof data === 'object' && data ? data : { result: data }),
118
- dryRunToken,
119
- confirmPhraseRequired: SOL_SPEND_CONFIRM_PHRASE,
120
- tip: `To launch: pass the same body + dryRunToken + humanConfirmed:true + confirmPhrase:"${SOL_SPEND_CONFIRM_PHRASE}" (human must supply the phrase).`,
121
- };
122
84
  }
123
- /**
124
- * Real launch — spends SOL. Requires a prior dryRunToken for this body plus
125
- * humanConfirmed and confirmPhrase APPROVE_SOL_SPEND.
126
- */
127
85
  launch(body, opts) {
128
- assertSpendConfirm(opts, 'Launch');
129
- const pending = pendingDryRuns.get(opts.dryRunToken);
130
- if (!pending || pending.expiresAt < Date.now()) {
131
- throw new Error('Launch blocked: missing/expired dryRunToken — call dryRun first and reuse its dryRunToken');
132
- }
133
- if (pending.bodyHash !== hashLaunchBody(body)) {
134
- throw new Error('Launch blocked: body does not match the dry-run that issued dryRunToken');
86
+ const dryRunId = String(opts.dryRunId || '').trim();
87
+ if (!dryRunId) {
88
+ throw new Error('Launch blocked: dryRunId required — dry-run, operator wallet-approves on approvalUrl, then launch');
135
89
  }
136
- pendingDryRuns.delete(opts.dryRunToken);
137
90
  return this.fetch('/api/agent/launch', {
138
91
  method: 'POST',
139
92
  auth: true,
140
93
  launcher: true,
141
- body: JSON.stringify(body),
94
+ body: JSON.stringify({ ...body, dryRunId }),
142
95
  });
143
96
  }
144
97
  wireFees(body, opts) {
145
- assertSpendConfirm(opts, 'Wire-fees');
98
+ const dryRunId = String(opts.dryRunId || '').trim();
99
+ if (!dryRunId) {
100
+ throw new Error('Wire-fees blocked: dryRunId required — dry-run with intent=wire-fees, wallet-approve, then wire');
101
+ }
146
102
  return this.fetch('/api/agent/wire-fees', {
147
103
  method: 'POST',
148
104
  auth: true,
149
105
  launcher: true,
150
- body: JSON.stringify(body),
106
+ body: JSON.stringify({ ...body, dryRunId }),
151
107
  });
152
108
  }
153
109
  crank(body) {
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * GOAT SDK plugin scaffold for CrewPay.
3
- * Prefer MCP: npx -y crewpay-mcp@1.2.1 or https://mcp.crewpay.dev/mcp
3
+ * Prefer MCP: npx -y crewpay-mcp@1.2.3 or https://mcp.crewpay.dev/mcp
4
4
  */
5
5
  export type CrewPayGoatOptions = {
6
6
  apiUrl?: string;
@@ -11,24 +11,17 @@ export declare class CrewPayGoatService {
11
11
  constructor(opts?: CrewPayGoatOptions);
12
12
  crewpay_discover(): Promise<unknown>;
13
13
  crewpay_autohire(params: Record<string, unknown>): Promise<unknown>;
14
- crewpay_launch_dry_run(params: Record<string, unknown>): Promise<{
15
- dryRunToken: string;
16
- confirmPhraseRequired: string;
17
- tip: string;
18
- }>;
14
+ crewpay_launch_dry_run(params: Record<string, unknown>): Promise<unknown>;
19
15
  /**
20
- * Spends SOL. Requires dryRunToken from dry-run + confirmPhrase APPROVE_SOL_SPEND + humanConfirmed.
16
+ * Spends SOL. Requires dryRunId from dry-run after human approval on approvalUrl.
21
17
  */
22
18
  crewpay_launch(params: Record<string, unknown> & {
23
- humanConfirmed?: boolean;
24
- confirmPhrase?: string;
25
- dryRunToken?: string;
19
+ dryRunId?: string;
26
20
  }): Promise<unknown>;
27
21
  crewpay_wire_fees(params: {
28
22
  mint: string;
29
23
  mode?: string;
30
- humanConfirmed?: boolean;
31
- confirmPhrase?: string;
24
+ dryRunId?: string;
32
25
  }): Promise<unknown>;
33
26
  crewpay_crank(params: {
34
27
  mint: string;
@@ -38,6 +31,6 @@ export declare class CrewPayGoatService {
38
31
  export declare function crewpay(options?: CrewPayGoatOptions): {
39
32
  name: string;
40
33
  description: string;
41
- service: CrewPayGoatService;
34
+ tools: CrewPayGoatService;
42
35
  };
43
36
  export default crewpay;
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * GOAT SDK plugin scaffold for CrewPay.
3
- * Prefer MCP: npx -y crewpay-mcp@1.2.1 or https://mcp.crewpay.dev/mcp
3
+ * Prefer MCP: npx -y crewpay-mcp@1.2.3 or https://mcp.crewpay.dev/mcp
4
4
  */
5
- import { CrewPayClient, loadCrewPayEnv, SOL_SPEND_CONFIRM_PHRASE, } from './client.js';
5
+ import { CrewPayClient, loadCrewPayEnv } from './client.js';
6
6
  function api(opts = {}) {
7
7
  return new CrewPayClient(loadCrewPayEnv(opts));
8
8
  }
@@ -21,22 +21,16 @@ export class CrewPayGoatService {
21
21
  return api(this.opts).dryRun(params);
22
22
  }
23
23
  /**
24
- * Spends SOL. Requires dryRunToken from dry-run + confirmPhrase APPROVE_SOL_SPEND + humanConfirmed.
24
+ * Spends SOL. Requires dryRunId from dry-run after human approval on approvalUrl.
25
25
  */
26
26
  async crewpay_launch(params) {
27
- const { humanConfirmed, confirmPhrase, dryRunToken, ...rest } = params;
27
+ const { dryRunId, humanConfirmed: _h, confirmPhrase: _c, dryRunToken: _t, ...rest } = params;
28
28
  return api(this.opts).launch(rest, {
29
- humanConfirmed: humanConfirmed === true,
30
- confirmPhrase: confirmPhrase || '',
31
- dryRunToken: dryRunToken || '',
29
+ dryRunId: dryRunId || '',
32
30
  });
33
31
  }
34
32
  async crewpay_wire_fees(params) {
35
- const { humanConfirmed, confirmPhrase, mint, mode } = params;
36
- return api(this.opts).wireFees({ mint, mode }, {
37
- humanConfirmed: humanConfirmed === true,
38
- confirmPhrase: confirmPhrase || '',
39
- });
33
+ return api(this.opts).wireFees({ mint: params.mint, mode: params.mode }, { dryRunId: params.dryRunId || '' });
40
34
  }
41
35
  async crewpay_crank(params) {
42
36
  return api(this.opts).crank(params);
@@ -48,8 +42,8 @@ export class CrewPayGoatService {
48
42
  export function crewpay(options = {}) {
49
43
  return {
50
44
  name: 'crewpay',
51
- description: `CrewPay — Pump.fun KOL Autohire + fee-shares (60/15/25). Buyback not live. Dry-run token + ${SOL_SPEND_CONFIRM_PHRASE} before launch.`,
52
- service: new CrewPayGoatService(options),
45
+ description: 'CrewPay — Pump.fun KOL Autohire + fee-shares (60/15/25). Buyback not live. Dry-run → approvalUrl → launch with dryRunId.',
46
+ tools: new CrewPayGoatService(options),
53
47
  };
54
48
  }
55
49
  export default crewpay;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "crewpay-goat-plugin",
3
- "version": "0.1.1",
4
- "description": "GOAT SDK plugin for CrewPay REST tools. Fee map 60/15/25; buyback not live; dryRunToken + APPROVE_SOL_SPEND before launch.",
3
+ "version": "0.2.0",
4
+ "description": "GOAT SDK plugin for CrewPay REST tools. Fee map 60/15/25; buyback not live; dryRunId after approvalUrl before launch.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
@@ -17,8 +17,7 @@
17
17
  "LICENSE"
18
18
  ],
19
19
  "scripts": {
20
- "build": "tsc -p tsconfig.json",
21
- "prepublishOnly": "npm run build"
20
+ "build": "tsc -p tsconfig.json"
22
21
  },
23
22
  "keywords": [
24
23
  "goat-sdk",
@@ -45,5 +44,6 @@
45
44
  },
46
45
  "publishConfig": {
47
46
  "access": "public"
48
- }
47
+ },
48
+ "private": false
49
49
  }