@gram-ai/create-function 0.1.1 → 0.2.1
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/main.js +38 -4
- package/dist/main.js.map +1 -1
- package/gram-template-gram/NEXT_STEPS.txt +14 -0
- package/gram-template-gram/README.md +58 -0
- package/gram-template-gram/package.json +5 -2
- package/gram-template-gram/src/server.ts +44 -0
- package/package.json +2 -2
- package/src/main.ts +42 -6
- /package/gram-template-gram/{.gitignore → gitignore} +0 -0
- /package/gram-template-mcp/{.gitignore → gitignore} +0 -0
package/dist/main.js
CHANGED
|
@@ -9,6 +9,25 @@ import pkg from "../package.json" with { type: "json" };
|
|
|
9
9
|
import { confirmOrClack, selectOrClack, textOrClack, yn, } from "./prompts/helpers.js";
|
|
10
10
|
const packageNameRE = /^(@?[a-z0-9-_]+\/)?[a-z0-9-_]+$/;
|
|
11
11
|
const knownPackageManagers = new Set(["npm", "yarn", "pnpm", "bun", "deno"]);
|
|
12
|
+
function printUsage(packageManager) {
|
|
13
|
+
console.log(`
|
|
14
|
+
Usage:
|
|
15
|
+
${packageManager} create @gram-ai/function [options]
|
|
16
|
+
|
|
17
|
+
Options:
|
|
18
|
+
--template <name> Template to use (gram, mcp)
|
|
19
|
+
--name <name> Project name
|
|
20
|
+
--dir <path> Directory to create project in
|
|
21
|
+
--git <yes|no> Initialize git repository
|
|
22
|
+
--install <yes|no> Install dependencies
|
|
23
|
+
-y, --yes Skip all prompts and use defaults
|
|
24
|
+
|
|
25
|
+
Examples:
|
|
26
|
+
${packageManager} create @gram-ai/function
|
|
27
|
+
${packageManager} create @gram-ai/function --template mcp --name ecommerce
|
|
28
|
+
${packageManager} create @gram-ai/function --yes --template gram
|
|
29
|
+
`);
|
|
30
|
+
}
|
|
12
31
|
async function init(argv) {
|
|
13
32
|
let packageManager = "npm";
|
|
14
33
|
let detectedPM = process.env["npm_config_user_agent"]?.split("/")[0] || "";
|
|
@@ -16,10 +35,14 @@ async function init(argv) {
|
|
|
16
35
|
packageManager = detectedPM;
|
|
17
36
|
}
|
|
18
37
|
const args = parse(argv, {
|
|
19
|
-
alias: { y: "yes" },
|
|
38
|
+
alias: { y: "yes", h: "help" },
|
|
20
39
|
string: ["template", "name", "dir", "git", "install"],
|
|
21
|
-
boolean: ["yes"],
|
|
40
|
+
boolean: ["yes", "help"],
|
|
22
41
|
});
|
|
42
|
+
if (args.help) {
|
|
43
|
+
printUsage(packageManager);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
23
46
|
const template = await selectOrClack({
|
|
24
47
|
message: "Pick a framework",
|
|
25
48
|
options: [
|
|
@@ -105,7 +128,7 @@ async function init(argv) {
|
|
|
105
128
|
await fs.cp(templateDir, dir, {
|
|
106
129
|
recursive: true,
|
|
107
130
|
filter: (src) => {
|
|
108
|
-
let banned = src.includes(".git");
|
|
131
|
+
let banned = src.includes(".git") || src.includes("NEXT_STEPS.txt");
|
|
109
132
|
if (isLocalDev) {
|
|
110
133
|
banned ||= src.includes("node_modules") || src.includes("dist");
|
|
111
134
|
}
|
|
@@ -134,6 +157,10 @@ async function init(argv) {
|
|
|
134
157
|
deps["@gram-ai/functions"] = gramFuncsVersion;
|
|
135
158
|
}
|
|
136
159
|
await fs.writeFile(join(dir, "package.json"), JSON.stringify(dstPkg, null, 2));
|
|
160
|
+
const gitignorePath = join(dir, "gitignore");
|
|
161
|
+
if (existsSync(gitignorePath)) {
|
|
162
|
+
await fs.rename(gitignorePath, join(dir, ".gitignore"));
|
|
163
|
+
}
|
|
137
164
|
const contributingPath = join(dir, "CONTRIBUTING.md");
|
|
138
165
|
if (existsSync(contributingPath)) {
|
|
139
166
|
tlog.message("Creating symlinks for CONTRIBUTING.md");
|
|
@@ -148,7 +175,14 @@ async function init(argv) {
|
|
|
148
175
|
tlog.message(`Installing dependencies with ${packageManager}`);
|
|
149
176
|
await $ `cd ${dir} && ${packageManager} install`;
|
|
150
177
|
}
|
|
151
|
-
|
|
178
|
+
let successMessage = `All done! Run \`cd ${dir} && ${packageManager} run build\` to build your first Gram Function.`;
|
|
179
|
+
successMessage = await fs
|
|
180
|
+
.readFile(join(templateDir, "NEXT_STEPS.txt"), "utf-8")
|
|
181
|
+
.catch(() => successMessage);
|
|
182
|
+
successMessage = successMessage
|
|
183
|
+
.replaceAll("$PACKAGE_MANAGER", packageManager)
|
|
184
|
+
.replaceAll("$DIR", dir);
|
|
185
|
+
tlog.success(successMessage);
|
|
152
186
|
}
|
|
153
187
|
try {
|
|
154
188
|
await init(process.argv);
|
package/dist/main.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,OAAO,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,CAAC,EAAE,MAAM,IAAI,CAAC;AACvB,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,OAAO,GAAG,MAAM,iBAAiB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAExD,OAAO,EACL,cAAc,EACd,aAAa,EACb,WAAW,EACX,EAAE,GACH,MAAM,sBAAsB,CAAC;AAE9B,MAAM,aAAa,GAAG,iCAAiC,CAAC;AAExD,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;AAE7E,KAAK,UAAU,IAAI,CAAC,IAAc;IAChC,IAAI,cAAc,GAAG,KAAK,CAAC;IAC3B,IAAI,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC3E,IAAI,oBAAoB,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;QACzC,cAAc,GAAG,UAAU,CAAC;IAC9B,CAAC;IAED,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE;QACvB,KAAK,EAAE,EAAE,CAAC,EAAE,KAAK,EAAE;
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
All done! Jump in with `cd $DIR`.
|
|
2
|
+
|
|
3
|
+
Some next steps:
|
|
4
|
+
|
|
5
|
+
- Build your function with `$PACKAGE_MANAGER run build` and deploy it with the Gram CLI: https://www.speakeasy.com/docs/gram/command-line/installation.
|
|
6
|
+
|
|
7
|
+
- Run the provided Hono server to simulate tool calls over HTTP with `$PACKAGE_MANAGER run dev` and:
|
|
8
|
+
|
|
9
|
+
curl \
|
|
10
|
+
--data '{"name": "greet", "input": {"name": "Friend"}}' \
|
|
11
|
+
-H "Content-Type: application/json" \
|
|
12
|
+
http://localhost:3000/tool-call
|
|
13
|
+
|
|
14
|
+
Have fun 🚀
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Hello from Gram Functions!
|
|
2
|
+
|
|
3
|
+
This project builds and deploys [Gram Functions](https://getgram.ai) using a
|
|
4
|
+
tiny TypeScript framework that looks like this:
|
|
5
|
+
|
|
6
|
+
```ts
|
|
7
|
+
import { Gram } from "@gram-ai/functions";
|
|
8
|
+
import * as z from "zod/mini";
|
|
9
|
+
|
|
10
|
+
const gram = new Gram().tool({
|
|
11
|
+
name: "greet",
|
|
12
|
+
description: "Greet someone special",
|
|
13
|
+
inputSchema: { name: z.string() },
|
|
14
|
+
async execute(ctx, input) {
|
|
15
|
+
return ctx.json({ message: `Hello, ${input.name}!` });
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
export default gram;
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Gram Functions are tools for LLMs and MCP servers that can do arbitrary tasks
|
|
23
|
+
such as fetching data from APIs, performing calculations, or interacting with
|
|
24
|
+
hosted databases.
|
|
25
|
+
|
|
26
|
+
## Getting Started
|
|
27
|
+
|
|
28
|
+
To get started, install dependencies and run the development server:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
pnpm install
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
To build a zip file that can be deployed to Gram, run:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pnpm build
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
If you want to poke at the tools you've built during local development, you can
|
|
41
|
+
start a Hono server with:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pnpm dev
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Now you can simulate tool calls with:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
curl \
|
|
51
|
+
--data '{"name": "greet", "input": {"name": "Georges"}}' \
|
|
52
|
+
-H "Content-Type: application/json" \
|
|
53
|
+
http://localhost:3000/tool-call
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## What next?
|
|
57
|
+
|
|
58
|
+
To learn more about using the framework, check out [CONTRIBUTING.md](./CONTRIBUTING.md)
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"node": ">=22.18.0"
|
|
20
20
|
},
|
|
21
21
|
"scripts": {
|
|
22
|
+
"dev": "node ./src/server.ts",
|
|
22
23
|
"lint": "tsc --noEmit",
|
|
23
24
|
"build": "node ./src/build.ts",
|
|
24
25
|
"prebuild": "tsc -p tsconfig.json",
|
|
@@ -29,7 +30,9 @@
|
|
|
29
30
|
"zod": "^4"
|
|
30
31
|
},
|
|
31
32
|
"devDependencies": {
|
|
32
|
-
"
|
|
33
|
-
"@types/node": "22.x"
|
|
33
|
+
"@hono/node-server": "^1.19.5",
|
|
34
|
+
"@types/node": "22.x",
|
|
35
|
+
"hono": "^4",
|
|
36
|
+
"typescript": "^5"
|
|
34
37
|
}
|
|
35
38
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { serve } from "@hono/node-server";
|
|
2
|
+
import { Hono } from "hono";
|
|
3
|
+
import gram from "./functions.ts";
|
|
4
|
+
|
|
5
|
+
const app = new Hono();
|
|
6
|
+
|
|
7
|
+
app.post("/tool-call", async (c) => {
|
|
8
|
+
const req = await c.req.json();
|
|
9
|
+
return await gram.handleToolCall(req, {
|
|
10
|
+
signal: AbortSignal.timeout(1 * 60 * 1000),
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
app.get("/manifest", async () => {
|
|
15
|
+
const manifest = gram.manifest();
|
|
16
|
+
return new Response(JSON.stringify(manifest, null, 2), {
|
|
17
|
+
headers: { "Content-Type": "application/json" },
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
export function startServer(port: number = 3000) {
|
|
22
|
+
const server = serve({ fetch: app.fetch, port }, (info) => {
|
|
23
|
+
console.log(`Listening on http://localhost:${info.port}`);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const onClose = () => {
|
|
27
|
+
console.log("Shutting down server...");
|
|
28
|
+
server.close((err) => {
|
|
29
|
+
if (err) {
|
|
30
|
+
console.error(err);
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
process.exit(0);
|
|
34
|
+
});
|
|
35
|
+
};
|
|
36
|
+
process.on("SIGINT", onClose);
|
|
37
|
+
process.on("SIGTERM", onClose);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (import.meta.main) {
|
|
41
|
+
startServer();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export default app;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@gram-ai/create-function",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.2.1",
|
|
5
5
|
"description": "Build AI tools and deploy them to getgram.ai",
|
|
6
6
|
"keywords": [],
|
|
7
7
|
"homepage": "https://github.com/speakeasy-api/gram",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"prettier": "^3.6.2",
|
|
39
39
|
"typescript": "5.9.2",
|
|
40
40
|
"zod": "^3.25.76",
|
|
41
|
-
"@gram-ai/functions": "^0.1
|
|
41
|
+
"@gram-ai/functions": "^0.2.1"
|
|
42
42
|
},
|
|
43
43
|
"scripts": {
|
|
44
44
|
"build": "tsc --noEmit false"
|
package/src/main.ts
CHANGED
|
@@ -18,6 +18,26 @@ const packageNameRE = /^(@?[a-z0-9-_]+\/)?[a-z0-9-_]+$/;
|
|
|
18
18
|
|
|
19
19
|
const knownPackageManagers = new Set(["npm", "yarn", "pnpm", "bun", "deno"]);
|
|
20
20
|
|
|
21
|
+
function printUsage(packageManager: string): void {
|
|
22
|
+
console.log(`
|
|
23
|
+
Usage:
|
|
24
|
+
${packageManager} create @gram-ai/function [options]
|
|
25
|
+
|
|
26
|
+
Options:
|
|
27
|
+
--template <name> Template to use (gram, mcp)
|
|
28
|
+
--name <name> Project name
|
|
29
|
+
--dir <path> Directory to create project in
|
|
30
|
+
--git <yes|no> Initialize git repository
|
|
31
|
+
--install <yes|no> Install dependencies
|
|
32
|
+
-y, --yes Skip all prompts and use defaults
|
|
33
|
+
|
|
34
|
+
Examples:
|
|
35
|
+
${packageManager} create @gram-ai/function
|
|
36
|
+
${packageManager} create @gram-ai/function --template mcp --name ecommerce
|
|
37
|
+
${packageManager} create @gram-ai/function --yes --template gram
|
|
38
|
+
`);
|
|
39
|
+
}
|
|
40
|
+
|
|
21
41
|
async function init(argv: string[]): Promise<void> {
|
|
22
42
|
let packageManager = "npm";
|
|
23
43
|
let detectedPM = process.env["npm_config_user_agent"]?.split("/")[0] || "";
|
|
@@ -26,11 +46,16 @@ async function init(argv: string[]): Promise<void> {
|
|
|
26
46
|
}
|
|
27
47
|
|
|
28
48
|
const args = parse(argv, {
|
|
29
|
-
alias: { y: "yes" },
|
|
49
|
+
alias: { y: "yes", h: "help" },
|
|
30
50
|
string: ["template", "name", "dir", "git", "install"],
|
|
31
|
-
boolean: ["yes"],
|
|
51
|
+
boolean: ["yes", "help"],
|
|
32
52
|
});
|
|
33
53
|
|
|
54
|
+
if (args.help) {
|
|
55
|
+
printUsage(packageManager);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
34
59
|
const template = await selectOrClack<string>({
|
|
35
60
|
message: "Pick a framework",
|
|
36
61
|
options: [
|
|
@@ -125,7 +150,7 @@ async function init(argv: string[]): Promise<void> {
|
|
|
125
150
|
await fs.cp(templateDir, dir, {
|
|
126
151
|
recursive: true,
|
|
127
152
|
filter: (src) => {
|
|
128
|
-
let banned = src.includes(".git");
|
|
153
|
+
let banned = src.includes(".git") || src.includes("NEXT_STEPS.txt");
|
|
129
154
|
if (isLocalDev) {
|
|
130
155
|
banned ||= src.includes("node_modules") || src.includes("dist");
|
|
131
156
|
}
|
|
@@ -161,6 +186,11 @@ async function init(argv: string[]): Promise<void> {
|
|
|
161
186
|
JSON.stringify(dstPkg, null, 2),
|
|
162
187
|
);
|
|
163
188
|
|
|
189
|
+
const gitignorePath = join(dir, "gitignore");
|
|
190
|
+
if (existsSync(gitignorePath)) {
|
|
191
|
+
await fs.rename(gitignorePath, join(dir, ".gitignore"));
|
|
192
|
+
}
|
|
193
|
+
|
|
164
194
|
const contributingPath = join(dir, "CONTRIBUTING.md");
|
|
165
195
|
if (existsSync(contributingPath)) {
|
|
166
196
|
tlog.message("Creating symlinks for CONTRIBUTING.md");
|
|
@@ -178,9 +208,15 @@ async function init(argv: string[]): Promise<void> {
|
|
|
178
208
|
await $`cd ${dir} && ${packageManager} install`;
|
|
179
209
|
}
|
|
180
210
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
211
|
+
let successMessage = `All done! Run \`cd ${dir} && ${packageManager} run build\` to build your first Gram Function.`;
|
|
212
|
+
successMessage = await fs
|
|
213
|
+
.readFile(join(templateDir, "NEXT_STEPS.txt"), "utf-8")
|
|
214
|
+
.catch(() => successMessage);
|
|
215
|
+
successMessage = successMessage
|
|
216
|
+
.replaceAll("$PACKAGE_MANAGER", packageManager)
|
|
217
|
+
.replaceAll("$DIR", dir);
|
|
218
|
+
|
|
219
|
+
tlog.success(successMessage);
|
|
184
220
|
}
|
|
185
221
|
|
|
186
222
|
try {
|
|
File without changes
|
|
File without changes
|