create-objectstack 15.1.1 → 16.0.0-rc.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 +2 -1
- package/dist/index.js +72 -64
- package/dist/templates/AGENTS.md +1 -1
- package/dist/templates/blank/README.md +44 -0
- package/dist/templates/blank/_gitignore +7 -0
- package/dist/templates/blank/objectstack.config.ts +25 -1
- package/dist/templates/blank/package.json +8 -5
- package/dist/templates/blank/pnpm-workspace.yaml +23 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -59,7 +59,8 @@ offline.
|
|
|
59
59
|
(`blank_note` → `my_app_note`).
|
|
60
60
|
2. Installs dependencies (pnpm if available, otherwise npm).
|
|
61
61
|
3. Installs the ObjectStack AI skills bundle for coding agents
|
|
62
|
-
(`npx skills add objectstack-ai/framework --all`
|
|
62
|
+
(`npx skills add objectstack-ai/framework/skills --all` — scoped to the
|
|
63
|
+
curated `skills/` catalog).
|
|
63
64
|
4. Writes `AGENTS.md` and `.github/copilot-instructions.md` with the project
|
|
64
65
|
conventions — unless the template ships its own.
|
|
65
66
|
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
import { Command } from "commander";
|
|
3
3
|
import chalk from "chalk";
|
|
4
|
-
import
|
|
5
|
-
import
|
|
4
|
+
import fs2 from "fs";
|
|
5
|
+
import path2 from "path";
|
|
6
6
|
import os from "os";
|
|
7
7
|
import { execSync } from "child_process";
|
|
8
8
|
import { fileURLToPath } from "url";
|
|
@@ -25,10 +25,32 @@ function syncObjectStackDeps(pkg, version) {
|
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
// src/template-copy.ts
|
|
29
|
+
import fs from "fs";
|
|
30
|
+
import path from "path";
|
|
31
|
+
var TEMPLATE_FILE_ALIASES = /* @__PURE__ */ new Map([
|
|
32
|
+
["_gitignore", ".gitignore"]
|
|
33
|
+
]);
|
|
34
|
+
function copyDir(src, dest, collected, rel = "") {
|
|
35
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
36
|
+
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
37
|
+
const srcPath = path.join(src, entry.name);
|
|
38
|
+
const outName = entry.isFile() ? TEMPLATE_FILE_ALIASES.get(entry.name) ?? entry.name : entry.name;
|
|
39
|
+
const destPath = path.join(dest, outName);
|
|
40
|
+
const relPath = rel ? `${rel}/${outName}` : outName;
|
|
41
|
+
if (entry.isDirectory()) {
|
|
42
|
+
copyDir(srcPath, destPath, collected, relPath);
|
|
43
|
+
} else if (entry.isFile()) {
|
|
44
|
+
fs.copyFileSync(srcPath, destPath);
|
|
45
|
+
collected.push(relPath);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
28
50
|
// src/index.ts
|
|
29
51
|
var __filename2 = fileURLToPath(import.meta.url);
|
|
30
|
-
var __dirname2 =
|
|
31
|
-
var BUNDLED_TEMPLATES_DIR =
|
|
52
|
+
var __dirname2 = path2.dirname(__filename2);
|
|
53
|
+
var BUNDLED_TEMPLATES_DIR = path2.resolve(__dirname2, "templates");
|
|
32
54
|
var REMOTE_REPO = "objectstack-ai/templates";
|
|
33
55
|
var REMOTE_BRANCH = "main";
|
|
34
56
|
var REMOTE_TARBALL_URL = `https://codeload.github.com/${REMOTE_REPO}/tar.gz/refs/heads/${REMOTE_BRANCH}`;
|
|
@@ -74,8 +96,8 @@ function sanitizeNamespace(name) {
|
|
|
74
96
|
}
|
|
75
97
|
function readCliVersion() {
|
|
76
98
|
try {
|
|
77
|
-
const pkgPath =
|
|
78
|
-
const pkg = JSON.parse(
|
|
99
|
+
const pkgPath = path2.resolve(__dirname2, "..", "package.json");
|
|
100
|
+
const pkg = JSON.parse(fs2.readFileSync(pkgPath, "utf8"));
|
|
79
101
|
return String(pkg.version || "0.0.0");
|
|
80
102
|
} catch {
|
|
81
103
|
return "0.0.0";
|
|
@@ -109,23 +131,9 @@ function detectPackageManager() {
|
|
|
109
131
|
return "npm";
|
|
110
132
|
}
|
|
111
133
|
}
|
|
112
|
-
function copyDir(src, dest, collected, rel = "") {
|
|
113
|
-
fs.mkdirSync(dest, { recursive: true });
|
|
114
|
-
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
115
|
-
const srcPath = path.join(src, entry.name);
|
|
116
|
-
const destPath = path.join(dest, entry.name);
|
|
117
|
-
const relPath = rel ? `${rel}/${entry.name}` : entry.name;
|
|
118
|
-
if (entry.isDirectory()) {
|
|
119
|
-
copyDir(srcPath, destPath, collected, relPath);
|
|
120
|
-
} else if (entry.isFile()) {
|
|
121
|
-
fs.copyFileSync(srcPath, destPath);
|
|
122
|
-
collected.push(relPath);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
134
|
function loadBundled(templateDir, targetDir) {
|
|
127
|
-
const src =
|
|
128
|
-
if (!
|
|
135
|
+
const src = path2.join(BUNDLED_TEMPLATES_DIR, templateDir);
|
|
136
|
+
if (!fs2.existsSync(src)) {
|
|
129
137
|
throw new Error(`Bundled template missing on disk: ${src}`);
|
|
130
138
|
}
|
|
131
139
|
const collected = [];
|
|
@@ -146,12 +154,12 @@ async function downloadTarball(url, destFile) {
|
|
|
146
154
|
});
|
|
147
155
|
}
|
|
148
156
|
async function loadRemote(pkgName, targetDir) {
|
|
149
|
-
const tmp = await mkdtemp(
|
|
157
|
+
const tmp = await mkdtemp(path2.join(os.tmpdir(), "create-objectstack-"));
|
|
150
158
|
try {
|
|
151
|
-
const tarball =
|
|
159
|
+
const tarball = path2.join(tmp, "templates.tar.gz");
|
|
152
160
|
printStep(`Fetching template "${pkgName}" from ${REMOTE_REPO}@${REMOTE_BRANCH}\u2026`);
|
|
153
161
|
await downloadTarball(REMOTE_TARBALL_URL, tarball);
|
|
154
|
-
|
|
162
|
+
fs2.mkdirSync(targetDir, { recursive: true });
|
|
155
163
|
const collected = [];
|
|
156
164
|
await pipeline(
|
|
157
165
|
createReadStream(tarball),
|
|
@@ -183,57 +191,57 @@ async function loadRemote(pkgName, targetDir) {
|
|
|
183
191
|
}
|
|
184
192
|
}
|
|
185
193
|
function walkAndRewriteTs(dir, fn) {
|
|
186
|
-
if (!
|
|
187
|
-
for (const entry of
|
|
188
|
-
const full =
|
|
194
|
+
if (!fs2.existsSync(dir)) return;
|
|
195
|
+
for (const entry of fs2.readdirSync(dir, { withFileTypes: true })) {
|
|
196
|
+
const full = path2.join(dir, entry.name);
|
|
189
197
|
if (entry.isDirectory()) {
|
|
190
198
|
walkAndRewriteTs(full, fn);
|
|
191
199
|
} else if (entry.isFile() && entry.name.endsWith(".ts")) {
|
|
192
|
-
const before =
|
|
200
|
+
const before = fs2.readFileSync(full, "utf8");
|
|
193
201
|
const after = fn(before);
|
|
194
|
-
if (after !== before)
|
|
202
|
+
if (after !== before) fs2.writeFileSync(full, after);
|
|
195
203
|
}
|
|
196
204
|
}
|
|
197
205
|
}
|
|
198
206
|
function rewriteProjectIdentity(targetDir, projectName, namespace) {
|
|
199
207
|
const title = toTitleCase(projectName);
|
|
200
208
|
let templateNamespace;
|
|
201
|
-
const manifestPathPre =
|
|
202
|
-
if (
|
|
209
|
+
const manifestPathPre = path2.join(targetDir, "objectstack.manifest.json");
|
|
210
|
+
if (fs2.existsSync(manifestPathPre)) {
|
|
203
211
|
try {
|
|
204
|
-
const m = JSON.parse(
|
|
212
|
+
const m = JSON.parse(fs2.readFileSync(manifestPathPre, "utf8"));
|
|
205
213
|
if (typeof m.namespace === "string") templateNamespace = m.namespace;
|
|
206
214
|
} catch {
|
|
207
215
|
}
|
|
208
216
|
}
|
|
209
|
-
const pkgPath =
|
|
210
|
-
if (
|
|
217
|
+
const pkgPath = path2.join(targetDir, "package.json");
|
|
218
|
+
if (fs2.existsSync(pkgPath)) {
|
|
211
219
|
try {
|
|
212
|
-
const pkg = JSON.parse(
|
|
220
|
+
const pkg = JSON.parse(fs2.readFileSync(pkgPath, "utf8"));
|
|
213
221
|
pkg.name = projectName;
|
|
214
222
|
syncObjectStackDeps(pkg, readCliVersion());
|
|
215
|
-
|
|
223
|
+
fs2.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
216
224
|
} catch {
|
|
217
225
|
}
|
|
218
226
|
}
|
|
219
|
-
const manifestPath =
|
|
220
|
-
if (
|
|
227
|
+
const manifestPath = path2.join(targetDir, "objectstack.manifest.json");
|
|
228
|
+
if (fs2.existsSync(manifestPath)) {
|
|
221
229
|
try {
|
|
222
|
-
const m = JSON.parse(
|
|
230
|
+
const m = JSON.parse(fs2.readFileSync(manifestPath, "utf8"));
|
|
223
231
|
m.name = projectName;
|
|
224
232
|
m.displayName = title;
|
|
225
233
|
if ("namespace" in m) m.namespace = namespace;
|
|
226
|
-
|
|
234
|
+
fs2.writeFileSync(manifestPath, JSON.stringify(m, null, 2) + "\n");
|
|
227
235
|
} catch {
|
|
228
236
|
}
|
|
229
237
|
}
|
|
230
|
-
const configPath =
|
|
231
|
-
if (
|
|
232
|
-
let cfg =
|
|
238
|
+
const configPath = path2.join(targetDir, "objectstack.config.ts");
|
|
239
|
+
if (fs2.existsSync(configPath)) {
|
|
240
|
+
let cfg = fs2.readFileSync(configPath, "utf8");
|
|
233
241
|
cfg = cfg.replace(/(\bid:\s*)(['"`])[^'"`]*\2/, `$1$2${projectName}$2`);
|
|
234
242
|
cfg = cfg.replace(/(\bnamespace:\s*)(['"`])[^'"`]*\2/, `$1$2${namespace}$2`);
|
|
235
243
|
cfg = cfg.replace(/(\bname:\s*)(['"`])[^'"`]*\2/, `$1$2${title}$2`);
|
|
236
|
-
|
|
244
|
+
fs2.writeFileSync(configPath, cfg);
|
|
237
245
|
}
|
|
238
246
|
if (namespace !== templateNamespace && templateNamespace) {
|
|
239
247
|
const prefixRe = new RegExp(
|
|
@@ -241,39 +249,39 @@ function rewriteProjectIdentity(targetDir, projectName, namespace) {
|
|
|
241
249
|
"g"
|
|
242
250
|
);
|
|
243
251
|
walkAndRewriteTs(
|
|
244
|
-
|
|
252
|
+
path2.join(targetDir, "src"),
|
|
245
253
|
(src) => src.replace(
|
|
246
254
|
prefixRe,
|
|
247
255
|
(_m, prefix, q, rest) => `${prefix}${q}${namespace}_${rest}${q}`
|
|
248
256
|
)
|
|
249
257
|
);
|
|
250
258
|
}
|
|
251
|
-
const readmePath =
|
|
252
|
-
if (
|
|
253
|
-
let md =
|
|
259
|
+
const readmePath = path2.join(targetDir, "README.md");
|
|
260
|
+
if (fs2.existsSync(readmePath)) {
|
|
261
|
+
let md = fs2.readFileSync(readmePath, "utf8");
|
|
254
262
|
md = md.replace(/^#\s+.*$/m, `# ${title}`);
|
|
255
|
-
|
|
263
|
+
fs2.writeFileSync(readmePath, md);
|
|
256
264
|
}
|
|
257
265
|
writeAgentGuides(targetDir, title, projectName);
|
|
258
266
|
}
|
|
259
267
|
function writeAgentGuides(targetDir, title, projectName) {
|
|
260
|
-
const templatePath =
|
|
268
|
+
const templatePath = path2.join(BUNDLED_TEMPLATES_DIR, "AGENTS.md");
|
|
261
269
|
let template;
|
|
262
270
|
try {
|
|
263
|
-
template =
|
|
271
|
+
template = fs2.readFileSync(templatePath, "utf8");
|
|
264
272
|
} catch (err) {
|
|
265
273
|
if (err?.code === "ENOENT") return;
|
|
266
274
|
throw err;
|
|
267
275
|
}
|
|
268
276
|
const rendered = template.replace(/\{\{PROJECT_TITLE\}\}/g, title).replace(/\{\{PROJECT_NAME\}\}/g, projectName);
|
|
269
|
-
writeIfAbsent(
|
|
270
|
-
const copilotPath =
|
|
271
|
-
|
|
277
|
+
writeIfAbsent(path2.join(targetDir, "AGENTS.md"), rendered);
|
|
278
|
+
const copilotPath = path2.join(targetDir, ".github", "copilot-instructions.md");
|
|
279
|
+
fs2.mkdirSync(path2.dirname(copilotPath), { recursive: true });
|
|
272
280
|
writeIfAbsent(copilotPath, rendered);
|
|
273
281
|
}
|
|
274
282
|
function writeIfAbsent(filePath, contents) {
|
|
275
283
|
try {
|
|
276
|
-
|
|
284
|
+
fs2.writeFileSync(filePath, contents, { flag: "wx" });
|
|
277
285
|
} catch (err) {
|
|
278
286
|
if (err?.code !== "EEXIST") throw err;
|
|
279
287
|
}
|
|
@@ -295,24 +303,24 @@ var program = new Command().name("create-objectstack").description("Create a new
|
|
|
295
303
|
process.exit(1);
|
|
296
304
|
}
|
|
297
305
|
const cwd = process.cwd();
|
|
298
|
-
const projectName = name ||
|
|
306
|
+
const projectName = name || path2.basename(cwd);
|
|
299
307
|
const namespace = sanitizeNamespace(projectName);
|
|
300
|
-
const targetDir = name ?
|
|
308
|
+
const targetDir = name ? path2.resolve(cwd, name) : cwd;
|
|
301
309
|
const isCurrentDir = targetDir === cwd;
|
|
302
310
|
printKV("Environment", projectName);
|
|
303
311
|
printKV("Namespace", namespace);
|
|
304
312
|
printKV("Template", `${options.template} \u2014 ${template.description}`);
|
|
305
313
|
printKV("Directory", targetDir);
|
|
306
314
|
console.log("");
|
|
307
|
-
if (!isCurrentDir &&
|
|
308
|
-
const existing =
|
|
315
|
+
if (!isCurrentDir && fs2.existsSync(targetDir)) {
|
|
316
|
+
const existing = fs2.readdirSync(targetDir);
|
|
309
317
|
if (existing.length > 0) {
|
|
310
318
|
printError(`Directory already exists and is not empty: ${targetDir}`);
|
|
311
319
|
process.exit(1);
|
|
312
320
|
}
|
|
313
321
|
}
|
|
314
322
|
try {
|
|
315
|
-
|
|
323
|
+
fs2.mkdirSync(targetDir, { recursive: true });
|
|
316
324
|
let createdFiles;
|
|
317
325
|
if (template.source.kind === "bundled") {
|
|
318
326
|
createdFiles = loadBundled(template.source.dir, targetDir);
|
|
@@ -342,14 +350,14 @@ var program = new Command().name("create-objectstack").description("Create a new
|
|
|
342
350
|
if (!options.skipInstall && !options.skipSkills) {
|
|
343
351
|
printStep("Installing AI skills for your coding agent...");
|
|
344
352
|
try {
|
|
345
|
-
execSync("npx -y skills add objectstack-ai/framework --all", {
|
|
353
|
+
execSync("npx -y skills add objectstack-ai/framework/skills --all", {
|
|
346
354
|
stdio: "inherit",
|
|
347
355
|
cwd: targetDir
|
|
348
356
|
});
|
|
349
357
|
console.log("");
|
|
350
358
|
} catch {
|
|
351
359
|
printWarning(
|
|
352
|
-
"Skills installation skipped. Run manually:\n npx skills add objectstack-ai/framework"
|
|
360
|
+
"Skills installation skipped. Run manually:\n npx skills add objectstack-ai/framework/skills"
|
|
353
361
|
);
|
|
354
362
|
console.log("");
|
|
355
363
|
}
|
|
@@ -369,7 +377,7 @@ var program = new Command().name("create-objectstack").description("Create a new
|
|
|
369
377
|
if (options.skipInstall || options.skipSkills) {
|
|
370
378
|
console.log("");
|
|
371
379
|
console.log(chalk.bold(" AI Skills (recommended):"));
|
|
372
|
-
console.log(chalk.dim(" npx skills add objectstack-ai/framework"));
|
|
380
|
+
console.log(chalk.dim(" npx skills add objectstack-ai/framework/skills"));
|
|
373
381
|
}
|
|
374
382
|
console.log("");
|
|
375
383
|
} catch (error) {
|
package/dist/templates/AGENTS.md
CHANGED
|
@@ -77,7 +77,7 @@ This project uses ObjectStack skills from `objectstack-ai/framework`.
|
|
|
77
77
|
Install or update skills with the standard [skills CLI](https://skills.sh/):
|
|
78
78
|
|
|
79
79
|
```bash
|
|
80
|
-
npx skills add objectstack-ai/framework
|
|
80
|
+
npx skills add objectstack-ai/framework/skills
|
|
81
81
|
```
|
|
82
82
|
|
|
83
83
|
Skills are triggered automatically based on task context:
|
|
@@ -21,11 +21,55 @@ curl -c cookies.txt -X POST http://localhost:3000/api/v1/auth/sign-in/email \
|
|
|
21
21
|
curl -b cookies.txt "http://localhost:3000/api/v1/data/<your_object>"
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
+
## Your app is an MCP server
|
|
25
|
+
|
|
26
|
+
Every ObjectStack app is itself a
|
|
27
|
+
[Model Context Protocol](https://modelcontextprotocol.io) server — **on by
|
|
28
|
+
default**, no plugin to install. `pnpm dev` prints the endpoint and a
|
|
29
|
+
ready-to-paste connect command on boot; point a coding agent (Claude Code,
|
|
30
|
+
Cursor, any MCP client) at it and it can read your schema, query data, and run
|
|
31
|
+
your exposed actions — all under the caller's own permissions and RLS:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
claude mcp add --transport http my-app http://localhost:3000/api/v1/mcp
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Set `OS_MCP_SERVER_ENABLED=false` to turn it off. This is the *serve* side — the
|
|
38
|
+
reverse of the `mcp` connector below (which lets your app *call* other MCP
|
|
39
|
+
servers). See [Connect an MCP Client](https://docs.objectstack.ai/docs/ai/connect-mcp)
|
|
40
|
+
for OAuth, API keys, and which objects/actions become tools.
|
|
41
|
+
|
|
24
42
|
## Layout
|
|
25
43
|
|
|
26
44
|
- `objectstack.config.ts` — environment manifest (objects, API, plugins)
|
|
27
45
|
- `src/objects/` — object definitions (one file per object)
|
|
28
46
|
|
|
47
|
+
## Connectors (default providers)
|
|
48
|
+
|
|
49
|
+
`objectstack.config.ts` wires the three **generic connector executors**, so you
|
|
50
|
+
can call an external system from a flow as pure metadata — no host code:
|
|
51
|
+
|
|
52
|
+
| Provider | Package | Use for |
|
|
53
|
+
|:---|:---|:---|
|
|
54
|
+
| `rest` | `@objectstack/connector-rest` | Any JSON/HTTP REST API |
|
|
55
|
+
| `openapi` | `@objectstack/connector-openapi` | An API described by an OpenAPI document |
|
|
56
|
+
| `mcp` | `@objectstack/connector-mcp` | A Model Context Protocol server |
|
|
57
|
+
|
|
58
|
+
Add a `connectors:` entry that names one of these `provider`s and the
|
|
59
|
+
`automation` capability materializes it into a live, dispatchable connector at
|
|
60
|
+
boot (ADR-0097); a flow's `connector_action` node then calls it. To add a brand
|
|
61
|
+
connector (e.g. Slack), install its package and add `new ConnectorSlackPlugin()`
|
|
62
|
+
to `plugins:`; to drop a provider, remove its plugin.
|
|
63
|
+
|
|
64
|
+
> **Security — declarative MCP over stdio.** An `mcp` connector whose transport
|
|
65
|
+
> spawns a local process (`stdio`) is denied by default, because the command
|
|
66
|
+
> comes from metadata. Opt in per host with
|
|
67
|
+
> `new ConnectorMcpPlugin({ declarativeStdio: ['node'] })`; `http` transports
|
|
68
|
+
> need no opt-in.
|
|
69
|
+
|
|
70
|
+
See [Automation → Flows](https://docs.objectstack.ai/docs/automation/flows) for
|
|
71
|
+
the full connector and `connector_action` guide.
|
|
72
|
+
|
|
29
73
|
## Verify your changes
|
|
30
74
|
|
|
31
75
|
After editing any metadata, run:
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { defineStack } from '@objectstack/spec';
|
|
2
|
+
import { ConnectorRestPlugin } from '@objectstack/connector-rest';
|
|
3
|
+
import { ConnectorOpenApiPlugin } from '@objectstack/connector-openapi';
|
|
4
|
+
import { ConnectorMcpPlugin } from '@objectstack/connector-mcp';
|
|
2
5
|
import * as objects from './src/objects/index.js';
|
|
3
6
|
|
|
4
7
|
export default defineStack({
|
|
@@ -13,7 +16,28 @@ export default defineStack({
|
|
|
13
16
|
// refuse this package at the boundary with the exact migration command,
|
|
14
17
|
// instead of crashing later. Kept in lockstep with releases by
|
|
15
18
|
// scripts/sync-template-versions.mjs.
|
|
16
|
-
engines: { protocol: '^
|
|
19
|
+
engines: { protocol: '^16' },
|
|
17
20
|
},
|
|
21
|
+
|
|
22
|
+
// `automation` backs flow execution and, per ADR-0097, materializes any
|
|
23
|
+
// declarative `connectors:` entry into a live, dispatchable connector at boot.
|
|
24
|
+
// The connector executors below register their provider factories with it —
|
|
25
|
+
// without `automation` loaded they have nowhere to register and boot fails, so
|
|
26
|
+
// keep this capability whenever `plugins:` lists a connector.
|
|
27
|
+
requires: ['automation'],
|
|
28
|
+
|
|
29
|
+
// Generic connector executors (ADR-0022/0023/0024 + ADR-0097), default-present
|
|
30
|
+
// so you can add a `connectors:` entry naming `provider: 'rest' | 'openapi' |
|
|
31
|
+
// 'mcp'` and have it materialize with zero host code. Zero-arg = contribute the
|
|
32
|
+
// provider factory only. Brand connectors (Slack, …) stay marketplace/opt-in.
|
|
33
|
+
// Security (#3055): a declarative `mcp` stdio transport spawns a local process
|
|
34
|
+
// from metadata and is denied by default — opt in per host with
|
|
35
|
+
// `new ConnectorMcpPlugin({ declarativeStdio: ['<trusted-command>'] })`.
|
|
36
|
+
plugins: [
|
|
37
|
+
new ConnectorRestPlugin(),
|
|
38
|
+
new ConnectorOpenApiPlugin(),
|
|
39
|
+
new ConnectorMcpPlugin(),
|
|
40
|
+
],
|
|
41
|
+
|
|
18
42
|
objects: Object.values(objects),
|
|
19
43
|
});
|
|
@@ -11,13 +11,16 @@
|
|
|
11
11
|
"typecheck": "tsc --noEmit"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@objectstack/spec": "^
|
|
15
|
-
"@objectstack/runtime": "^
|
|
16
|
-
"@objectstack/driver-memory": "^
|
|
17
|
-
"@objectstack/plugin-hono-server": "^
|
|
14
|
+
"@objectstack/spec": "^16.0.0",
|
|
15
|
+
"@objectstack/runtime": "^16.0.0",
|
|
16
|
+
"@objectstack/driver-memory": "^16.0.0",
|
|
17
|
+
"@objectstack/plugin-hono-server": "^16.0.0",
|
|
18
|
+
"@objectstack/connector-rest": "^16.0.0",
|
|
19
|
+
"@objectstack/connector-openapi": "^16.0.0",
|
|
20
|
+
"@objectstack/connector-mcp": "^16.0.0"
|
|
18
21
|
},
|
|
19
22
|
"devDependencies": {
|
|
20
|
-
"@objectstack/cli": "^
|
|
23
|
+
"@objectstack/cli": "^16.0.0",
|
|
21
24
|
"typescript": "^6.0.0"
|
|
22
25
|
}
|
|
23
26
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# pnpm does not run dependency install scripts unless they are approved here.
|
|
2
|
+
# Without this file a fresh `pnpm install` on pnpm 11 exits 1 with
|
|
3
|
+
# ERR_PNPM_IGNORED_BUILDS — pnpm 10 only warned, pnpm 11 made it a hard error.
|
|
4
|
+
#
|
|
5
|
+
# Both keys are needed; they are read by different pnpm versions:
|
|
6
|
+
# allowBuilds pnpm >= 10.31 and pnpm 11+. pnpm 11 reads ONLY this
|
|
7
|
+
# one — onlyBuiltDependencies alone still errors.
|
|
8
|
+
# onlyBuiltDependencies pnpm 10.0–10.30, which do not understand allowBuilds.
|
|
9
|
+
#
|
|
10
|
+
# better-sqlite3 is the native sqlite driver (@objectstack/driver-sql's optional
|
|
11
|
+
# dependency); esbuild compiles objectstack.config.ts. Both ship prebuilt
|
|
12
|
+
# binaries, so an unapproved build degrades rather than breaks — but pnpm 11
|
|
13
|
+
# fails the install before it gets that far.
|
|
14
|
+
#
|
|
15
|
+
# npm and yarn ignore this file; it costs them nothing.
|
|
16
|
+
|
|
17
|
+
onlyBuiltDependencies:
|
|
18
|
+
- better-sqlite3
|
|
19
|
+
- esbuild
|
|
20
|
+
|
|
21
|
+
allowBuilds:
|
|
22
|
+
better-sqlite3: true
|
|
23
|
+
esbuild: true
|