@joystack/cli 0.1.43 → 0.1.44
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 +11 -0
- package/lib/create.mjs +2 -0
- package/lib/legacy-names.mjs +29 -0
- package/lib/update.mjs +19 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -14,6 +14,14 @@ Versions: [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
14
14
|
|
|
15
15
|
## [Unreleased]
|
|
16
16
|
|
|
17
|
+
## [0.1.44] - 2026-10-09
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- When `joystack update` moves a game made before the rename, it ends with a
|
|
22
|
+
short checklist for your agent: the links, tests and publishing tokens in
|
|
23
|
+
your game's own files that the update cannot move itself.
|
|
24
|
+
|
|
17
25
|
### Removed
|
|
18
26
|
|
|
19
27
|
- `joystack dev` no longer starts a services proxy on port 8788. Nothing in the
|
|
@@ -22,6 +30,9 @@ Versions: [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
22
30
|
|
|
23
31
|
### Changed
|
|
24
32
|
|
|
33
|
+
- `joystack create` marks the new game as ES modules (`"type": "module"` in
|
|
34
|
+
package.json), so `joystack publish` no longer prints Node's
|
|
35
|
+
`MODULE_TYPELESS_PACKAGE_JSON` warning.
|
|
25
36
|
- **The CLI is `@joystack/cli`, and its command is `joystack`** (`npx joystack
|
|
26
37
|
dev`, `npx joystack test`, `npx joystack publish`, …). Nothing in your game has
|
|
27
38
|
to change: the previous command name runs the same CLI, so the scripts in your
|
package/lib/create.mjs
CHANGED
|
@@ -112,6 +112,8 @@ async function scaffold({ dir, name, install, cliSpec, apiBase, log, ensure, rec
|
|
|
112
112
|
{
|
|
113
113
|
name,
|
|
114
114
|
private: true,
|
|
115
|
+
// Every file a game is made of is an ES module.
|
|
116
|
+
type: 'module',
|
|
115
117
|
description: `A Joystack game. Play at https://${name}.joystack.games/`,
|
|
116
118
|
// The scaffold is a framework-v2 game (entities + traits + a world root,
|
|
117
119
|
// lowered to the engine runtime on this machine). This flag is what makes
|
package/lib/legacy-names.mjs
CHANGED
|
@@ -244,3 +244,32 @@ export const LEGACY_MANAGED_MARKERS = Object.freeze({
|
|
|
244
244
|
start: `<!-- ${OLD}:managed:start -->`,
|
|
245
245
|
end: `<!-- ${OLD}:managed:end -->`,
|
|
246
246
|
});
|
|
247
|
+
|
|
248
|
+
// Whether this update moved a game made under the old name: the CLI dependency
|
|
249
|
+
// was switched over, or the old update skill was retired. `cli` and `surface`
|
|
250
|
+
// are what update.mjs got from syncCli and the agent-surface reconcile.
|
|
251
|
+
export function movedFromLegacy(cli, surface) {
|
|
252
|
+
return Boolean(cli?.switched) || (surface?.removed ?? []).some((f) => /(^|\/)skills\/update-looop(\/|$)/.test(f));
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// What `joystack update` prints after such a move, once. It is addressed to
|
|
256
|
+
// the creator's agent, which reads the update's output: the update moved what
|
|
257
|
+
// is Joystack's, and these are what the game itself may still say about Looop.
|
|
258
|
+
export const MOVED_FROM_LEGACY_NOTE = [
|
|
259
|
+
'This game just moved from Looop to Joystack. The update moved what is',
|
|
260
|
+
"Joystack's; check the game's own files for what it could not move, and",
|
|
261
|
+
'fix what you find before calling the update done:',
|
|
262
|
+
' • Links to play.looop.games/g/<slug>: the game lives at',
|
|
263
|
+
' https://<slug>.joystack.games/ from its first `npx joystack publish`.',
|
|
264
|
+
' The Looop copy stays as it was.',
|
|
265
|
+
' • Tests or scripts matching `[looop]`, `looop:` keys or `.looop/`: the',
|
|
266
|
+
' engine now writes `[joystack]`, `joystack:` and `.joystack/`.',
|
|
267
|
+
' • Automation that publishes (GitHub Actions, scripts) with a Looop token:',
|
|
268
|
+
' Joystack does not accept it. Make one for the job by signing in with an',
|
|
269
|
+
' empty folder (mktemp -d) as the home: `JOYSTACK_HOME=<folder> npx joystack login`.',
|
|
270
|
+
' With the creator\'s OK, store it without ever displaying it:',
|
|
271
|
+
' node -e "process.stdout.write(require(\'<folder>/config.json\').token)" | gh secret set <NAME>',
|
|
272
|
+
' Without gh, pipe the same into pbcopy (Mac) and walk them through',
|
|
273
|
+
' GitHub → Settings → Secrets and variables → Actions → <NAME> → Update.',
|
|
274
|
+
' Then delete the folder.',
|
|
275
|
+
];
|
package/lib/update.mjs
CHANGED
|
@@ -16,6 +16,7 @@ import { login } from './login.mjs';
|
|
|
16
16
|
import { compareVersions, renderReleases } from './changelog.mjs';
|
|
17
17
|
import { syncCli, reportCli } from './self-update.mjs';
|
|
18
18
|
import { fetchStatus, landedIn } from './feedback-sync.mjs';
|
|
19
|
+
import { MOVED_FROM_LEGACY_NOTE, movedFromLegacy } from './legacy-names.mjs';
|
|
19
20
|
|
|
20
21
|
// The report is the point. A creator reading this must be able to answer, with
|
|
21
22
|
// no further digging: what changed, was any of it mine, and what do I do now.
|
|
@@ -69,6 +70,20 @@ function report(log, engineVersion, surface) {
|
|
|
69
70
|
log(" changes you didn't make. Review them and save them with your next commit.");
|
|
70
71
|
}
|
|
71
72
|
|
|
73
|
+
// A game made before the rename moves over in this update. What is Joystack's
|
|
74
|
+
// has moved; what the game itself says (its links, its tests, a token its
|
|
75
|
+
// automation publishes with) has not, and the note lists it for the agent
|
|
76
|
+
// reading this output. Neither condition holds on a later update, so it is
|
|
77
|
+
// printed this once only.
|
|
78
|
+
function noteMove(log, cli, surface) {
|
|
79
|
+
const moved = movedFromLegacy(cli, surface);
|
|
80
|
+
if (moved) {
|
|
81
|
+
log('');
|
|
82
|
+
for (const line of MOVED_FROM_LEGACY_NOTE) log(` ${line}`);
|
|
83
|
+
}
|
|
84
|
+
return moved;
|
|
85
|
+
}
|
|
86
|
+
|
|
72
87
|
export async function update({
|
|
73
88
|
cwd = process.cwd(),
|
|
74
89
|
apiBase = getApiBase(DEFAULT_API_BASE),
|
|
@@ -146,7 +161,8 @@ export async function update({
|
|
|
146
161
|
log(' This is a pre-release candidate — its changelog and any migration');
|
|
147
162
|
log(' notes ship inside the engine (read the handbook / engine docs), not');
|
|
148
163
|
log(' via `joystack changelog`. Republish (`npx joystack publish`) when ready.');
|
|
149
|
-
|
|
164
|
+
const movedIn = noteMove(log, cli, surface);
|
|
165
|
+
return { from, to: engine.version, updated: from !== engine.version, surface, crossed: null, cli, candidate: true, movedIn };
|
|
150
166
|
}
|
|
151
167
|
|
|
152
168
|
const res = await fetchImpl(`${apiBase}/api/creator/engine`, {
|
|
@@ -295,5 +311,6 @@ export async function update({
|
|
|
295
311
|
log('');
|
|
296
312
|
log(' Republish (`npx joystack publish`) when you want the live game on it.');
|
|
297
313
|
}
|
|
298
|
-
|
|
314
|
+
const movedIn = noteMove(log, cli, surface);
|
|
315
|
+
return { from, to: latest, updated, surface, crossed, cli, landed, movedIn };
|
|
299
316
|
}
|
package/package.json
CHANGED