create-objectstack 17.3.0 → 17.4.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/CHANGELOG.md CHANGED
@@ -1,5 +1,102 @@
1
1
  # create-objectstack
2
2
 
3
+ ## 17.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 4998efa: Scaffolded projects now ship a CI workflow, and a `lint` script for it to run.
8
+ The blank template carries `.github/workflows/ci.yml` — one job, on `push` and
9
+ `pull_request`: checkout, pnpm, Node 22, `pnpm install --frozen-lockfile`, then
10
+ `pnpm validate`, `pnpm lint` and `pnpm typecheck`.
11
+
12
+ `lint` is new to the template (`objectstack lint`). It is not a second spelling
13
+ of `validate`: the two share the authoring-rule engine but only `lint` runs the
14
+ hook-body lowering check, which catches handlers that have silently stopped
15
+ lowering to metadata-only bodies — a change of deployment shape produced by a
16
+ refactor that looks like tidying.
17
+
18
+ The scaffolder already created `.github/` at runtime for a single file
19
+ (`copilot-instructions.md`) while the template's gates shipped as npm scripts
20
+ nothing ever ran, so a fresh project started with no CI at all — and ObjectStack
21
+ metadata mistakes fail silently at runtime, which makes `objectstack validate`
22
+ the only place they surface early. That gate is now unskippable for a human and
23
+ for an AI agent authoring metadata in the project, instead of advisory.
24
+
25
+ Existing projects are unaffected; copy the file from a fresh scaffold to adopt
26
+ it.
27
+ - 813d6c5: `npx create-objectstack` now declares the same TypeScript range as `os init` and
28
+ `os create`, and the value is generated rather than restated.
29
+
30
+ Three scaffolders write a new project's `package.json`, and the range that
31
+ decides whether that project type-checks at all had split: `os init` and
32
+ `os create` emitted `typescript: ^5.3.0` from a shared emission policy, while
33
+ this package's bundled template carried `^6.0.0`. Two projects created the same
34
+ day got different TypeScript **majors** depending on which documented entry
35
+ point the reader followed.
36
+
37
+ - **What changed for a scaffolded project.** Its declared `typescript`
38
+ devDependency floor moves from `^6.0.0` to `^5.3.0`. Both resolve to the same
39
+ installed compiler on a fresh install; what moves is the floor the project
40
+ **declares**, and a floor is a support promise. `^5.3.0` is the promise the
41
+ docs already make — "ObjectStack works with TypeScript 5.3+" on the getting
42
+ started page, "TypeScript 5.3.0 or later" in the deployment troubleshooting
43
+ page — and it is measured rather than assumed: TypeScript 5.3.3 type-checks
44
+ every shape these scaffolders emit with results identical to 6.0.3. The repo's
45
+ own `typescript@^6.0.3` devDependency is deliberately not this value; the same
46
+ doc sentence states both halves ("…but the project itself is built and tested
47
+ against TypeScript 6.x"). `engines.pnpm` was already in agreement and is now
48
+ held there by the same mechanism.
49
+ - **Why the value is generated.** This package cannot import from
50
+ `@objectstack/cli`: the dependency edge runs the other way, and the `npx`
51
+ package must not pull the CLI's package closure. So the values are stamped
52
+ into the bundled template at build time by
53
+ `scripts/sync-scaffold-emission-policy.mjs`, read out of the same
54
+ `SCAFFOLD_*` constants the other two scaffolders import, and
55
+ `pnpm check:scaffold-emission-policy` reddens the moment the inlined values
56
+ disagree with that source. Editing the two into agreement by hand would have
57
+ left them free to diverge again on the next move, silently, for the same
58
+ structural reason — which is how they diverged the first time.
59
+ - fd75728: Scaffolded projects now install the AI skills bundle for **one** agent runtime
60
+ instead of every runtime the skills CLI knows, so the bundle is committed once.
61
+
62
+ **Route B of the two the card offered was taken**, and the choice was measured
63
+ rather than argued. Against `skills@1.5.23` and the 11-skill catalog, the old
64
+ `--all` (shorthand for `--skill '*' --agent '*' -y`) wrote the same bundle to
65
+ three destinations — `.agents/` (46 real files, 604,102 B), `agent/` (46 real
66
+ files, 602,682 B, identical bodies with re-serialised frontmatter) and
67
+ `.claude/` (11 symlinks into `.agents/`). The template's `.gitignore` excluded
68
+ none of it, so a new project's first `git add -A` staged 22 `SKILL.md` paths
69
+ plus 11 symlinks. That reached the initial commit of a real app before anyone
70
+ noticed.
71
+
72
+ The scaffolder now runs
73
+ `npx skills add objectstack-ai/objectstack/skills --skill '*' --agent claude-code -y`,
74
+ which writes 46 real files to `.claude/skills/` and nothing else: 11 staged
75
+ `SKILL.md` paths, no symlinks, and a clone of that commit has readable skill
76
+ files on every platform.
77
+
78
+ Route A (keep `--all`, exclude the duplicates in the template `_gitignore`) was
79
+ built and cloned, not reasoned about, and both of its shapes were rejected.
80
+ Ignoring `.agents/` and `agent/` while committing `.claude/` gives a fresh
81
+ cloner 11 dangling symlinks and zero readable `SKILL.md`. Ignoring only
82
+ `agent/` works on POSIX but commits 11 symlinks that a `core.symlinks=false`
83
+ clone — git-for-Windows' default — materialises as ordinary files whose whole
84
+ content is the link target. `--all --copy`, the other way to make `.claude/`
85
+ real, fans out to 56 destination directories totalling 33.8 MB. A denylist is
86
+ also the wrong shape regardless of which paths it names: this package does not
87
+ choose the destination set, the skills CLI does, and it moves with that
88
+ package's releases.
89
+
90
+ The cost is the multi-runtime default, and it is paid in the open: the closing
91
+ summary now always prints an **AI Skills** block naming where the bundle landed
92
+ and the one-line command for any other runtime, one agent at a time. The
93
+ bundle is identical whichever agent is named.
94
+
95
+ Existing projects are unaffected. To shrink one that already carries the
96
+ triplicate, delete `.agents/` and `agent/` and re-run the single-agent command
97
+ above; `skills-lock.json` records source and hash, not paths, so it does not
98
+ change.
99
+
3
100
  ## 17.3.0
4
101
 
5
102
  ### Minor Changes
package/README.md CHANGED
@@ -56,9 +56,12 @@ you so rather than failing as an unknown template.
56
56
  every object name in the template is re-prefixed to match
57
57
  (`blank_note` → `my_app_note`).
58
58
  2. Installs dependencies (pnpm if available, otherwise npm).
59
- 3. Installs the ObjectStack AI skills bundle for coding agents
60
- (`npx skills add objectstack-ai/objectstack/skills --all` scoped to the
61
- curated `skills/` catalog).
59
+ 3. Installs the ObjectStack AI skills bundle for **one** coding agent —
60
+ `npx skills add objectstack-ai/objectstack/skills --skill '*' --agent claude-code -y`,
61
+ scoped to the curated `skills/` catalog. One agent, not `--all`, so the
62
+ bundle lands in exactly one directory (`.claude/skills/`) and a scaffolded
63
+ project commits it once; `src/skills-install.ts` carries the measurement.
64
+ The closing summary prints the same command for any other runtime.
62
65
  4. Writes `AGENTS.md` and `.github/copilot-instructions.md` with the project
63
66
  conventions — unless the template ships its own.
64
67
 
package/dist/index.js CHANGED
@@ -245,6 +245,19 @@ function pinRuntimeImage(targetDir, version) {
245
245
  return { pinned: true, tag: version };
246
246
  }
247
247
 
248
+ // src/skills-install.ts
249
+ var SKILLS_CATALOG = "objectstack-ai/objectstack/skills";
250
+ var DEFAULT_SKILLS_AGENT = "claude-code";
251
+ var DEFAULT_SKILLS_DIR = ".claude/skills/";
252
+ var EXAMPLE_OTHER_AGENT = "codex";
253
+ function skillsAddArgs(agent) {
254
+ return `skills add ${SKILLS_CATALOG} --skill '*' --agent ${agent} -y`;
255
+ }
256
+ var SKILLS_INSTALL_COMMAND = `npx -y ${skillsAddArgs(DEFAULT_SKILLS_AGENT)}`;
257
+ function skillsInstallHint(agent) {
258
+ return `npx ${skillsAddArgs(agent)}`;
259
+ }
260
+
248
261
  // src/banner.ts
249
262
  import chalk from "chalk";
250
263
  var PREFIX = " \u25C6 Create ObjectStack ";
@@ -526,17 +539,20 @@ var program = new Command().name("create-objectstack").description("Create a new
526
539
  }
527
540
  }
