@volter/world 3.0.146 → 3.0.148
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/dist/examples/customer-onboarding/README.md +1 -1
- package/dist/examples/customer-onboarding/package.json +4 -4
- package/dist/examples/integration-branches/README.md +4 -4
- package/dist/examples/integration-branches/package.json +4 -4
- package/dist/examples/workplace-agent/README.md +1 -1
- package/dist/examples/workplace-agent/package.json +4 -4
- package/dist/src/world.d.ts +2 -0
- package/dist/src/world.js +38 -9
- package/examples/customer-onboarding/README.md +1 -1
- package/examples/customer-onboarding/package.json +4 -4
- package/examples/integration-branches/README.md +4 -4
- package/examples/integration-branches/package.json +4 -4
- package/examples/workplace-agent/README.md +1 -1
- package/examples/workplace-agent/package.json +4 -4
- package/package.json +5 -5
- package/src/world.ts +28 -5
|
@@ -13,7 +13,7 @@ You need Node 22.6+, npm and registry access during installation. The browser pa
|
|
|
13
13
|
Copy this starter into a new folder:
|
|
14
14
|
|
|
15
15
|
```console
|
|
16
|
-
$ npx @volter/world@3.0.
|
|
16
|
+
$ npx @volter/world@3.0.148 example customer-onboarding --dir onboarding
|
|
17
17
|
$ cd onboarding
|
|
18
18
|
$ npm install
|
|
19
19
|
```
|
|
@@ -11,10 +11,10 @@
|
|
|
11
11
|
"pg": "8.16.3"
|
|
12
12
|
},
|
|
13
13
|
"devDependencies": {
|
|
14
|
-
"@volter/world": "3.0.
|
|
15
|
-
"@volter/world-core": "3.0.
|
|
16
|
-
"@volter/world-runtime": "3.0.
|
|
17
|
-
"@volter/world-console": "3.0.
|
|
14
|
+
"@volter/world": "3.0.148",
|
|
15
|
+
"@volter/world-core": "3.0.147",
|
|
16
|
+
"@volter/world-runtime": "3.0.147",
|
|
17
|
+
"@volter/world-console": "3.0.142",
|
|
18
18
|
"@volter/twin-stripe": "3.0.2",
|
|
19
19
|
"@volter/twin-resend": "1.0.1"
|
|
20
20
|
}
|
|
@@ -13,7 +13,7 @@ Give two workers the same Stripe baseline, let them change different existing cu
|
|
|
13
13
|
Use an empty parent folder. Create the baseline starter there:
|
|
14
14
|
|
|
15
15
|
```console
|
|
16
|
-
$ npx @volter/world@3.0.
|
|
16
|
+
$ npx @volter/world@3.0.148 example integration-branches --dir baseline
|
|
17
17
|
$ cd baseline
|
|
18
18
|
$ npm install
|
|
19
19
|
$ ./node_modules/.bin/volter world init --name baseline --twins stripe
|
|
@@ -38,9 +38,9 @@ The stopped baseline retains its history and can supply local path remotes. Defa
|
|
|
38
38
|
Create three more copies in the same parent folder:
|
|
39
39
|
|
|
40
40
|
```console
|
|
41
|
-
$ npx @volter/world@3.0.
|
|
42
|
-
$ npx @volter/world@3.0.
|
|
43
|
-
$ npx @volter/world@3.0.
|
|
41
|
+
$ npx @volter/world@3.0.148 example integration-branches --dir integration
|
|
42
|
+
$ npx @volter/world@3.0.148 example integration-branches --dir worker-a
|
|
43
|
+
$ npx @volter/world@3.0.148 example integration-branches --dir worker-b
|
|
44
44
|
```
|
|
45
45
|
|
|
46
46
|
In `integration`, then `worker-a`, then `worker-b`, install dependencies and initialize with the folder's name. Before a first boot or app write, link and pull the baseline:
|
|
@@ -9,10 +9,10 @@
|
|
|
9
9
|
"stripe": "17.7.0"
|
|
10
10
|
},
|
|
11
11
|
"devDependencies": {
|
|
12
|
-
"@volter/world": "3.0.
|
|
13
|
-
"@volter/world-core": "3.0.
|
|
14
|
-
"@volter/world-runtime": "3.0.
|
|
15
|
-
"@volter/world-console": "3.0.
|
|
12
|
+
"@volter/world": "3.0.148",
|
|
13
|
+
"@volter/world-core": "3.0.147",
|
|
14
|
+
"@volter/world-runtime": "3.0.147",
|
|
15
|
+
"@volter/world-console": "3.0.142",
|
|
16
16
|
"@volter/twin-stripe": "3.0.2"
|
|
17
17
|
}
|
|
18
18
|
}
|
|
@@ -13,7 +13,7 @@ You need Node 22.6+, npm and registry access during installation. No platform ac
|
|
|
13
13
|
## Prepare an ordinary workplace
|
|
14
14
|
|
|
15
15
|
```console
|
|
16
|
-
$ npx @volter/world@3.0.
|
|
16
|
+
$ npx @volter/world@3.0.148 example workplace-agent --dir workplace
|
|
17
17
|
$ cd workplace
|
|
18
18
|
$ npm install
|
|
19
19
|
$ ./node_modules/.bin/volter world init --name workplace --twins github,linear,slack
|
|
@@ -11,10 +11,10 @@
|
|
|
11
11
|
"@slack/web-api": "7.19.0"
|
|
12
12
|
},
|
|
13
13
|
"devDependencies": {
|
|
14
|
-
"@volter/world": "3.0.
|
|
15
|
-
"@volter/world-core": "3.0.
|
|
16
|
-
"@volter/world-runtime": "3.0.
|
|
17
|
-
"@volter/world-console": "3.0.
|
|
14
|
+
"@volter/world": "3.0.148",
|
|
15
|
+
"@volter/world-core": "3.0.147",
|
|
16
|
+
"@volter/world-runtime": "3.0.147",
|
|
17
|
+
"@volter/world-console": "3.0.142",
|
|
18
18
|
"@volter/twin-github": "3.0.6",
|
|
19
19
|
"@volter/twin-linear": "3.0.4",
|
|
20
20
|
"@volter/twin-slack": "3.0.5"
|
package/dist/src/world.d.ts
CHANGED
|
@@ -105,6 +105,8 @@ export declare class World {
|
|
|
105
105
|
seed?: boolean;
|
|
106
106
|
cwd?: string;
|
|
107
107
|
}): Promise<WorldInstance>;
|
|
108
|
+
/** Product startup completes its seed sequence; the runtime owns only the boot. */
|
|
109
|
+
private finishStartup;
|
|
108
110
|
/** Stop the twins; the branch's state stays (`up` resumes). `purge` forgets it. */
|
|
109
111
|
down(opts?: {
|
|
110
112
|
purge?: boolean;
|
package/dist/src/world.js
CHANGED
|
@@ -125,12 +125,17 @@ export class World {
|
|
|
125
125
|
...(opts.mode ? { mode: opts.mode } : existing ? { mode: existing.mode } : {}),
|
|
126
126
|
...(existing ? { keepState: true } : {}),
|
|
127
127
|
});
|
|
128
|
+
await this.finishStartup(instance, existing === null, opts);
|
|
129
|
+
return instance;
|
|
130
|
+
}
|
|
131
|
+
/** Product startup completes its seed sequence; the runtime owns only the boot. */
|
|
132
|
+
async finishStartup(instance, fresh, opts = {}) {
|
|
128
133
|
try {
|
|
129
|
-
if (
|
|
134
|
+
if (fresh && opts.seed !== false && existsSync(worldSeedPath(this.root))) {
|
|
130
135
|
// a story that fails is a loud failure: the world is up, but not the world the app expects
|
|
131
136
|
const seeded = await seedWorld(this.name, { root: this.root, cwd: opts.cwd ?? this.root });
|
|
132
137
|
if (seeded.exitCode !== 0)
|
|
133
|
-
throw new Error(`the story failed (${seeded.entry} exited ${seeded.exitCode});
|
|
138
|
+
throw new Error(`the story failed (${seeded.entry} exited ${seeded.exitCode}); state may be partially seeded — fix the seed, start this World and run \`volter world seed\``);
|
|
134
139
|
}
|
|
135
140
|
}
|
|
136
141
|
finally {
|
|
@@ -138,7 +143,6 @@ export class World {
|
|
|
138
143
|
// fresh boot runs simulated), where the deploy reads it — also when the seed failed
|
|
139
144
|
materializeRoots(loadWorldConfig(this.configRef(), this.root).config, instance.dirs.data, this.root);
|
|
140
145
|
}
|
|
141
|
-
return instance;
|
|
142
146
|
}
|
|
143
147
|
/** Stop the twins; the branch's state stays (`up` resumes). `purge` forgets it. */
|
|
144
148
|
down(opts = {}) { return downWorld(this.name, this.root, opts); }
|
|
@@ -150,12 +154,9 @@ export class World {
|
|
|
150
154
|
shell() { return shellWorld(this.name, this.root); }
|
|
151
155
|
/** The kernel's instance record, or null before the first `up`. */
|
|
152
156
|
instance() {
|
|
153
|
-
|
|
154
|
-
return statusWorld(this.name, this.root);
|
|
155
|
-
}
|
|
156
|
-
catch {
|
|
157
|
+
if (!existsSync(join(instanceDir(this.root, this.name), 'instance.json')))
|
|
157
158
|
return null;
|
|
158
|
-
|
|
159
|
+
return statusWorld(this.name, this.root);
|
|
159
160
|
}
|
|
160
161
|
/** The world, the branch, the origin, what is unpushed, what is running. */
|
|
161
162
|
status() {
|
|
@@ -379,7 +380,35 @@ export class World {
|
|
|
379
380
|
/** Serve this world on a port under `/<org>/<world>/`; returns when listening. */
|
|
380
381
|
serve(opts = {}) { return serveWorld(this.name, { root: this.root, ...opts }); }
|
|
381
382
|
/** `volter world view`: this World, its twins' screens, its branches and the console on one origin (docs/contributing/architecture.md, "Viewing a World"). */
|
|
382
|
-
view(opts = {}) {
|
|
383
|
+
async view(opts = {}) {
|
|
384
|
+
const fresh = this.instance() === null;
|
|
385
|
+
const person = platformPerson();
|
|
386
|
+
const announced = [];
|
|
387
|
+
let ready = false;
|
|
388
|
+
const view = await serveWorldView(this.name, { root: this.root, ...(person ? { localPerson: person } : {}), ...opts, announce: line => { if (ready)
|
|
389
|
+
opts.announce?.(line);
|
|
390
|
+
else
|
|
391
|
+
announced.push(line); } });
|
|
392
|
+
try {
|
|
393
|
+
const instance = this.instance();
|
|
394
|
+
if (!instance)
|
|
395
|
+
throw new Error('the viewer started without a recorded World instance');
|
|
396
|
+
await this.finishStartup(instance, fresh);
|
|
397
|
+
for (const line of announced)
|
|
398
|
+
opts.announce?.(line);
|
|
399
|
+
ready = true;
|
|
400
|
+
return view;
|
|
401
|
+
}
|
|
402
|
+
catch (error) {
|
|
403
|
+
try {
|
|
404
|
+
await view.stop();
|
|
405
|
+
}
|
|
406
|
+
catch (stopError) {
|
|
407
|
+
throw new AggregateError([error, stopError], 'World viewer startup failed and teardown was not confirmed; retained lifecycle evidence needs inspection');
|
|
408
|
+
}
|
|
409
|
+
throw error;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
383
412
|
// ── remotes ─────────────────────────────────────────────────────────────────────────────
|
|
384
413
|
/** The vendors this world has a twin of, as world.json names them (a twin service's package, else its id). */
|
|
385
414
|
vendors() {
|
|
@@ -13,7 +13,7 @@ You need Node 22.6+, npm and registry access during installation. The browser pa
|
|
|
13
13
|
Copy this starter into a new folder:
|
|
14
14
|
|
|
15
15
|
```console
|
|
16
|
-
$ npx @volter/world@3.0.
|
|
16
|
+
$ npx @volter/world@3.0.148 example customer-onboarding --dir onboarding
|
|
17
17
|
$ cd onboarding
|
|
18
18
|
$ npm install
|
|
19
19
|
```
|
|
@@ -11,10 +11,10 @@
|
|
|
11
11
|
"pg": "8.16.3"
|
|
12
12
|
},
|
|
13
13
|
"devDependencies": {
|
|
14
|
-
"@volter/world": "3.0.
|
|
15
|
-
"@volter/world-core": "3.0.
|
|
16
|
-
"@volter/world-runtime": "3.0.
|
|
17
|
-
"@volter/world-console": "3.0.
|
|
14
|
+
"@volter/world": "3.0.148",
|
|
15
|
+
"@volter/world-core": "3.0.147",
|
|
16
|
+
"@volter/world-runtime": "3.0.147",
|
|
17
|
+
"@volter/world-console": "3.0.142",
|
|
18
18
|
"@volter/twin-stripe": "3.0.2",
|
|
19
19
|
"@volter/twin-resend": "1.0.1"
|
|
20
20
|
}
|
|
@@ -13,7 +13,7 @@ Give two workers the same Stripe baseline, let them change different existing cu
|
|
|
13
13
|
Use an empty parent folder. Create the baseline starter there:
|
|
14
14
|
|
|
15
15
|
```console
|
|
16
|
-
$ npx @volter/world@3.0.
|
|
16
|
+
$ npx @volter/world@3.0.148 example integration-branches --dir baseline
|
|
17
17
|
$ cd baseline
|
|
18
18
|
$ npm install
|
|
19
19
|
$ ./node_modules/.bin/volter world init --name baseline --twins stripe
|
|
@@ -38,9 +38,9 @@ The stopped baseline retains its history and can supply local path remotes. Defa
|
|
|
38
38
|
Create three more copies in the same parent folder:
|
|
39
39
|
|
|
40
40
|
```console
|
|
41
|
-
$ npx @volter/world@3.0.
|
|
42
|
-
$ npx @volter/world@3.0.
|
|
43
|
-
$ npx @volter/world@3.0.
|
|
41
|
+
$ npx @volter/world@3.0.148 example integration-branches --dir integration
|
|
42
|
+
$ npx @volter/world@3.0.148 example integration-branches --dir worker-a
|
|
43
|
+
$ npx @volter/world@3.0.148 example integration-branches --dir worker-b
|
|
44
44
|
```
|
|
45
45
|
|
|
46
46
|
In `integration`, then `worker-a`, then `worker-b`, install dependencies and initialize with the folder's name. Before a first boot or app write, link and pull the baseline:
|
|
@@ -9,10 +9,10 @@
|
|
|
9
9
|
"stripe": "17.7.0"
|
|
10
10
|
},
|
|
11
11
|
"devDependencies": {
|
|
12
|
-
"@volter/world": "3.0.
|
|
13
|
-
"@volter/world-core": "3.0.
|
|
14
|
-
"@volter/world-runtime": "3.0.
|
|
15
|
-
"@volter/world-console": "3.0.
|
|
12
|
+
"@volter/world": "3.0.148",
|
|
13
|
+
"@volter/world-core": "3.0.147",
|
|
14
|
+
"@volter/world-runtime": "3.0.147",
|
|
15
|
+
"@volter/world-console": "3.0.142",
|
|
16
16
|
"@volter/twin-stripe": "3.0.2"
|
|
17
17
|
}
|
|
18
18
|
}
|
|
@@ -13,7 +13,7 @@ You need Node 22.6+, npm and registry access during installation. No platform ac
|
|
|
13
13
|
## Prepare an ordinary workplace
|
|
14
14
|
|
|
15
15
|
```console
|
|
16
|
-
$ npx @volter/world@3.0.
|
|
16
|
+
$ npx @volter/world@3.0.148 example workplace-agent --dir workplace
|
|
17
17
|
$ cd workplace
|
|
18
18
|
$ npm install
|
|
19
19
|
$ ./node_modules/.bin/volter world init --name workplace --twins github,linear,slack
|
|
@@ -11,10 +11,10 @@
|
|
|
11
11
|
"@slack/web-api": "7.19.0"
|
|
12
12
|
},
|
|
13
13
|
"devDependencies": {
|
|
14
|
-
"@volter/world": "3.0.
|
|
15
|
-
"@volter/world-core": "3.0.
|
|
16
|
-
"@volter/world-runtime": "3.0.
|
|
17
|
-
"@volter/world-console": "3.0.
|
|
14
|
+
"@volter/world": "3.0.148",
|
|
15
|
+
"@volter/world-core": "3.0.147",
|
|
16
|
+
"@volter/world-runtime": "3.0.147",
|
|
17
|
+
"@volter/world-console": "3.0.142",
|
|
18
18
|
"@volter/twin-github": "3.0.6",
|
|
19
19
|
"@volter/twin-linear": "3.0.4",
|
|
20
20
|
"@volter/twin-slack": "3.0.5"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volter/world",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.148",
|
|
4
4
|
"description": "Run your app against a world of twins. `World` and `Repo` — one method per verb: init, up, run, log, diff, reset, branch, checkout, clone, fetch, changeset, push — and the `volter` command, one client of them.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"volter",
|
|
@@ -31,12 +31,12 @@
|
|
|
31
31
|
],
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@modelcontextprotocol/sdk": "^1.30.1",
|
|
34
|
-
"@volter/world-core": "3.0.
|
|
35
|
-
"@volter/world-runtime": "3.0.
|
|
34
|
+
"@volter/world-core": "3.0.147",
|
|
35
|
+
"@volter/world-runtime": "3.0.147",
|
|
36
36
|
"zod": "^4.6.5"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
|
-
"@volter/world-console": "3.0.
|
|
39
|
+
"@volter/world-console": "3.0.142"
|
|
40
40
|
},
|
|
41
41
|
"peerDependenciesMeta": {
|
|
42
42
|
"@volter/world-console": {
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
}
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
|
-
"@volter/world-console": "3.0.
|
|
47
|
+
"@volter/world-console": "3.0.142"
|
|
48
48
|
},
|
|
49
49
|
"bin": {
|
|
50
50
|
"volter": "dist/src/cli.js"
|
package/src/world.ts
CHANGED
|
@@ -138,18 +138,22 @@ export class World {
|
|
|
138
138
|
...(opts.mode ? { mode: opts.mode } : existing ? { mode: existing.mode } : {}),
|
|
139
139
|
...(existing ? { keepState: true } : {}),
|
|
140
140
|
});
|
|
141
|
+
await this.finishStartup(instance, existing === null, opts);
|
|
142
|
+
return instance;
|
|
143
|
+
}
|
|
144
|
+
/** Product startup completes its seed sequence; the runtime owns only the boot. */
|
|
145
|
+
private async finishStartup(instance: WorldInstance, fresh: boolean, opts: { seed?: boolean; cwd?: string } = {}): Promise<void> {
|
|
141
146
|
try {
|
|
142
|
-
if (
|
|
147
|
+
if (fresh && opts.seed !== false && existsSync(worldSeedPath(this.root))) {
|
|
143
148
|
// a story that fails is a loud failure: the world is up, but not the world the app expects
|
|
144
149
|
const seeded = await seedWorld(this.name, { root: this.root, cwd: opts.cwd ?? this.root });
|
|
145
|
-
if (seeded.exitCode !== 0) throw new Error(`the story failed (${seeded.entry} exited ${seeded.exitCode});
|
|
150
|
+
if (seeded.exitCode !== 0) throw new Error(`the story failed (${seeded.entry} exited ${seeded.exitCode}); state may be partially seeded — fix the seed, start this World and run \`volter world seed\``);
|
|
146
151
|
}
|
|
147
152
|
} finally {
|
|
148
153
|
// a root set while the world was stopped reaches the twins' state after the default data (which a
|
|
149
154
|
// fresh boot runs simulated), where the deploy reads it — also when the seed failed
|
|
150
155
|
materializeRoots(loadWorldConfig(this.configRef(), this.root).config, instance.dirs.data, this.root);
|
|
151
156
|
}
|
|
152
|
-
return instance;
|
|
153
157
|
}
|
|
154
158
|
/** Stop the twins; the branch's state stays (`up` resumes). `purge` forgets it. */
|
|
155
159
|
down(opts: { purge?: boolean } = {}): ReturnType<typeof downWorld> { return downWorld(this.name, this.root, opts); }
|
|
@@ -162,7 +166,8 @@ export class World {
|
|
|
162
166
|
|
|
163
167
|
/** The kernel's instance record, or null before the first `up`. */
|
|
164
168
|
instance(): ReturnType<typeof statusWorld> | null {
|
|
165
|
-
|
|
169
|
+
if (!existsSync(join(instanceDir(this.root, this.name), 'instance.json'))) return null;
|
|
170
|
+
return statusWorld(this.name, this.root);
|
|
166
171
|
}
|
|
167
172
|
/** The world, the branch, the origin, what is unpushed, what is running. */
|
|
168
173
|
status(): WorldStatus {
|
|
@@ -351,7 +356,25 @@ export class World {
|
|
|
351
356
|
/** Serve this world on a port under `/<org>/<world>/`; returns when listening. */
|
|
352
357
|
serve(opts: { port?: number; host?: string; consolePort?: number; announce?: (info: { name: string; base: string; token: string; readToken: string; console: string | null }) => void } = {}): Promise<ServedWorld> { return serveWorld(this.name, { root: this.root, ...opts }); }
|
|
353
358
|
/** `volter world view`: this World, its twins' screens, its branches and the console on one origin (docs/contributing/architecture.md, "Viewing a World"). */
|
|
354
|
-
view(opts: { port?: number; host?: string; console?: ViewConsole; announce?: (line: string) => void; origins?: boolean; origin?: string } = {}): Promise<WorldView> {
|
|
359
|
+
async view(opts: { port?: number; host?: string; console?: ViewConsole; announce?: (line: string) => void; origins?: boolean; origin?: string } = {}): Promise<WorldView> {
|
|
360
|
+
const fresh = this.instance() === null;
|
|
361
|
+
const person = platformPerson();
|
|
362
|
+
const announced: string[] = [];
|
|
363
|
+
let ready = false;
|
|
364
|
+
const view = await serveWorldView(this.name, { root: this.root, ...(person ? { localPerson: person } : {}), ...opts, announce: line => { if (ready) opts.announce?.(line); else announced.push(line); } });
|
|
365
|
+
try {
|
|
366
|
+
const instance = this.instance();
|
|
367
|
+
if (!instance) throw new Error('the viewer started without a recorded World instance');
|
|
368
|
+
await this.finishStartup(instance, fresh);
|
|
369
|
+
for (const line of announced) opts.announce?.(line);
|
|
370
|
+
ready = true;
|
|
371
|
+
return view;
|
|
372
|
+
} catch (error) {
|
|
373
|
+
try { await view.stop(); }
|
|
374
|
+
catch (stopError) { throw new AggregateError([error, stopError], 'World viewer startup failed and teardown was not confirmed; retained lifecycle evidence needs inspection'); }
|
|
375
|
+
throw error;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
355
378
|
|
|
356
379
|
// ── remotes ─────────────────────────────────────────────────────────────────────────────
|
|
357
380
|
/** The vendors this world has a twin of, as world.json names them (a twin service's package, else its id). */
|