@usegraft/cli 0.2.0 → 1.0.0-beta.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 +9 -5
- package/dist/{add-ASXTMYCX.js → add-TCQY3YAN.js} +1 -1
- package/dist/approvals-4PAANLA4.js +14 -0
- package/dist/{asset-DMNX5JBZ.js → asset-JWER6AOG.js} +1 -1
- package/dist/{branch-IDY42TAV.js → branch-U7FFDTFV.js} +1 -1
- package/dist/{chunk-2NH6KYTL.js → chunk-2LG6TWYY.js} +13 -1
- package/dist/{chunk-GDTOV3DU.js → chunk-2N3HXYNN.js} +1 -1
- package/dist/{chunk-U25NVB6W.js → chunk-CONTLKSZ.js} +48 -6
- package/dist/{chunk-6Z27SGVO.js → chunk-DW6WTDRX.js} +1 -1
- package/dist/{approvals-MN3IS3FO.js → chunk-NBJ4N4O6.js} +3 -1
- package/dist/{compilations-72DJ2VEP.js → compilations-CH6AIOFG.js} +1 -1
- package/dist/{compile-TCBGZZAU.js → compile-AWPSEA7U.js} +2 -2
- package/dist/{content-VLKNYIHL.js → content-ZULMTJMD.js} +1 -1
- package/dist/{db-WACSH3HN.js → db-5YMFKHGO.js} +1 -1
- package/dist/{dev-4YSMWIAS.js → dev-WHTIRWMR.js} +2 -2
- package/dist/{harden-QASY2KMI.js → harden-QONL2MAO.js} +1 -1
- package/dist/index.js +27 -18
- package/dist/{init-TRPSGUYW.js → init-FV7Q6VXM.js} +1 -1
- package/dist/{mcp-LUJMTAQO.js → mcp-77QFFJXK.js} +8 -3
- package/dist/{merge-XMTFPLHO.js → merge-ZWYZJVFE.js} +2 -2
- package/dist/{migrate-QB44VL6R.js → migrate-6ZYG2H5C.js} +2 -2
- package/dist/{serve-ZGXLEAEB.js → serve-5ADUQG66.js} +2 -2
- package/dist/{studio-HXVSO4WJ.js → studio-7VAYFEWS.js} +2 -2
- package/package.json +14 -13
package/README.md
CHANGED
|
@@ -9,16 +9,20 @@ Part of [Graft](https://github.com/AndersonDesign1/graft), a CMS built so an AI
|
|
|
9
9
|
```bash
|
|
10
10
|
npm i -D @usegraft/cli
|
|
11
11
|
# or run it without installing
|
|
12
|
-
npx
|
|
12
|
+
npx @usegraft/cli init
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
+
Once installed, the command is `graft`. Run it without installing under the
|
|
16
|
+
full package name: the bare name `graft` on npm belongs to an unrelated
|
|
17
|
+
package, so `npx graft` fetches the wrong thing.
|
|
18
|
+
|
|
15
19
|
## Quickstart, with no database
|
|
16
20
|
|
|
17
21
|
A content project needs no services at all. `graft compile` writes the index to a SQLite artifact your app reads embedded.
|
|
18
22
|
|
|
19
23
|
```bash
|
|
20
|
-
npx
|
|
21
|
-
npx
|
|
24
|
+
npx @usegraft/cli init # scaffolds graft.config.ts, content/, llms.txt
|
|
25
|
+
npx @usegraft/cli compile # → .graft/index.db
|
|
22
26
|
```
|
|
23
27
|
|
|
24
28
|
Move to Postgres by setting `DATABASE_URL` and changing one line in `graft.config.ts`:
|
|
@@ -34,7 +38,7 @@ export const index = "postgres";
|
|
|
34
38
|
| `graft init` | Scaffold a project |
|
|
35
39
|
| `graft compile` | Validate authored MDX and project it into the index |
|
|
36
40
|
| `graft dev` | Recompile on save |
|
|
37
|
-
| `graft serve` | Run the headless runtime: typed functions, MCP
|
|
41
|
+
| `graft serve` | Run the headless runtime: typed functions, MCP, authored-content reads, `/healthz` |
|
|
38
42
|
| `graft studio` | Open the optional editing UI |
|
|
39
43
|
| `graft mcp` | Serve MCP on stdio, for `.mcp.json` |
|
|
40
44
|
| `graft add <item>` | Copy a registry primitive into your repo, shadcn-style |
|
|
@@ -57,4 +61,4 @@ graft harden graft_runtime
|
|
|
57
61
|
|
|
58
62
|
---
|
|
59
63
|
|
|
60
|
-
MIT. [Repository](https://github.com/AndersonDesign1/graft) · [Changelog](https://github.com/AndersonDesign1/graft/blob/
|
|
64
|
+
MIT. [Repository](https://github.com/AndersonDesign1/graft) · [Changelog](https://github.com/AndersonDesign1/graft/blob/main/packages/cli/CHANGELOG.md) · [Security policy](https://github.com/AndersonDesign1/graft/blob/main/SECURITY.md)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
approvalsListCommand,
|
|
4
|
+
decideCommand,
|
|
5
|
+
formatApproval,
|
|
6
|
+
operatorName
|
|
7
|
+
} from "./chunk-NBJ4N4O6.js";
|
|
8
|
+
import "./chunk-2LG6TWYY.js";
|
|
9
|
+
export {
|
|
10
|
+
approvalsListCommand,
|
|
11
|
+
decideCommand,
|
|
12
|
+
formatApproval,
|
|
13
|
+
operatorName
|
|
14
|
+
};
|
|
@@ -98,6 +98,7 @@ async function loadConfig(configPath) {
|
|
|
98
98
|
const index = parseIndexConfig(mod.index, projectDir, configPath);
|
|
99
99
|
assertStaticSupports(index, collections, functions, configPath);
|
|
100
100
|
const mdxTrust = parseMdxTrust(mod.mdxTrust, configPath);
|
|
101
|
+
const approvalPolicy = parseApprovalPolicy(mod.approvalPolicy, configPath);
|
|
101
102
|
const contentDirSetting = typeof mod.contentDir === "string" ? mod.contentDir : "content";
|
|
102
103
|
const migrationsDirSetting = typeof mod.migrationsDir === "string" ? mod.migrationsDir : "migrations";
|
|
103
104
|
return {
|
|
@@ -108,7 +109,8 @@ async function loadConfig(configPath) {
|
|
|
108
109
|
index,
|
|
109
110
|
collections,
|
|
110
111
|
functions,
|
|
111
|
-
mdxTrust
|
|
112
|
+
mdxTrust,
|
|
113
|
+
approvalPolicy
|
|
112
114
|
};
|
|
113
115
|
}
|
|
114
116
|
function parseMdxTrust(value, configPath) {
|
|
@@ -121,6 +123,16 @@ function parseMdxTrust(value, configPath) {
|
|
|
121
123
|
details: { mdxTrust: value }
|
|
122
124
|
});
|
|
123
125
|
}
|
|
126
|
+
function parseApprovalPolicy(value, configPath) {
|
|
127
|
+
if (value === void 0) return "none";
|
|
128
|
+
if (value === "none" || value === "human" || value === "unattended") return value;
|
|
129
|
+
throw new GraftError({
|
|
130
|
+
code: "CONFIG_INVALID",
|
|
131
|
+
message: `${configPath} exports \`approvalPolicy\` as ${JSON.stringify(value)}, which is not "none", "human" or "unattended".`,
|
|
132
|
+
fix: 'Export `approvalPolicy = "none"` (the default: only `destructive` functions are gated), `"human"` (every mutation is gated), or `"unattended"` (nothing is gated, for a caller with no human behind it). Omit the export to keep the default.',
|
|
133
|
+
details: { approvalPolicy: value }
|
|
134
|
+
});
|
|
135
|
+
}
|
|
124
136
|
function assertStaticSupports(index, collections, functions, configPath) {
|
|
125
137
|
if (index.driver !== "static") return;
|
|
126
138
|
const dbCollections = Object.values(collections).filter((collection) => collection.authority === "db-authoritative").map((collection) => collection.name);
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
loadConfig,
|
|
5
5
|
loadProjectEnv,
|
|
6
6
|
requireDatabaseUrl
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-2LG6TWYY.js";
|
|
8
8
|
|
|
9
9
|
// src/commands/serve.ts
|
|
10
10
|
import { execFileSync } from "child_process";
|
|
@@ -18,6 +18,9 @@ function createServeRouter(routes) {
|
|
|
18
18
|
if (pathname === "/healthz") return routes.health(request);
|
|
19
19
|
if (pathname === "/api/mcp") return routes.mcp(request);
|
|
20
20
|
if (pathname === "/api/fn" || pathname.startsWith("/api/fn/")) return routes.fn(request);
|
|
21
|
+
if (pathname === "/api/content/v1" || pathname.startsWith("/api/content/v1/")) {
|
|
22
|
+
return routes.content(request);
|
|
23
|
+
}
|
|
21
24
|
if (routes.studio && (pathname === "/studio" || pathname.startsWith("/studio/") || pathname.startsWith("/api/studio/"))) {
|
|
22
25
|
return routes.studio(request);
|
|
23
26
|
}
|
|
@@ -25,7 +28,7 @@ function createServeRouter(routes) {
|
|
|
25
28
|
const error = new GraftError({
|
|
26
29
|
code: "ROUTE_NOT_FOUND",
|
|
27
30
|
message: `Nothing is mounted at ${pathname}.`,
|
|
28
|
-
fix: `Use POST /api/fn/<name> (typed functions), POST /api/mcp (MCP Streamable HTTP), or GET /healthz${studioHint}.`,
|
|
31
|
+
fix: `Use POST /api/fn/<name> (typed functions), POST /api/mcp (MCP Streamable HTTP), GET /api/content/v1/documents (authored content), GET /api/content/v1/search, or GET /healthz${studioHint}.`,
|
|
29
32
|
details: { pathname }
|
|
30
33
|
});
|
|
31
34
|
return new Response(JSON.stringify(error.toJSON()), {
|
|
@@ -128,11 +131,13 @@ async function startServe(options) {
|
|
|
128
131
|
const [
|
|
129
132
|
{ createFunctionsHandler },
|
|
130
133
|
{ createGraftMcpHandler },
|
|
131
|
-
{
|
|
134
|
+
{ createContentApiHandler },
|
|
135
|
+
{ createDb, createDbIndexReader, resolveBranchHandle, scopeWriteBranch, sql },
|
|
132
136
|
studioMod
|
|
133
137
|
] = await Promise.all([
|
|
134
138
|
import("@usegraft/core"),
|
|
135
139
|
import("@usegraft/mcp"),
|
|
140
|
+
import("@usegraft/content-api"),
|
|
136
141
|
import("@usegraft/db"),
|
|
137
142
|
enableStudio ? import("@usegraft/studio") : Promise.resolve(null)
|
|
138
143
|
]);
|
|
@@ -147,7 +152,12 @@ async function startServe(options) {
|
|
|
147
152
|
issuers,
|
|
148
153
|
devTokens: devToken ? { [devToken]: { kind: "agent", id: "graft-serve", scopes } } : void 0
|
|
149
154
|
});
|
|
150
|
-
const approvalPolicy =
|
|
155
|
+
const approvalPolicy = config.approvalPolicy;
|
|
156
|
+
if (process.env.GRAFT_APPROVAL_POLICY) {
|
|
157
|
+
console.warn(
|
|
158
|
+
`[graft serve] GRAFT_APPROVAL_POLICY is set and is now ignored. Approval policy moved to graft.config.ts so that turning off the gate on destructive functions appears in a diff. Export \`approvalPolicy = "${process.env.GRAFT_APPROVAL_POLICY}"\` there instead. Serving with "${approvalPolicy}".`
|
|
159
|
+
);
|
|
160
|
+
}
|
|
151
161
|
const host = options.host ?? process.env.HOST ?? "127.0.0.1";
|
|
152
162
|
const loopback = host === "127.0.0.1" || host === "localhost" || host === "::1";
|
|
153
163
|
const anonymousOptIn = process.env.GRAFT_MCP_ALLOW_ANONYMOUS === "1";
|
|
@@ -174,7 +184,26 @@ async function startServe(options) {
|
|
|
174
184
|
branchId: writeBranch,
|
|
175
185
|
scope: branch.scope,
|
|
176
186
|
actor: resolveActor,
|
|
177
|
-
allowAnonymous: allowAnonymousMcp
|
|
187
|
+
allowAnonymous: allowAnonymousMcp,
|
|
188
|
+
// The same backstop the functions handler gets. Without it a function with
|
|
189
|
+
// no per-function rateLimit was capped over POST /api/fn and uncapped over
|
|
190
|
+
// run_function, so the transport decided the limit — and tools/functions.ts
|
|
191
|
+
// claims the two surfaces apply rate limits identically.
|
|
192
|
+
rateLimit: { limit: 60, windowSeconds: 60 }
|
|
193
|
+
});
|
|
194
|
+
const allowedOriginsRaw = process.env.GRAFT_CONTENT_ALLOWED_ORIGINS?.trim();
|
|
195
|
+
const allowedOrigins = allowedOriginsRaw === void 0 || allowedOriginsRaw === "" ? void 0 : allowedOriginsRaw === "*" ? "*" : allowedOriginsRaw.split(",").map((entry) => entry.trim()).filter(Boolean);
|
|
196
|
+
const contentHandler = createContentApiHandler({
|
|
197
|
+
collections: Object.keys(config.collections),
|
|
198
|
+
branch: writeBranch,
|
|
199
|
+
index: createDbIndexReader(branch.db),
|
|
200
|
+
...allowedOrigins === void 0 ? {} : { allowedOrigins },
|
|
201
|
+
// The same backstop the functions handler gets, for the same reason. These
|
|
202
|
+
// routes authenticate nobody and run database listings and full-text
|
|
203
|
+
// searches, so without a limit here one anonymous caller can keep the index
|
|
204
|
+
// busy indefinitely — and `graft serve` is the mount most likely to face
|
|
205
|
+
// the open internet.
|
|
206
|
+
rateLimit: { limit: 60, windowSeconds: 60 }
|
|
178
207
|
});
|
|
179
208
|
const health = async () => {
|
|
180
209
|
try {
|
|
@@ -218,6 +247,11 @@ async function startServe(options) {
|
|
|
218
247
|
"[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."
|
|
219
248
|
);
|
|
220
249
|
}
|
|
250
|
+
if (approvalPolicy === "unattended") {
|
|
251
|
+
console.warn(
|
|
252
|
+
'[graft serve] WARNING: approvalPolicy = "unattended" in graft.config.ts \u2014 destructive functions run without human approval. Deletes are not recoverable from git: deleteRecord removes rows outright and the asset store keeps no history. Audit rows are still written. This applies to POST /api/fn only; run_function over /api/mcp stays gated, because the policy is not part of the MCP surface.'
|
|
253
|
+
);
|
|
254
|
+
}
|
|
221
255
|
let studioHandler;
|
|
222
256
|
if (studioMod) {
|
|
223
257
|
const authenticate = !loopback && (devToken || issuers.length > 0) ? async (request) => {
|
|
@@ -240,7 +274,13 @@ async function startServe(options) {
|
|
|
240
274
|
}
|
|
241
275
|
const server = createServer(
|
|
242
276
|
createNodeListener(
|
|
243
|
-
createServeRouter({
|
|
277
|
+
createServeRouter({
|
|
278
|
+
fn: fnHandler,
|
|
279
|
+
mcp: mcpHandler,
|
|
280
|
+
content: contentHandler,
|
|
281
|
+
health,
|
|
282
|
+
studio: studioHandler
|
|
283
|
+
}),
|
|
244
284
|
{ allowedHosts: allowedHostsFor(host) }
|
|
245
285
|
)
|
|
246
286
|
);
|
|
@@ -272,6 +312,8 @@ async function serveCommand(options) {
|
|
|
272
312
|
`graft serve \u2014 branch "${running.branch}"`,
|
|
273
313
|
` functions POST ${base}/api/fn/<name>`,
|
|
274
314
|
` mcp POST ${base}/api/mcp`,
|
|
315
|
+
` documents GET ${base}/api/content/v1/documents`,
|
|
316
|
+
` search GET ${base}/api/content/v1/search`,
|
|
275
317
|
` health GET ${base}/healthz`,
|
|
276
318
|
...studioOn ? [
|
|
277
319
|
` studio GET ${base}/studio`,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
loadProjectEnv,
|
|
4
4
|
requireDatabaseUrl
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-2LG6TWYY.js";
|
|
6
6
|
|
|
7
7
|
// src/commands/approvals.ts
|
|
8
8
|
import { userInfo } from "os";
|
|
@@ -59,7 +59,9 @@ function formatApproval(row) {
|
|
|
59
59
|
` input: ${JSON.stringify(row.input)}`
|
|
60
60
|
].join("\n");
|
|
61
61
|
}
|
|
62
|
+
|
|
62
63
|
export {
|
|
64
|
+
operatorName,
|
|
63
65
|
approvalsListCommand,
|
|
64
66
|
decideCommand,
|
|
65
67
|
formatApproval
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
import {
|
|
3
3
|
assertNoStaticBranch,
|
|
4
4
|
compileCommand
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-2N3HXYNN.js";
|
|
6
6
|
import "./chunk-GPA66AP5.js";
|
|
7
|
-
import "./chunk-
|
|
7
|
+
import "./chunk-2LG6TWYY.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-2N3HXYNN.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-2LG6TWYY.js";
|
|
16
16
|
|
|
17
17
|
// src/commands/dev.ts
|
|
18
18
|
import { existsSync, watch } from "fs";
|
package/dist/index.js
CHANGED
|
@@ -50,6 +50,11 @@ function printHelp() {
|
|
|
50
50
|
" --port <n> Port for `graft serve` / `graft studio` (serve default 3903; studio 4983)",
|
|
51
51
|
" --host <h> Host for `graft serve` / `graft studio` (default: 127.0.0.1, or HOST)",
|
|
52
52
|
" --studio Mount opt-in Studio on `graft serve` at /studio (or GRAFT_STUDIO=1)",
|
|
53
|
+
" --elicit-approvals",
|
|
54
|
+
" `graft mcp` asks THIS terminal's operator to decide a destructive call,",
|
|
55
|
+
" instead of failing with an id for `graft approve`. Local only: the human",
|
|
56
|
+
" must be present and the client must support MCP elicitation. Decisions",
|
|
57
|
+
" are recorded as the OS user, exactly as `graft approve` records them.",
|
|
53
58
|
" --from <name> Parent to fork from (branch create; default: main)",
|
|
54
59
|
" --into <name> Merge target (merge; default: main)",
|
|
55
60
|
" --backend <kind> Branch backend: overlay (default) or neon (branch create)",
|
|
@@ -80,6 +85,7 @@ function parseArgs(rest) {
|
|
|
80
85
|
let overwrite = false;
|
|
81
86
|
let pruneUnknown = false;
|
|
82
87
|
let studio = false;
|
|
88
|
+
let elicitApprovals = false;
|
|
83
89
|
let initDriver;
|
|
84
90
|
const value = (flag, raw) => {
|
|
85
91
|
if (!raw || raw.startsWith("-")) {
|
|
@@ -115,6 +121,8 @@ function parseArgs(rest) {
|
|
|
115
121
|
pruneUnknown = true;
|
|
116
122
|
} else if (arg === "--studio") {
|
|
117
123
|
studio = true;
|
|
124
|
+
} else if (arg === "--elicit-approvals") {
|
|
125
|
+
elicitApprovals = true;
|
|
118
126
|
} else if (arg === "--postgres") {
|
|
119
127
|
initDriver = "postgres";
|
|
120
128
|
} else if (arg === "--static") {
|
|
@@ -138,6 +146,7 @@ function parseArgs(rest) {
|
|
|
138
146
|
overwrite,
|
|
139
147
|
pruneUnknown,
|
|
140
148
|
studio,
|
|
149
|
+
elicitApprovals,
|
|
141
150
|
initDriver
|
|
142
151
|
};
|
|
143
152
|
}
|
|
@@ -156,7 +165,7 @@ async function run(argv, options = {}) {
|
|
|
156
165
|
const args = parseArgs(rest);
|
|
157
166
|
switch (command) {
|
|
158
167
|
case "init": {
|
|
159
|
-
const { initCommand } = await import("./init-
|
|
168
|
+
const { initCommand } = await import("./init-FV7Q6VXM.js");
|
|
160
169
|
const result = initCommand({
|
|
161
170
|
targetDir: args.positionals[0] ?? cwd,
|
|
162
171
|
driver: args.initDriver
|
|
@@ -187,12 +196,12 @@ async function run(argv, options = {}) {
|
|
|
187
196
|
return 0;
|
|
188
197
|
}
|
|
189
198
|
case "compile": {
|
|
190
|
-
const { compileCommand } = await import("./compile-
|
|
199
|
+
const { compileCommand } = await import("./compile-AWPSEA7U.js");
|
|
191
200
|
await compileCommand({ cwd, branchId: args.branchId, pruneUnknown: args.pruneUnknown });
|
|
192
201
|
return 0;
|
|
193
202
|
}
|
|
194
203
|
case "dev": {
|
|
195
|
-
const { devCommand } = await import("./dev-
|
|
204
|
+
const { devCommand } = await import("./dev-WHTIRWMR.js");
|
|
196
205
|
await devCommand({ cwd, branchId: args.branchId });
|
|
197
206
|
return 0;
|
|
198
207
|
}
|
|
@@ -203,7 +212,7 @@ async function run(argv, options = {}) {
|
|
|
203
212
|
subcommand ? `unknown db subcommand "${subcommand}" \u2014 the only one is \`graft db migrate\`` : "usage: graft db migrate [--dry-run]"
|
|
204
213
|
);
|
|
205
214
|
}
|
|
206
|
-
const { dbMigrateCommand, formatMigrateResult } = await import("./db-
|
|
215
|
+
const { dbMigrateCommand, formatMigrateResult } = await import("./db-5YMFKHGO.js");
|
|
207
216
|
const result = await dbMigrateCommand({ cwd, dryRun: args.dryRun });
|
|
208
217
|
console.log(formatMigrateResult(result));
|
|
209
218
|
return 0;
|
|
@@ -213,7 +222,7 @@ async function run(argv, options = {}) {
|
|
|
213
222
|
if (subcommand !== "put" || !file) {
|
|
214
223
|
throw new UsageError("usage: graft asset put <file> [key]");
|
|
215
224
|
}
|
|
216
|
-
const { assetPutCommand } = await import("./asset-
|
|
225
|
+
const { assetPutCommand } = await import("./asset-JWER6AOG.js");
|
|
217
226
|
const result = await assetPutCommand({ cwd, file, key });
|
|
218
227
|
console.log(`Uploaded ${result.key} (${result.contentType}, ${result.bytes} bytes)`);
|
|
219
228
|
console.log(
|
|
@@ -228,7 +237,7 @@ async function run(argv, options = {}) {
|
|
|
228
237
|
return 0;
|
|
229
238
|
}
|
|
230
239
|
case "approvals": {
|
|
231
|
-
const { approvalsListCommand, formatApproval } = await import("./approvals-
|
|
240
|
+
const { approvalsListCommand, formatApproval } = await import("./approvals-4PAANLA4.js");
|
|
232
241
|
const pending = await approvalsListCommand({ cwd });
|
|
233
242
|
if (pending.length === 0) {
|
|
234
243
|
console.log("No pending approvals.");
|
|
@@ -245,7 +254,7 @@ async function run(argv, options = {}) {
|
|
|
245
254
|
case "deny": {
|
|
246
255
|
const id = args.positionals[0];
|
|
247
256
|
if (!id) throw new UsageError(`usage: graft ${command} <approval-id>`);
|
|
248
|
-
const { decideCommand } = await import("./approvals-
|
|
257
|
+
const { decideCommand } = await import("./approvals-4PAANLA4.js");
|
|
249
258
|
const decision = command === "approve" ? "approved" : "denied";
|
|
250
259
|
const row = await decideCommand({ cwd, id, decision });
|
|
251
260
|
console.log(
|
|
@@ -259,7 +268,7 @@ async function run(argv, options = {}) {
|
|
|
259
268
|
return 0;
|
|
260
269
|
}
|
|
261
270
|
case "migrate": {
|
|
262
|
-
const { migrateCommand } = await import("./migrate-
|
|
271
|
+
const { migrateCommand } = await import("./migrate-6ZYG2H5C.js");
|
|
263
272
|
await migrateCommand({ cwd, branchId: args.branchId, apply: args.apply });
|
|
264
273
|
return 0;
|
|
265
274
|
}
|
|
@@ -273,7 +282,7 @@ async function run(argv, options = {}) {
|
|
|
273
282
|
if (subcommand && !name) {
|
|
274
283
|
throw new UsageError(`usage: graft branch ${subcommand} <name>`);
|
|
275
284
|
}
|
|
276
|
-
const mod = await import("./branch-
|
|
285
|
+
const mod = await import("./branch-U7FFDTFV.js");
|
|
277
286
|
if (!subcommand) {
|
|
278
287
|
const rows = await mod.branchListCommand({ cwd });
|
|
279
288
|
if (rows.length === 0) {
|
|
@@ -316,12 +325,12 @@ async function run(argv, options = {}) {
|
|
|
316
325
|
const branch = args.positionals[0];
|
|
317
326
|
if (!branch)
|
|
318
327
|
throw new UsageError("usage: graft merge <branch> [--into <target>] [--apply]");
|
|
319
|
-
const { mergeCommand } = await import("./merge-
|
|
328
|
+
const { mergeCommand } = await import("./merge-ZWYZJVFE.js");
|
|
320
329
|
await mergeCommand({ cwd, branch, into: args.into, apply: args.apply });
|
|
321
330
|
return 0;
|
|
322
331
|
}
|
|
323
332
|
case "add": {
|
|
324
|
-
const { addCommand } = await import("./add-
|
|
333
|
+
const { addCommand } = await import("./add-TCQY3YAN.js");
|
|
325
334
|
await addCommand({
|
|
326
335
|
cwd,
|
|
327
336
|
names: args.positionals,
|
|
@@ -331,12 +340,12 @@ async function run(argv, options = {}) {
|
|
|
331
340
|
return 0;
|
|
332
341
|
}
|
|
333
342
|
case "mcp": {
|
|
334
|
-
const { mcpCommand } = await import("./mcp-
|
|
335
|
-
await mcpCommand({ cwd, branchId: args.branchId });
|
|
343
|
+
const { mcpCommand } = await import("./mcp-77QFFJXK.js");
|
|
344
|
+
await mcpCommand({ cwd, branchId: args.branchId, elicitApprovals: args.elicitApprovals });
|
|
336
345
|
return 0;
|
|
337
346
|
}
|
|
338
347
|
case "serve": {
|
|
339
|
-
const { serveCommand } = await import("./serve-
|
|
348
|
+
const { serveCommand } = await import("./serve-5ADUQG66.js");
|
|
340
349
|
await serveCommand({
|
|
341
350
|
cwd,
|
|
342
351
|
branchId: args.branchId,
|
|
@@ -347,7 +356,7 @@ async function run(argv, options = {}) {
|
|
|
347
356
|
return 0;
|
|
348
357
|
}
|
|
349
358
|
case "studio": {
|
|
350
|
-
const { studioCommand } = await import("./studio-
|
|
359
|
+
const { studioCommand } = await import("./studio-7VAYFEWS.js");
|
|
351
360
|
await studioCommand({
|
|
352
361
|
cwd,
|
|
353
362
|
branchId: args.branchId,
|
|
@@ -357,7 +366,7 @@ async function run(argv, options = {}) {
|
|
|
357
366
|
return 0;
|
|
358
367
|
}
|
|
359
368
|
case "content": {
|
|
360
|
-
const { contentListCommand, formatContentLine } = await import("./content-
|
|
369
|
+
const { contentListCommand, formatContentLine } = await import("./content-ZULMTJMD.js");
|
|
361
370
|
const { branch, lines } = await contentListCommand({ cwd, branchId: args.branchId });
|
|
362
371
|
if (lines.length === 0) {
|
|
363
372
|
console.log(`No content on branch "${branch}" (run graft compile).`);
|
|
@@ -369,7 +378,7 @@ async function run(argv, options = {}) {
|
|
|
369
378
|
return 0;
|
|
370
379
|
}
|
|
371
380
|
case "compilations": {
|
|
372
|
-
const { compilationsListCommand, formatCompilation } = await import("./compilations-
|
|
381
|
+
const { compilationsListCommand, formatCompilation } = await import("./compilations-CH6AIOFG.js");
|
|
373
382
|
const rows = await compilationsListCommand({ cwd, branchId: args.branchId });
|
|
374
383
|
if (rows.length === 0) {
|
|
375
384
|
console.log("No compilations recorded yet (run graft compile).");
|
|
@@ -381,7 +390,7 @@ async function run(argv, options = {}) {
|
|
|
381
390
|
case "harden": {
|
|
382
391
|
const role = args.positionals[0];
|
|
383
392
|
if (!role) throw new UsageError("usage: graft harden <role>");
|
|
384
|
-
const { hardenCommand } = await import("./harden-
|
|
393
|
+
const { hardenCommand } = await import("./harden-QONL2MAO.js");
|
|
385
394
|
const result = await hardenCommand({ cwd, role });
|
|
386
395
|
console.log(`Hardened runtime role "${result.role}" (${result.statements.length} grants):`);
|
|
387
396
|
for (const statement of result.statements) console.log(` ${statement}`);
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
assertNoStaticBranch
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-2N3HXYNN.js";
|
|
5
5
|
import "./chunk-GPA66AP5.js";
|
|
6
|
+
import {
|
|
7
|
+
operatorName
|
|
8
|
+
} from "./chunk-NBJ4N4O6.js";
|
|
6
9
|
import {
|
|
7
10
|
findConfig,
|
|
8
11
|
loadConfig,
|
|
9
12
|
loadProjectEnv,
|
|
10
13
|
requireDatabaseUrl
|
|
11
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-2LG6TWYY.js";
|
|
12
15
|
|
|
13
16
|
// src/commands/mcp.ts
|
|
14
17
|
import { createActorResolver } from "@usegraft/auth";
|
|
@@ -38,6 +41,7 @@ async function mcpCommand(options) {
|
|
|
38
41
|
const resolved = await resolveActor(request);
|
|
39
42
|
return resolved.kind === "anonymous" ? cliActor : resolved;
|
|
40
43
|
};
|
|
44
|
+
const approvalElicitation = options.elicitApprovals ? { decider: { kind: "human", id: operatorName() } } : void 0;
|
|
41
45
|
const server = createGraftMcp({
|
|
42
46
|
name: "graft",
|
|
43
47
|
contentDir: config.contentDir,
|
|
@@ -56,7 +60,8 @@ async function mcpCommand(options) {
|
|
|
56
60
|
// Local agents may upload a file from the project; remote mounts get no
|
|
57
61
|
// `path` argument at all.
|
|
58
62
|
localUploadRoot: config.projectDir,
|
|
59
|
-
defaultAuthorization: devToken
|
|
63
|
+
defaultAuthorization: devToken,
|
|
64
|
+
approvalElicitation
|
|
60
65
|
});
|
|
61
66
|
await serveStdio(server);
|
|
62
67
|
} finally {
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
discoverMigrations
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-DW6WTDRX.js";
|
|
5
5
|
import {
|
|
6
6
|
findConfig,
|
|
7
7
|
loadConfig,
|
|
8
8
|
loadProjectEnv,
|
|
9
9
|
requireDatabaseUrl
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-2LG6TWYY.js";
|
|
11
11
|
|
|
12
12
|
// src/commands/merge.ts
|
|
13
13
|
import { basename } from "path";
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
import {
|
|
3
3
|
allowedHostsFor,
|
|
4
4
|
createNodeListener
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-CONTLKSZ.js";
|
|
6
6
|
import {
|
|
7
7
|
findConfig,
|
|
8
8
|
loadConfig,
|
|
9
9
|
loadProjectEnv,
|
|
10
10
|
requireDatabaseUrl
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-2LG6TWYY.js";
|
|
12
12
|
|
|
13
13
|
// src/commands/studio.ts
|
|
14
14
|
import { execFile } from "child_process";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@usegraft/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0-beta.0",
|
|
4
4
|
"description": "The graft CLI: scaffold, compile authored content, serve the runtime, and split your database credentials.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent",
|
|
@@ -34,21 +34,22 @@
|
|
|
34
34
|
"access": "public"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@usegraft/assets": "0.
|
|
38
|
-
"@usegraft/auth": "0.
|
|
39
|
-
"@usegraft/compiler": "0.
|
|
40
|
-
"@usegraft/content-
|
|
41
|
-
"@usegraft/
|
|
42
|
-
"@usegraft/
|
|
43
|
-
"@usegraft/
|
|
44
|
-
"@usegraft/
|
|
45
|
-
"@usegraft/
|
|
46
|
-
"@usegraft/
|
|
47
|
-
"@usegraft/
|
|
37
|
+
"@usegraft/assets": "1.0.0-beta.0",
|
|
38
|
+
"@usegraft/auth": "1.0.0-beta.0",
|
|
39
|
+
"@usegraft/compiler": "1.0.0-beta.0",
|
|
40
|
+
"@usegraft/content-api": "1.0.0-beta.0",
|
|
41
|
+
"@usegraft/content-migrations": "1.0.0-beta.0",
|
|
42
|
+
"@usegraft/contracts": "1.0.0-beta.0",
|
|
43
|
+
"@usegraft/core": "1.0.0-beta.0",
|
|
44
|
+
"@usegraft/db": "1.0.0-beta.0",
|
|
45
|
+
"@usegraft/mcp": "1.0.0-beta.0",
|
|
46
|
+
"@usegraft/mdx-safety": "1.0.0-beta.0",
|
|
47
|
+
"@usegraft/registry": "1.0.0-beta.0",
|
|
48
|
+
"@usegraft/studio": "1.0.0-beta.0",
|
|
48
49
|
"jiti": "^2.4.0"
|
|
49
50
|
},
|
|
50
51
|
"devDependencies": {
|
|
51
|
-
"@usegraft/sdk-core": "0.
|
|
52
|
+
"@usegraft/sdk-core": "1.0.0-beta.0"
|
|
52
53
|
},
|
|
53
54
|
"engines": {
|
|
54
55
|
"node": ">=22.16"
|