528
541
  const beforeSkills = topLevelNames(targetDir);
542
+ let skillsInstalled = false;
529
543
  if (!options.skipInstall && !options.skipSkills) {
530
544
  printStep("Installing AI skills for your coding agent...");
531
545
  try {
532
- execSync2("npx -y skills add objectstack-ai/objectstack/skills --all", {
546
+ execSync2(SKILLS_INSTALL_COMMAND, {
533
547
  stdio: "inherit",
534
548
  cwd: targetDir
535
549
  });
550
+ skillsInstalled = true;
536
551
  console.log("");
537
552
  } catch {
538
553
  printWarning(
539
- "Skills installation skipped. Run manually:\n npx skills add objectstack-ai/objectstack/skills"
554
+ `Skills installation skipped. Run manually:
555
+ ${skillsInstallHint(DEFAULT_SKILLS_AGENT)}`
540
556
  );
541
557
  console.log("");
542
558
  }
@@ -560,10 +576,23 @@ var program = new Command().name("create-objectstack").description("Create a new
560
576
  console.log(chalk2.dim(` ${devLabel.padEnd(labelWidth)}# Start development server`));
561
577
  console.log(chalk2.dim(` ${validateLabel.padEnd(labelWidth)}# Verify metadata: schema + predicates + bindings`));
562
578
  console.log(chalk2.dim(` ${" ".repeat(labelWidth)}# (run after every metadata edit \u2014 see AGENTS.md)`));
563
- if (options.skipInstall || options.skipSkills) {
564
- console.log("");
579
+ console.log("");
580
+ if (skillsInstalled) {
581
+ console.log(chalk2.bold(" AI Skills:"));
582
+ console.log(
583
+ chalk2.dim(
584
+ ` Installed for ${DEFAULT_SKILLS_AGENT} \u2192 ${DEFAULT_SKILLS_DIR} \u2014 commit it with your project.`
585
+ )
586
+ );
587
+ console.log(chalk2.dim(" Using a different agent? Add it one runtime at a time:"));
588
+ console.log(chalk2.dim(` ${skillsInstallHint(EXAMPLE_OTHER_AGENT)}`));
589
+ console.log(chalk2.dim(" (`npx skills add --help` lists every agent name)"));
590
+ } else {
565
591
  console.log(chalk2.bold(" AI Skills (recommended):"));
566
- console.log(chalk2.dim(" npx skills add objectstack-ai/objectstack/skills"));
592
+ console.log(chalk2.dim(` ${skillsInstallHint(DEFAULT_SKILLS_AGENT)}`));
593
+ console.log(
594
+ chalk2.dim(` Replace \`${DEFAULT_SKILLS_AGENT}\` with your own agent runtime if it differs.`)
595
+ );
567
596
  }
568
597
  console.log("");
569
598
  } catch (error) {
@@ -73,13 +73,19 @@ Run `npm run build` when you need the compiled `dist/objectstack.json` artifact.
73
73
 
74
74
  ## AI Skills
75
75
 
76
- This project uses ObjectStack skills from `objectstack-ai/objectstack`.
77
- Install or update skills with the standard [skills CLI](https://skills.sh/):
76
+ This project uses ObjectStack skills from `objectstack-ai/objectstack`. They
77
+ were installed for one agent runtime, live in `.claude/skills/`, and are
78
+ committed with the project. Install or update them with the standard
79
+ [skills CLI](https://skills.sh/), naming your runtime:
78
80
 
79
81
  ```bash
80
- npx skills add objectstack-ai/objectstack/skills
82
+ npx skills add objectstack-ai/objectstack/skills --skill '*' --agent claude-code -y
81
83
  ```
82
84
 
85
+ Adding a second runtime? Re-run it with that runtime's `--agent` name.
86
+ ⛔ Do not use `--all`: it writes the same bundle to `.agents/`, `agent/` and
87
+ `.claude/` at once, and all three then land in your next commit.
88
+
83
89
  Skills are triggered automatically based on task context:
84
90
 
85
91
  | Skill | Trigger Context |
@@ -0,0 +1,67 @@
1
+ # Continuous integration for this ObjectStack app.
2
+ #
3
+ # ObjectStack metadata fails SILENTLY at runtime, not at edit time: a mistyped
4
+ # permission grant or a bare field name in an action predicate raises nothing,
5
+ # it just behaves wrongly for whoever hits it first. `objectstack validate` is
6
+ # where that class surfaces — and running it is something a human, or an AI
7
+ # agent authoring metadata in this project, has to remember. This workflow is
8
+ # what makes it unskippable. AGENTS.md carries the authoring conventions it
9
+ # enforces.
10
+ #
11
+ # One job, one file: a starting point, not a CI framework. Grow it with the
12
+ # project — add a step when you add a script, a second job when you deploy.
13
+
14
+ name: CI
15
+
16
+ on: [push, pull_request]
17
+
18
+ # Read-only. Nothing here writes to the repository or publishes anything.
19
+ permissions:
20
+ contents: read
21
+
22
+ jobs:
23
+ verify:
24
+ name: Validate
25
+ runs-on: ubuntu-latest
26
+ timeout-minutes: 15
27
+ steps:
28
+ - uses: actions/checkout@v7
29
+
30
+ # pnpm BEFORE setup-node, deliberately. `cache: pnpm` below makes
31
+ # setup-node shell out to pnpm to locate the store, so pnpm has to be on
32
+ # PATH by then. Reversed, this does not degrade — the job dies in the
33
+ # setup step with "Unable to locate executable file: pnpm".
34
+ #
35
+ # `version` is explicit because this project declares no `packageManager`
36
+ # field — pinning one would make the project pnpm-only, and a
37
+ # corepack-driven npm or yarn then refuses to run in it — so
38
+ # pnpm/action-setup has nothing to resolve from. Keep this in step with
39
+ # the `engines.pnpm` floor in package.json.
40
+ - uses: pnpm/action-setup@v6
41
+ with:
42
+ version: 10
43
+
44
+ - uses: actions/setup-node@v7
45
+ with:
46
+ node-version: '22'
47
+ cache: pnpm
48
+
49
+ # `--frozen-lockfile` installs exactly what the lockfile records and fails
50
+ # when the two disagree, so `pnpm-lock.yaml` has to be committed.
51
+ # Scaffolding wrote it for you unless you passed `--skip-install`; in that
52
+ # case run `pnpm install` once and commit the result.
53
+ - run: pnpm install --frozen-lockfile
54
+
55
+ # The gate this file exists for: schema, CEL predicates and widget
56
+ # bindings. The same checks `pnpm build` runs, without producing an
57
+ # artifact.
58
+ - run: pnpm validate
59
+
60
+ # Not a second spelling of `validate`. The two share the authoring-rule
61
+ # engine but not the rule set — the hook-body lowering check, which
62
+ # catches handlers that silently stop lowering to metadata-only bodies
63
+ # (a change of deployment shape, from a refactor that looks like
64
+ # tidying), runs here and nowhere else.
65
+ - run: pnpm lint
66
+
67
+ - run: pnpm typecheck
@@ -100,6 +100,8 @@ After editing any metadata, run:
100
100
 
101
101
  ```bash
102
102
  pnpm validate # schema + CEL predicates + widget bindings (no artifact)
103
+ pnpm lint # authoring rules validate does not run — e.g. a handler that
104
+ # stopped lowering to a metadata-only body
103
105
  pnpm typecheck # TypeScript types against @objectstack/spec
104
106
  ```
105
107
 
@@ -138,5 +140,10 @@ covered in [Self-Hosted Deployment](https://objectstack.ai/docs/deployment/self-
138
140
  - Add a flow or automation: see `objectstack-automation`.
139
141
  - Add an AI agent: see `objectstack-ai`.
140
142
 
141
- Skills are installed with `npx skills add objectstack-ai/objectstack/skills`
142
- (see `AGENTS.md`) and also show up in the in-IDE assistant catalog.
143
+ Skills live in `.claude/skills/` and are committed with this project, once.
144
+ They are installed one agent runtime at a time (see `AGENTS.md`), and also show
145
+ up in the in-IDE assistant catalog:
146
+
147
+ ```bash
148
+ npx skills add objectstack-ai/objectstack/skills --skill '*' --agent claude-code -y
149
+ ```
@@ -11,6 +11,7 @@
11
11
  "start": "objectstack start",
12
12
  "build": "objectstack build",
13
13
  "validate": "objectstack validate",
14
+ "lint": "objectstack lint",
14
15
  "typecheck": "tsc --noEmit"
15
16
  },
16
17
  "dependencies": {
@@ -23,6 +24,6 @@
23
24
  },
24
25
  "devDependencies": {
25
26
  "@objectstack/cli": "^17.0.0",
26
- "typescript": "^6.0.0"
27
+ "typescript": "^5.3.0"
27
28
  }
28
29
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-objectstack",
3
- "version": "17.3.0",
3
+ "version": "17.4.0",
4
4
  "description": "Create a new ObjectStack project — npx create-objectstack",
5
5
  "bin": {
6
6
  "create-objectstack": "./bin/create-objectstack.js"
@@ -28,7 +28,8 @@
28
28
  "@types/node": "^26.2.0",
29
29
  "tsup": "^8.5.1",
30
30
  "typescript": "^6.0.3",
31
- "vitest": "^4.1.10"
31
+ "vitest": "^4.1.10",
32
+ "yaml": "^2.9.0"
32
33
  },
33
34
  "repository": {
34
35
  "type": "git",
@@ -49,7 +50,7 @@
49
50
  "node": ">=22.0.0"
50
51
  },
51
52
  "scripts": {
52
- "build": "tsup && node ../../scripts/check-dts-emitted.mjs",
53
+ "build": "node ../../scripts/sync-scaffold-emission-policy.mjs && tsup && node ../../scripts/check-dts-emitted.mjs",
53
54
  "typecheck": "tsc --noEmit",
54
55
  "dev": "tsup --watch",
55
56
  "test": "vitest run"