@usegraft/cli 0.1.0 → 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 +60 -0
- package/dist/{add-UBAZMSP7.js → add-ASXTMYCX.js} +1 -1
- package/dist/{approvals-Z3EOK5AM.js → approvals-MN3IS3FO.js} +5 -7
- package/dist/{asset-FPEL463J.js → asset-DMNX5JBZ.js} +1 -1
- package/dist/{branch-HRG46YIL.js → branch-IDY42TAV.js} +1 -1
- package/dist/{chunk-BUPFXTUG.js → chunk-2NH6KYTL.js} +16 -5
- package/dist/{chunk-LTFTDG6Z.js → chunk-6Z27SGVO.js} +2 -1
- package/dist/{chunk-KZ3FDWUK.js → chunk-GDTOV3DU.js} +3 -1
- package/dist/{chunk-TUWL7WFD.js → chunk-U25NVB6W.js} +54 -14
- package/dist/{compilations-6P45MPAE.js → compilations-72DJ2VEP.js} +1 -1
- package/dist/{compile-AAUC4G7H.js → compile-TCBGZZAU.js} +2 -2
- package/dist/{content-DY2YI3LT.js → content-VLKNYIHL.js} +1 -1
- package/dist/{db-VGDWG4QA.js → db-WACSH3HN.js} +1 -1
- package/dist/{dev-MX7TQOJ2.js → dev-4YSMWIAS.js} +14 -3
- package/dist/{harden-HQHONZPH.js → harden-QASY2KMI.js} +1 -1
- package/dist/index.js +19 -18
- package/dist/{init-3H2IP5US.js → init-TRPSGUYW.js} +1 -1
- package/dist/{mcp-US3QFLOR.js → mcp-LUJMTAQO.js} +18 -10
- package/dist/{merge-CZUNMMB5.js → merge-XMTFPLHO.js} +3 -2
- package/dist/{migrate-RRW4Z6RB.js → migrate-QB44VL6R.js} +2 -2
- package/dist/{serve-Q63UTTER.js → serve-ZGXLEAEB.js} +4 -2
- package/dist/{studio-TNPOB665.js → studio-HXVSO4WJ.js} +17 -11
- package/package.json +31 -15
package/README.md
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# @usegraft/cli
|
|
2
|
+
|
|
3
|
+
> The `graft` command. Scaffold a project, compile authored content, serve the runtime, split your database credentials.
|
|
4
|
+
|
|
5
|
+
Part of [Graft](https://github.com/AndersonDesign1/graft), a CMS built so an AI agent is the primary operator.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm i -D @usegraft/cli
|
|
11
|
+
# or run it without installing
|
|
12
|
+
npx graft init
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quickstart, with no database
|
|
16
|
+
|
|
17
|
+
A content project needs no services at all. `graft compile` writes the index to a SQLite artifact your app reads embedded.
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npx graft init # scaffolds graft.config.ts, content/, llms.txt
|
|
21
|
+
npx graft compile # → .graft/index.db
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Move to Postgres by setting `DATABASE_URL` and changing one line in `graft.config.ts`:
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
export const index = "postgres";
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Commands
|
|
31
|
+
|
|
32
|
+
| Command | Does |
|
|
33
|
+
| ------------------------------ | ---------------------------------------------------------------------------------------------- |
|
|
34
|
+
| `graft init` | Scaffold a project |
|
|
35
|
+
| `graft compile` | Validate authored MDX and project it into the index |
|
|
36
|
+
| `graft dev` | Recompile on save |
|
|
37
|
+
| `graft serve` | Run the headless runtime: typed functions, MCP over HTTP, `/healthz` |
|
|
38
|
+
| `graft studio` | Open the optional editing UI |
|
|
39
|
+
| `graft mcp` | Serve MCP on stdio, for `.mcp.json` |
|
|
40
|
+
| `graft add <item>` | Copy a registry primitive into your repo, shadcn-style |
|
|
41
|
+
| `graft approve <id>` | Decide a pending approval. Operator credential only |
|
|
42
|
+
| `graft harden <role>` | Grant a Postgres role exactly what a deployment needs, and nothing that can decide an approval |
|
|
43
|
+
| `graft branch` / `graft merge` | Copy-on-write content branches |
|
|
44
|
+
| `graft migrate` | Run content codemods when the schema changes |
|
|
45
|
+
|
|
46
|
+
Run `graft <command> --help` for flags.
|
|
47
|
+
|
|
48
|
+
## Two credentials
|
|
49
|
+
|
|
50
|
+
`graft harden` splits the operator credential from the runtime one. The runtime can serve, project content, and request approvals. It can never decide one, and Postgres enforces that rather than the application.
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
graft harden graft_runtime
|
|
54
|
+
# deploy with the runtime role's URL as DATABASE_URL
|
|
55
|
+
# keep the operator URL for compile, migrate, merge and approve
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
MIT. [Repository](https://github.com/AndersonDesign1/graft) · [Changelog](https://github.com/AndersonDesign1/graft/blob/feat/core/packages/cli/CHANGELOG.md) · [Security policy](https://github.com/AndersonDesign1/graft/blob/feat/core/SECURITY.md)
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
loadProjectEnv,
|
|
4
4
|
requireDatabaseUrl
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-2NH6KYTL.js";
|
|
6
6
|
|
|
7
7
|
// src/commands/approvals.ts
|
|
8
8
|
import { userInfo } from "os";
|
|
@@ -33,12 +33,10 @@ async function decideCommand(options) {
|
|
|
33
33
|
]);
|
|
34
34
|
const handle = createDb(url);
|
|
35
35
|
try {
|
|
36
|
-
const row = await decideApproval(
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
options.decidedBy ?? operatorName()
|
|
41
|
-
);
|
|
36
|
+
const row = await decideApproval(handle.db, options.id, options.decision, {
|
|
37
|
+
kind: "human",
|
|
38
|
+
id: operatorName()
|
|
39
|
+
});
|
|
42
40
|
if (!row) {
|
|
43
41
|
throw new GraftError({
|
|
44
42
|
code: "APPROVAL_INVALID",
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// src/config.ts
|
|
4
4
|
import { existsSync } from "fs";
|
|
5
5
|
import { dirname, join, resolve } from "path";
|
|
6
|
-
import { GraftError } from "@usegraft/contracts";
|
|
6
|
+
import { GraftError, STATIC_INDEX_DEFAULT_PATH } from "@usegraft/contracts";
|
|
7
7
|
import { createJiti } from "jiti";
|
|
8
8
|
var CONFIG_FILENAMES = [
|
|
9
9
|
"graft.config.ts",
|
|
@@ -97,6 +97,7 @@ async function loadConfig(configPath) {
|
|
|
97
97
|
const projectDir = dirname(configPath);
|
|
98
98
|
const index = parseIndexConfig(mod.index, projectDir, configPath);
|
|
99
99
|
assertStaticSupports(index, collections, functions, configPath);
|
|
100
|
+
const mdxTrust = parseMdxTrust(mod.mdxTrust, configPath);
|
|
100
101
|
const contentDirSetting = typeof mod.contentDir === "string" ? mod.contentDir : "content";
|
|
101
102
|
const migrationsDirSetting = typeof mod.migrationsDir === "string" ? mod.migrationsDir : "migrations";
|
|
102
103
|
return {
|
|
@@ -106,9 +107,20 @@ async function loadConfig(configPath) {
|
|
|
106
107
|
migrationsDir: resolve(projectDir, migrationsDirSetting),
|
|
107
108
|
index,
|
|
108
109
|
collections,
|
|
109
|
-
functions
|
|
110
|
+
functions,
|
|
111
|
+
mdxTrust
|
|
110
112
|
};
|
|
111
113
|
}
|
|
114
|
+
function parseMdxTrust(value, configPath) {
|
|
115
|
+
if (value === void 0) return "restricted";
|
|
116
|
+
if (value === "restricted" || value === "full") return value;
|
|
117
|
+
throw new GraftError({
|
|
118
|
+
code: "CONFIG_INVALID",
|
|
119
|
+
message: `${configPath} exports \`mdxTrust\` as ${JSON.stringify(value)}, which is not "restricted" or "full".`,
|
|
120
|
+
fix: 'Export `mdxTrust = "restricted"` (the default: `{\u2026}` expressions and `import` are refused in authored bodies) or `mdxTrust = "full"` (every author has commit access, so code review is the control). Omit the export to keep the default.',
|
|
121
|
+
details: { mdxTrust: value }
|
|
122
|
+
});
|
|
123
|
+
}
|
|
112
124
|
function assertStaticSupports(index, collections, functions, configPath) {
|
|
113
125
|
if (index.driver !== "static") return;
|
|
114
126
|
const dbCollections = Object.values(collections).filter((collection) => collection.authority === "db-authoritative").map((collection) => collection.name);
|
|
@@ -125,18 +137,17 @@ function assertStaticSupports(index, collections, functions, configPath) {
|
|
|
125
137
|
details: { dbCollections, functions: functionNames }
|
|
126
138
|
});
|
|
127
139
|
}
|
|
128
|
-
var STATIC_INDEX_DEFAULT = ".graft/index.db";
|
|
129
140
|
function parseIndexConfig(value, projectDir, configPath) {
|
|
130
141
|
if (value === void 0 || value === "postgres") return { driver: "postgres" };
|
|
131
142
|
if (value === "static") {
|
|
132
|
-
return { driver: "static", path: resolve(projectDir,
|
|
143
|
+
return { driver: "static", path: resolve(projectDir, STATIC_INDEX_DEFAULT_PATH) };
|
|
133
144
|
}
|
|
134
145
|
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
135
146
|
const driver = value.driver;
|
|
136
147
|
const path = value.path;
|
|
137
148
|
if (driver === "postgres") return { driver: "postgres" };
|
|
138
149
|
if (driver === "static" && (path === void 0 || typeof path === "string")) {
|
|
139
|
-
return { driver: "static", path: resolve(projectDir, path ??
|
|
150
|
+
return { driver: "static", path: resolve(projectDir, path ?? STATIC_INDEX_DEFAULT_PATH) };
|
|
140
151
|
}
|
|
141
152
|
}
|
|
142
153
|
throw new GraftError({
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
loadConfig,
|
|
5
5
|
loadProjectEnv,
|
|
6
6
|
requireDatabaseUrl
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-2NH6KYTL.js";
|
|
8
8
|
|
|
9
9
|
// src/commands/migrate.ts
|
|
10
10
|
import { existsSync, readdirSync, statSync } from "fs";
|
|
@@ -99,6 +99,7 @@ Author one as migrations/0001-<name>.ts default-exporting defineContentMigration
|
|
|
99
99
|
db: branch.db,
|
|
100
100
|
contentDir: config.contentDir,
|
|
101
101
|
collections: config.collections,
|
|
102
|
+
mdxTrust: config.mdxTrust,
|
|
102
103
|
branchId: writeBranch,
|
|
103
104
|
gitSha
|
|
104
105
|
});
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
loadConfig,
|
|
8
8
|
loadProjectEnv,
|
|
9
9
|
requireDatabaseUrl
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-2NH6KYTL.js";
|
|
11
11
|
|
|
12
12
|
// src/commands/compile.ts
|
|
13
13
|
import { GraftError } from "@usegraft/contracts";
|
|
@@ -29,6 +29,7 @@ async function compileCommand(options) {
|
|
|
29
29
|
const result = await compileStatic({
|
|
30
30
|
contentDir: config.contentDir,
|
|
31
31
|
collections: config.collections,
|
|
32
|
+
mdxTrust: config.mdxTrust,
|
|
32
33
|
indexPath: config.index.path
|
|
33
34
|
});
|
|
34
35
|
console.log(formatCompileResult(result));
|
|
@@ -52,6 +53,7 @@ async function compileCommand(options) {
|
|
|
52
53
|
db: branch.db,
|
|
53
54
|
contentDir: config.contentDir,
|
|
54
55
|
collections: config.collections,
|
|
56
|
+
mdxTrust: config.mdxTrust,
|
|
55
57
|
branchId: scopeWriteBranch(branch.scope),
|
|
56
58
|
pruneUnknown: options.pruneUnknown
|
|
57
59
|
});
|
|
@@ -4,13 +4,14 @@ import {
|
|
|
4
4
|
loadConfig,
|
|
5
5
|
loadProjectEnv,
|
|
6
6
|
requireDatabaseUrl
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-2NH6KYTL.js";
|
|
8
8
|
|
|
9
9
|
// src/commands/serve.ts
|
|
10
10
|
import { execFileSync } from "child_process";
|
|
11
11
|
import { createServer } from "http";
|
|
12
12
|
import { createActorResolver } from "@usegraft/auth";
|
|
13
13
|
import { GraftError } from "@usegraft/contracts";
|
|
14
|
+
import { setRequestPeer } from "@usegraft/core";
|
|
14
15
|
function createServeRouter(routes) {
|
|
15
16
|
return async (request) => {
|
|
16
17
|
const { pathname } = new URL(request.url);
|
|
@@ -41,9 +42,34 @@ var HOP_BY_HOP = /* @__PURE__ */ new Set([
|
|
|
41
42
|
"upgrade",
|
|
42
43
|
"proxy-connection"
|
|
43
44
|
]);
|
|
44
|
-
function
|
|
45
|
+
function allowedHostsFor(host) {
|
|
46
|
+
if (host === "0.0.0.0" || host === "::" || host === "") return void 0;
|
|
47
|
+
if (host === "127.0.0.1" || host === "localhost" || host === "::1") {
|
|
48
|
+
return ["127.0.0.1", "localhost", "[::1]"];
|
|
49
|
+
}
|
|
50
|
+
return [host];
|
|
51
|
+
}
|
|
52
|
+
function hostname(host) {
|
|
53
|
+
const trimmed = host.trim().toLowerCase();
|
|
54
|
+
if (trimmed.startsWith("[")) return trimmed.slice(0, trimmed.indexOf("]") + 1);
|
|
55
|
+
const colon = trimmed.lastIndexOf(":");
|
|
56
|
+
return colon === -1 ? trimmed : trimmed.slice(0, colon);
|
|
57
|
+
}
|
|
58
|
+
function createNodeListener(handler, options = {}) {
|
|
59
|
+
const allowed = options.allowedHosts?.map(hostname);
|
|
45
60
|
return async (req, res) => {
|
|
46
61
|
try {
|
|
62
|
+
if (allowed && !allowed.includes(hostname(req.headers.host ?? ""))) {
|
|
63
|
+
res.writeHead(400, { "content-type": "application/json" });
|
|
64
|
+
res.end(
|
|
65
|
+
JSON.stringify({
|
|
66
|
+
error: "INPUT_VALIDATION_FAILED",
|
|
67
|
+
message: `This server does not answer to Host "${req.headers.host ?? ""}".`,
|
|
68
|
+
fix: `Reach it at one of: ${allowed.join(", ")}. A mismatched Host is either a misconfigured proxy or a DNS-rebinding attempt.`
|
|
69
|
+
})
|
|
70
|
+
);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
47
73
|
const chunks = [];
|
|
48
74
|
for await (const chunk of req) chunks.push(chunk);
|
|
49
75
|
const body = Buffer.concat(chunks);
|
|
@@ -59,6 +85,8 @@ function createNodeListener(handler) {
|
|
|
59
85
|
headers,
|
|
60
86
|
body: method === "GET" || method === "HEAD" || body.length === 0 ? void 0 : body
|
|
61
87
|
});
|
|
88
|
+
const peer = req.socket.remoteAddress;
|
|
89
|
+
if (peer) setRequestPeer(request, peer);
|
|
62
90
|
const response = await handler(request);
|
|
63
91
|
const outHeaders = {};
|
|
64
92
|
response.headers.forEach((value, key) => {
|
|
@@ -120,7 +148,10 @@ async function startServe(options) {
|
|
|
120
148
|
devTokens: devToken ? { [devToken]: { kind: "agent", id: "graft-serve", scopes } } : void 0
|
|
121
149
|
});
|
|
122
150
|
const approvalPolicy = process.env.GRAFT_APPROVAL_POLICY === "human" ? "human" : "none";
|
|
123
|
-
const
|
|
151
|
+
const host = options.host ?? process.env.HOST ?? "127.0.0.1";
|
|
152
|
+
const loopback = host === "127.0.0.1" || host === "localhost" || host === "::1";
|
|
153
|
+
const anonymousOptIn = process.env.GRAFT_MCP_ALLOW_ANONYMOUS === "1";
|
|
154
|
+
const allowAnonymousMcp = loopback || anonymousOptIn;
|
|
124
155
|
const functions = config.functions ?? {};
|
|
125
156
|
const gitSha = localGitSha(options.cwd);
|
|
126
157
|
const fnHandler = createFunctionsHandler({
|
|
@@ -138,11 +169,12 @@ async function startServe(options) {
|
|
|
138
169
|
contentDir: config.contentDir,
|
|
139
170
|
collections: config.collections,
|
|
140
171
|
functions,
|
|
172
|
+
mdxTrust: config.mdxTrust,
|
|
141
173
|
db: branch.db,
|
|
142
174
|
branchId: writeBranch,
|
|
143
175
|
scope: branch.scope,
|
|
144
176
|
actor: resolveActor,
|
|
145
|
-
|
|
177
|
+
allowAnonymous: allowAnonymousMcp
|
|
146
178
|
});
|
|
147
179
|
const health = async () => {
|
|
148
180
|
try {
|
|
@@ -167,7 +199,6 @@ async function startServe(options) {
|
|
|
167
199
|
{ status: 200, headers: { "content-type": "application/json" } }
|
|
168
200
|
);
|
|
169
201
|
};
|
|
170
|
-
const host = options.host ?? process.env.HOST ?? "127.0.0.1";
|
|
171
202
|
const requestedPort = options.port ?? Number(process.env.PORT ?? 3903);
|
|
172
203
|
if (!Number.isInteger(requestedPort) || requestedPort < 0 || requestedPort > 65535) {
|
|
173
204
|
await branch.close();
|
|
@@ -178,31 +209,39 @@ async function startServe(options) {
|
|
|
178
209
|
fix: "Pass --port <0-65535> (0 picks a free port) or set PORT."
|
|
179
210
|
});
|
|
180
211
|
}
|
|
181
|
-
|
|
182
|
-
|
|
212
|
+
if (!loopback && anonymousOptIn) {
|
|
213
|
+
console.warn(
|
|
214
|
+
"[graft serve] WARNING: GRAFT_MCP_ALLOW_ANONYMOUS=1 while bound beyond loopback \u2014 unauthenticated callers can write content, upload assets and decide approvals. Only do this behind an auth proxy you control."
|
|
215
|
+
);
|
|
216
|
+
} else if (!loopback && issuers.length === 0 && !devToken) {
|
|
183
217
|
console.warn(
|
|
184
|
-
"[graft serve] WARNING: binding beyond loopback with no identity configured \u2014
|
|
218
|
+
"[graft serve] WARNING: binding beyond loopback with no identity configured \u2014 MCP will refuse every caller, because there is nothing to authenticate them against. Set GRAFT_DEV_TOKEN or GRAFT_TRUSTED_ISSUERS."
|
|
185
219
|
);
|
|
186
220
|
}
|
|
187
221
|
let studioHandler;
|
|
188
222
|
if (studioMod) {
|
|
189
|
-
const
|
|
223
|
+
const authenticate = !loopback && (devToken || issuers.length > 0) ? async (request) => {
|
|
190
224
|
const actor = await resolveActor(request);
|
|
191
|
-
|
|
192
|
-
|
|
225
|
+
if (actor.kind === "anonymous" || !actor.id) return null;
|
|
226
|
+
return { kind: actor.kind, id: actor.id, scopes: actor.scopes ?? [] };
|
|
227
|
+
} : !loopback ? () => null : void 0;
|
|
193
228
|
studioHandler = studioMod.createStudioHandler({
|
|
194
229
|
db: branch.db,
|
|
195
230
|
collections: config.collections,
|
|
196
231
|
contentDir: config.contentDir,
|
|
232
|
+
mdxTrust: config.mdxTrust,
|
|
197
233
|
defaultBranch: writeBranch,
|
|
198
|
-
|
|
234
|
+
// Only reached on a loopback mount, where there is no caller identity to
|
|
235
|
+
// attribute to. Off loopback the authenticated principal is used instead.
|
|
236
|
+
decider: { kind: "agent", id: "studio-serve" },
|
|
199
237
|
uiBasePath: "/studio",
|
|
200
|
-
|
|
238
|
+
authenticate
|
|
201
239
|
});
|
|
202
240
|
}
|
|
203
241
|
const server = createServer(
|
|
204
242
|
createNodeListener(
|
|
205
|
-
createServeRouter({ fn: fnHandler, mcp: mcpHandler, health, studio: studioHandler })
|
|
243
|
+
createServeRouter({ fn: fnHandler, mcp: mcpHandler, health, studio: studioHandler }),
|
|
244
|
+
{ allowedHosts: allowedHostsFor(host) }
|
|
206
245
|
)
|
|
207
246
|
);
|
|
208
247
|
await new Promise((resolve, reject) => {
|
|
@@ -250,6 +289,7 @@ async function serveCommand(options) {
|
|
|
250
289
|
|
|
251
290
|
export {
|
|
252
291
|
createServeRouter,
|
|
292
|
+
allowedHostsFor,
|
|
253
293
|
createNodeListener,
|
|
254
294
|
startServe,
|
|
255
295
|
serveCommand
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
import {
|
|
3
3
|
assertNoStaticBranch,
|
|
4
4
|
compileCommand
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-GDTOV3DU.js";
|
|
6
6
|
import "./chunk-GPA66AP5.js";
|
|
7
|
-
import "./chunk-
|
|
7
|
+
import "./chunk-2NH6KYTL.js";
|
|
8
8
|
export {
|
|
9
9
|
assertNoStaticBranch,
|
|
10
10
|
compileCommand
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
assertNoStaticBranch
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-GDTOV3DU.js";
|
|
5
5
|
import {
|
|
6
6
|
formatCompileResult,
|
|
7
7
|
printGraftError
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
loadConfig,
|
|
13
13
|
loadProjectEnv,
|
|
14
14
|
requireDatabaseUrl
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-2NH6KYTL.js";
|
|
16
16
|
|
|
17
17
|
// src/commands/dev.ts
|
|
18
18
|
import { existsSync, watch } from "fs";
|
|
@@ -42,6 +42,7 @@ async function devCommand(options) {
|
|
|
42
42
|
const branch = control !== void 0 && url !== void 0 ? await resolveBranchHandle(control.db, options.branchId ?? "main", { databaseUrl: url }) : void 0;
|
|
43
43
|
const writeBranch = branch !== void 0 ? scopeWriteBranch(branch.scope) : "main";
|
|
44
44
|
let timer;
|
|
45
|
+
let rewatchContent;
|
|
45
46
|
let compiling = false;
|
|
46
47
|
let dirty = false;
|
|
47
48
|
let configDirty = false;
|
|
@@ -54,17 +55,21 @@ async function devCommand(options) {
|
|
|
54
55
|
try {
|
|
55
56
|
if (configDirty) {
|
|
56
57
|
configDirty = false;
|
|
58
|
+
const previousContentDir = config.contentDir;
|
|
57
59
|
config = await loadConfig(configPath);
|
|
58
60
|
console.log(`reloaded ${basename(configPath)}`);
|
|
61
|
+
if (config.contentDir !== previousContentDir) rewatchContent?.(config.contentDir);
|
|
59
62
|
}
|
|
60
63
|
const result = branch !== void 0 ? await compile({
|
|
61
64
|
db: branch.db,
|
|
62
65
|
contentDir: config.contentDir,
|
|
63
66
|
collections: config.collections,
|
|
67
|
+
mdxTrust: config.mdxTrust,
|
|
64
68
|
branchId: writeBranch
|
|
65
69
|
}) : await compileStatic({
|
|
66
70
|
contentDir: config.contentDir,
|
|
67
71
|
collections: config.collections,
|
|
72
|
+
mdxTrust: config.mdxTrust,
|
|
68
73
|
indexPath: config.index.path
|
|
69
74
|
});
|
|
70
75
|
console.log(formatCompileResult(result));
|
|
@@ -85,12 +90,17 @@ async function devCommand(options) {
|
|
|
85
90
|
timer = setTimeout(() => void runCompile(), DEBOUNCE_MS);
|
|
86
91
|
};
|
|
87
92
|
await runCompile();
|
|
93
|
+
let contentWatcher = watch(config.contentDir, { recursive: true }, () => schedule());
|
|
88
94
|
const watchers = [
|
|
89
|
-
watch(config.contentDir, { recursive: true }, () => schedule()),
|
|
90
95
|
watch(config.projectDir, (_event, filename) => {
|
|
91
96
|
if (filename && CONFIG_FILENAMES.includes(filename)) schedule(true);
|
|
92
97
|
})
|
|
93
98
|
];
|
|
99
|
+
rewatchContent = (dir) => {
|
|
100
|
+
contentWatcher.close();
|
|
101
|
+
contentWatcher = watch(dir, { recursive: true }, () => schedule());
|
|
102
|
+
console.log(`now watching ${relative(options.cwd, dir) || "."}`);
|
|
103
|
+
};
|
|
94
104
|
const watchedContent = relative(options.cwd, config.contentDir) || ".";
|
|
95
105
|
const branchLabel = branch === void 0 ? "static index" : branch.scope.kind === "physical" ? `${branch.name} (neon)` : options.branchId ?? "main";
|
|
96
106
|
console.log(
|
|
@@ -99,6 +109,7 @@ async function devCommand(options) {
|
|
|
99
109
|
await new Promise((resolveStopped) => {
|
|
100
110
|
const stop = () => {
|
|
101
111
|
clearTimeout(timer);
|
|
112
|
+
contentWatcher.close();
|
|
102
113
|
for (const watcher of watchers) watcher.close();
|
|
103
114
|
resolveStopped();
|
|
104
115
|
};
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,8 @@ import {
|
|
|
4
4
|
} from "./chunk-GPA66AP5.js";
|
|
5
5
|
|
|
6
6
|
// src/cli.ts
|
|
7
|
-
|
|
7
|
+
import { createRequire } from "module";
|
|
8
|
+
var VERSION = createRequire(import.meta.url)("../package.json").version;
|
|
8
9
|
var PLANNED = [];
|
|
9
10
|
function printHelp() {
|
|
10
11
|
const lines = [
|
|
@@ -155,7 +156,7 @@ async function run(argv, options = {}) {
|
|
|
155
156
|
const args = parseArgs(rest);
|
|
156
157
|
switch (command) {
|
|
157
158
|
case "init": {
|
|
158
|
-
const { initCommand } = await import("./init-
|
|
159
|
+
const { initCommand } = await import("./init-TRPSGUYW.js");
|
|
159
160
|
const result = initCommand({
|
|
160
161
|
targetDir: args.positionals[0] ?? cwd,
|
|
161
162
|
driver: args.initDriver
|
|
@@ -186,12 +187,12 @@ async function run(argv, options = {}) {
|
|
|
186
187
|
return 0;
|
|
187
188
|
}
|
|
188
189
|
case "compile": {
|
|
189
|
-
const { compileCommand } = await import("./compile-
|
|
190
|
+
const { compileCommand } = await import("./compile-TCBGZZAU.js");
|
|
190
191
|
await compileCommand({ cwd, branchId: args.branchId, pruneUnknown: args.pruneUnknown });
|
|
191
192
|
return 0;
|
|
192
193
|
}
|
|
193
194
|
case "dev": {
|
|
194
|
-
const { devCommand } = await import("./dev-
|
|
195
|
+
const { devCommand } = await import("./dev-4YSMWIAS.js");
|
|
195
196
|
await devCommand({ cwd, branchId: args.branchId });
|
|
196
197
|
return 0;
|
|
197
198
|
}
|
|
@@ -202,7 +203,7 @@ async function run(argv, options = {}) {
|
|
|
202
203
|
subcommand ? `unknown db subcommand "${subcommand}" \u2014 the only one is \`graft db migrate\`` : "usage: graft db migrate [--dry-run]"
|
|
203
204
|
);
|
|
204
205
|
}
|
|
205
|
-
const { dbMigrateCommand, formatMigrateResult } = await import("./db-
|
|
206
|
+
const { dbMigrateCommand, formatMigrateResult } = await import("./db-WACSH3HN.js");
|
|
206
207
|
const result = await dbMigrateCommand({ cwd, dryRun: args.dryRun });
|
|
207
208
|
console.log(formatMigrateResult(result));
|
|
208
209
|
return 0;
|
|
@@ -212,7 +213,7 @@ async function run(argv, options = {}) {
|
|
|
212
213
|
if (subcommand !== "put" || !file) {
|
|
213
214
|
throw new UsageError("usage: graft asset put <file> [key]");
|
|
214
215
|
}
|
|
215
|
-
const { assetPutCommand } = await import("./asset-
|
|
216
|
+
const { assetPutCommand } = await import("./asset-DMNX5JBZ.js");
|
|
216
217
|
const result = await assetPutCommand({ cwd, file, key });
|
|
217
218
|
console.log(`Uploaded ${result.key} (${result.contentType}, ${result.bytes} bytes)`);
|
|
218
219
|
console.log(
|
|
@@ -227,7 +228,7 @@ async function run(argv, options = {}) {
|
|
|
227
228
|
return 0;
|
|
228
229
|
}
|
|
229
230
|
case "approvals": {
|
|
230
|
-
const { approvalsListCommand, formatApproval } = await import("./approvals-
|
|
231
|
+
const { approvalsListCommand, formatApproval } = await import("./approvals-MN3IS3FO.js");
|
|
231
232
|
const pending = await approvalsListCommand({ cwd });
|
|
232
233
|
if (pending.length === 0) {
|
|
233
234
|
console.log("No pending approvals.");
|
|
@@ -244,7 +245,7 @@ async function run(argv, options = {}) {
|
|
|
244
245
|
case "deny": {
|
|
245
246
|
const id = args.positionals[0];
|
|
246
247
|
if (!id) throw new UsageError(`usage: graft ${command} <approval-id>`);
|
|
247
|
-
const { decideCommand } = await import("./approvals-
|
|
248
|
+
const { decideCommand } = await import("./approvals-MN3IS3FO.js");
|
|
248
249
|
const decision = command === "approve" ? "approved" : "denied";
|
|
249
250
|
const row = await decideCommand({ cwd, id, decision });
|
|
250
251
|
console.log(
|
|
@@ -258,7 +259,7 @@ async function run(argv, options = {}) {
|
|
|
258
259
|
return 0;
|
|
259
260
|
}
|
|
260
261
|
case "migrate": {
|
|
261
|
-
const { migrateCommand } = await import("./migrate-
|
|
262
|
+
const { migrateCommand } = await import("./migrate-QB44VL6R.js");
|
|
262
263
|
await migrateCommand({ cwd, branchId: args.branchId, apply: args.apply });
|
|
263
264
|
return 0;
|
|
264
265
|
}
|
|
@@ -272,7 +273,7 @@ async function run(argv, options = {}) {
|
|
|
272
273
|
if (subcommand && !name) {
|
|
273
274
|
throw new UsageError(`usage: graft branch ${subcommand} <name>`);
|
|
274
275
|
}
|
|
275
|
-
const mod = await import("./branch-
|
|
276
|
+
const mod = await import("./branch-IDY42TAV.js");
|
|
276
277
|
if (!subcommand) {
|
|
277
278
|
const rows = await mod.branchListCommand({ cwd });
|
|
278
279
|
if (rows.length === 0) {
|
|
@@ -315,12 +316,12 @@ async function run(argv, options = {}) {
|
|
|
315
316
|
const branch = args.positionals[0];
|
|
316
317
|
if (!branch)
|
|
317
318
|
throw new UsageError("usage: graft merge <branch> [--into <target>] [--apply]");
|
|
318
|
-
const { mergeCommand } = await import("./merge-
|
|
319
|
+
const { mergeCommand } = await import("./merge-XMTFPLHO.js");
|
|
319
320
|
await mergeCommand({ cwd, branch, into: args.into, apply: args.apply });
|
|
320
321
|
return 0;
|
|
321
322
|
}
|
|
322
323
|
case "add": {
|
|
323
|
-
const { addCommand } = await import("./add-
|
|
324
|
+
const { addCommand } = await import("./add-ASXTMYCX.js");
|
|
324
325
|
await addCommand({
|
|
325
326
|
cwd,
|
|
326
327
|
names: args.positionals,
|
|
@@ -330,12 +331,12 @@ async function run(argv, options = {}) {
|
|
|
330
331
|
return 0;
|
|
331
332
|
}
|
|
332
333
|
case "mcp": {
|
|
333
|
-
const { mcpCommand } = await import("./mcp-
|
|
334
|
+
const { mcpCommand } = await import("./mcp-LUJMTAQO.js");
|
|
334
335
|
await mcpCommand({ cwd, branchId: args.branchId });
|
|
335
336
|
return 0;
|
|
336
337
|
}
|
|
337
338
|
case "serve": {
|
|
338
|
-
const { serveCommand } = await import("./serve-
|
|
339
|
+
const { serveCommand } = await import("./serve-ZGXLEAEB.js");
|
|
339
340
|
await serveCommand({
|
|
340
341
|
cwd,
|
|
341
342
|
branchId: args.branchId,
|
|
@@ -346,7 +347,7 @@ async function run(argv, options = {}) {
|
|
|
346
347
|
return 0;
|
|
347
348
|
}
|
|
348
349
|
case "studio": {
|
|
349
|
-
const { studioCommand } = await import("./studio-
|
|
350
|
+
const { studioCommand } = await import("./studio-HXVSO4WJ.js");
|
|
350
351
|
await studioCommand({
|
|
351
352
|
cwd,
|
|
352
353
|
branchId: args.branchId,
|
|
@@ -356,7 +357,7 @@ async function run(argv, options = {}) {
|
|
|
356
357
|
return 0;
|
|
357
358
|
}
|
|
358
359
|
case "content": {
|
|
359
|
-
const { contentListCommand, formatContentLine } = await import("./content-
|
|
360
|
+
const { contentListCommand, formatContentLine } = await import("./content-VLKNYIHL.js");
|
|
360
361
|
const { branch, lines } = await contentListCommand({ cwd, branchId: args.branchId });
|
|
361
362
|
if (lines.length === 0) {
|
|
362
363
|
console.log(`No content on branch "${branch}" (run graft compile).`);
|
|
@@ -368,7 +369,7 @@ async function run(argv, options = {}) {
|
|
|
368
369
|
return 0;
|
|
369
370
|
}
|
|
370
371
|
case "compilations": {
|
|
371
|
-
const { compilationsListCommand, formatCompilation } = await import("./compilations-
|
|
372
|
+
const { compilationsListCommand, formatCompilation } = await import("./compilations-72DJ2VEP.js");
|
|
372
373
|
const rows = await compilationsListCommand({ cwd, branchId: args.branchId });
|
|
373
374
|
if (rows.length === 0) {
|
|
374
375
|
console.log("No compilations recorded yet (run graft compile).");
|
|
@@ -380,7 +381,7 @@ async function run(argv, options = {}) {
|
|
|
380
381
|
case "harden": {
|
|
381
382
|
const role = args.positionals[0];
|
|
382
383
|
if (!role) throw new UsageError("usage: graft harden <role>");
|
|
383
|
-
const { hardenCommand } = await import("./harden-
|
|
384
|
+
const { hardenCommand } = await import("./harden-QASY2KMI.js");
|
|
384
385
|
const result = await hardenCommand({ cwd, role });
|
|
385
386
|
console.log(`Hardened runtime role "${result.role}" (${result.statements.length} grants):`);
|
|
386
387
|
for (const statement of result.statements) console.log(` ${statement}`);
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
assertNoStaticBranch
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-GDTOV3DU.js";
|
|
5
5
|
import "./chunk-GPA66AP5.js";
|
|
6
6
|
import {
|
|
7
7
|
findConfig,
|
|
8
8
|
loadConfig,
|
|
9
9
|
loadProjectEnv,
|
|
10
10
|
requireDatabaseUrl
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-2NH6KYTL.js";
|
|
12
12
|
|
|
13
13
|
// src/commands/mcp.ts
|
|
14
14
|
import { createActorResolver } from "@usegraft/auth";
|
|
@@ -25,21 +25,25 @@ async function mcpCommand(options) {
|
|
|
25
25
|
try {
|
|
26
26
|
const devToken = process.env.GRAFT_DEV_TOKEN;
|
|
27
27
|
const scopes = (process.env.GRAFT_DEV_SCOPES ?? "").split(/[,\s]+/).map((s) => s.trim()).filter(Boolean);
|
|
28
|
+
const cliActor = {
|
|
29
|
+
kind: "agent",
|
|
30
|
+
id: "graft-cli",
|
|
31
|
+
scopes: [.../* @__PURE__ */ new Set(["content:write", ...scopes])]
|
|
32
|
+
};
|
|
28
33
|
const resolveActor = createActorResolver({
|
|
29
34
|
issuers: [],
|
|
30
|
-
devTokens: devToken ? {
|
|
31
|
-
[devToken]: {
|
|
32
|
-
kind: "agent",
|
|
33
|
-
id: "graft-cli",
|
|
34
|
-
scopes
|
|
35
|
-
}
|
|
36
|
-
} : void 0
|
|
35
|
+
devTokens: devToken ? { [devToken]: cliActor } : void 0
|
|
37
36
|
});
|
|
37
|
+
const resolveStdioActor = async (request) => {
|
|
38
|
+
const resolved = await resolveActor(request);
|
|
39
|
+
return resolved.kind === "anonymous" ? cliActor : resolved;
|
|
40
|
+
};
|
|
38
41
|
const server = createGraftMcp({
|
|
39
42
|
name: "graft",
|
|
40
43
|
contentDir: config.contentDir,
|
|
41
44
|
collections: config.collections,
|
|
42
45
|
functions: config.functions,
|
|
46
|
+
mdxTrust: config.mdxTrust,
|
|
43
47
|
...branch !== void 0 ? {
|
|
44
48
|
db: branch.db,
|
|
45
49
|
branchId: scopeWriteBranch(branch.scope),
|
|
@@ -47,7 +51,11 @@ async function mcpCommand(options) {
|
|
|
47
51
|
// overlay branch searches its full parent chain, not just its own rows.
|
|
48
52
|
scope: branch.scope
|
|
49
53
|
} : { staticIndexPath: config.index.path },
|
|
50
|
-
actor:
|
|
54
|
+
actor: resolveStdioActor,
|
|
55
|
+
connectionActor: cliActor,
|
|
56
|
+
// Local agents may upload a file from the project; remote mounts get no
|
|
57
|
+
// `path` argument at all.
|
|
58
|
+
localUploadRoot: config.projectDir,
|
|
51
59
|
defaultAuthorization: devToken
|
|
52
60
|
});
|
|
53
61
|
await serveStdio(server);
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
discoverMigrations
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-6Z27SGVO.js";
|
|
5
5
|
import {
|
|
6
6
|
findConfig,
|
|
7
7
|
loadConfig,
|
|
8
8
|
loadProjectEnv,
|
|
9
9
|
requireDatabaseUrl
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-2NH6KYTL.js";
|
|
11
11
|
|
|
12
12
|
// src/commands/merge.ts
|
|
13
13
|
import { basename } from "path";
|
|
@@ -144,6 +144,7 @@ async function mergeCommand(options) {
|
|
|
144
144
|
db: target.db,
|
|
145
145
|
contentDir: config.contentDir,
|
|
146
146
|
collections: config.collections,
|
|
147
|
+
mdxTrust: config.mdxTrust,
|
|
147
148
|
branchId: targetWrite,
|
|
148
149
|
gitSha
|
|
149
150
|
});
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
allowedHostsFor,
|
|
3
4
|
createNodeListener,
|
|
4
5
|
createServeRouter,
|
|
5
6
|
serveCommand,
|
|
6
7
|
startServe
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-
|
|
8
|
+
} from "./chunk-U25NVB6W.js";
|
|
9
|
+
import "./chunk-2NH6KYTL.js";
|
|
9
10
|
export {
|
|
11
|
+
allowedHostsFor,
|
|
10
12
|
createNodeListener,
|
|
11
13
|
createServeRouter,
|
|
12
14
|
serveCommand,
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
allowedHostsFor,
|
|
3
4
|
createNodeListener
|
|
4
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-U25NVB6W.js";
|
|
5
6
|
import {
|
|
6
7
|
findConfig,
|
|
7
8
|
loadConfig,
|
|
8
9
|
loadProjectEnv,
|
|
9
10
|
requireDatabaseUrl
|
|
10
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-2NH6KYTL.js";
|
|
11
12
|
|
|
12
13
|
// src/commands/studio.ts
|
|
13
14
|
import { execFile } from "child_process";
|
|
@@ -17,11 +18,11 @@ import { GraftError } from "@usegraft/contracts";
|
|
|
17
18
|
function isLoopback(host) {
|
|
18
19
|
return host === "127.0.0.1" || host === "localhost" || host === "::1";
|
|
19
20
|
}
|
|
20
|
-
function
|
|
21
|
+
function operatorIdentity() {
|
|
21
22
|
try {
|
|
22
|
-
return userInfo().username;
|
|
23
|
+
return { kind: "human", id: userInfo().username };
|
|
23
24
|
} catch {
|
|
24
|
-
return process.env.USERNAME ?? process.env.USER ?? "operator";
|
|
25
|
+
return { kind: "human", id: process.env.USERNAME ?? process.env.USER ?? "operator" };
|
|
25
26
|
}
|
|
26
27
|
}
|
|
27
28
|
function openBrowser(url) {
|
|
@@ -58,19 +59,24 @@ async function studioCommand(options) {
|
|
|
58
59
|
"[graft studio] WARNING: binding beyond loopback with no GRAFT_DEV_TOKEN \u2014 set a bearer token before exposing Studio to a network."
|
|
59
60
|
);
|
|
60
61
|
}
|
|
61
|
-
const
|
|
62
|
+
const authenticate = !loopback && devToken ? (request) => {
|
|
62
63
|
const header = request.headers.get("authorization") ?? "";
|
|
63
|
-
|
|
64
|
-
|
|
64
|
+
if (header !== `Bearer ${devToken}`) return null;
|
|
65
|
+
return {
|
|
66
|
+
...operatorIdentity(),
|
|
67
|
+
scopes: ["studio:read", "studio:write", "approvals:decide"]
|
|
68
|
+
};
|
|
69
|
+
} : !loopback ? () => null : void 0;
|
|
65
70
|
const handler = createStudioHandler({
|
|
66
71
|
db: branch.db,
|
|
67
72
|
collections: config.collections,
|
|
68
73
|
contentDir: config.contentDir,
|
|
74
|
+
mdxTrust: config.mdxTrust,
|
|
69
75
|
defaultBranch: writeBranch,
|
|
70
|
-
|
|
71
|
-
|
|
76
|
+
decider: operatorIdentity,
|
|
77
|
+
authenticate
|
|
72
78
|
});
|
|
73
|
-
const server = createServer(createNodeListener(handler));
|
|
79
|
+
const server = createServer(createNodeListener(handler, { allowedHosts: allowedHostsFor(host) }));
|
|
74
80
|
await new Promise((resolve, reject) => {
|
|
75
81
|
server.once("error", reject);
|
|
76
82
|
server.listen(requestedPort, host, () => resolve());
|
package/package.json
CHANGED
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@usegraft/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "The graft CLI: scaffold, compile authored content, serve the runtime, and split your database credentials.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"agent",
|
|
7
|
+
"ai",
|
|
8
|
+
"cli",
|
|
9
|
+
"cms",
|
|
10
|
+
"content",
|
|
11
|
+
"graft",
|
|
12
|
+
"headless-cms",
|
|
13
|
+
"mcp",
|
|
14
|
+
"postgres",
|
|
15
|
+
"scaffolding",
|
|
16
|
+
"static-site",
|
|
17
|
+
"typescript"
|
|
18
|
+
],
|
|
19
|
+
"homepage": "https://github.com/AndersonDesign1/graft#readme",
|
|
4
20
|
"license": "MIT",
|
|
5
21
|
"repository": {
|
|
6
22
|
"type": "git",
|
|
@@ -18,20 +34,21 @@
|
|
|
18
34
|
"access": "public"
|
|
19
35
|
},
|
|
20
36
|
"dependencies": {
|
|
21
|
-
"
|
|
22
|
-
"@usegraft/
|
|
23
|
-
"@usegraft/compiler": "0.
|
|
24
|
-
"@usegraft/
|
|
25
|
-
"@usegraft/
|
|
26
|
-
"@usegraft/core": "0.
|
|
27
|
-
"@usegraft/
|
|
28
|
-
"@usegraft/
|
|
29
|
-
"@usegraft/
|
|
30
|
-
"@usegraft/registry": "0.
|
|
31
|
-
"@usegraft/studio": "0.
|
|
37
|
+
"@usegraft/assets": "0.2.0",
|
|
38
|
+
"@usegraft/auth": "0.2.0",
|
|
39
|
+
"@usegraft/compiler": "0.2.0",
|
|
40
|
+
"@usegraft/content-migrations": "0.2.0",
|
|
41
|
+
"@usegraft/contracts": "0.2.0",
|
|
42
|
+
"@usegraft/core": "0.2.0",
|
|
43
|
+
"@usegraft/db": "0.2.0",
|
|
44
|
+
"@usegraft/mcp": "0.2.0",
|
|
45
|
+
"@usegraft/mdx-safety": "0.2.0",
|
|
46
|
+
"@usegraft/registry": "0.2.0",
|
|
47
|
+
"@usegraft/studio": "0.2.0",
|
|
48
|
+
"jiti": "^2.4.0"
|
|
32
49
|
},
|
|
33
50
|
"devDependencies": {
|
|
34
|
-
"@usegraft/sdk-core": "0.
|
|
51
|
+
"@usegraft/sdk-core": "0.2.0"
|
|
35
52
|
},
|
|
36
53
|
"engines": {
|
|
37
54
|
"node": ">=22.16"
|
|
@@ -40,7 +57,6 @@
|
|
|
40
57
|
"build": "tsup",
|
|
41
58
|
"dev": "tsup --watch",
|
|
42
59
|
"typecheck": "tsc --noEmit",
|
|
43
|
-
"test": "vitest run --passWithNoTests"
|
|
44
|
-
"lint": "oxlint ."
|
|
60
|
+
"test": "vitest run --passWithNoTests"
|
|
45
61
|
}
|
|
46
62
|
}
|