@volter/world 3.0.147 → 3.0.149
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 +2 -2
- package/dist/examples/integration-branches/README.md +4 -4
- package/dist/examples/integration-branches/package.json +2 -2
- package/dist/examples/workplace-agent/README.md +1 -1
- package/dist/examples/workplace-agent/package.json +2 -2
- package/dist/src/world.d.ts +2 -0
- package/dist/src/world.js +36 -4
- package/examples/customer-onboarding/README.md +1 -1
- package/examples/customer-onboarding/package.json +2 -2
- package/examples/integration-branches/README.md +4 -4
- package/examples/integration-branches/package.json +2 -2
- package/examples/workplace-agent/README.md +1 -1
- package/examples/workplace-agent/package.json +2 -2
- package/package.json +2 -2
- package/src/world.ts +26 -4
|
@@ -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.149 example customer-onboarding --dir onboarding
|
|
17
17
|
$ cd onboarding
|
|
18
18
|
$ npm install
|
|
19
19
|
```
|
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
"pg": "8.16.3"
|
|
12
12
|
},
|
|
13
13
|
"devDependencies": {
|
|
14
|
-
"@volter/world": "3.0.
|
|
14
|
+
"@volter/world": "3.0.149",
|
|
15
15
|
"@volter/world-core": "3.0.147",
|
|
16
|
-
"@volter/world-runtime": "3.0.
|
|
16
|
+
"@volter/world-runtime": "3.0.148",
|
|
17
17
|
"@volter/world-console": "3.0.142",
|
|
18
18
|
"@volter/twin-stripe": "3.0.2",
|
|
19
19
|
"@volter/twin-resend": "1.0.1"
|
|
@@ -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.149 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.149 example integration-branches --dir integration
|
|
42
|
+
$ npx @volter/world@3.0.149 example integration-branches --dir worker-a
|
|
43
|
+
$ npx @volter/world@3.0.149 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,9 +9,9 @@
|
|
|
9
9
|
"stripe": "17.7.0"
|
|
10
10
|
},
|
|
11
11
|
"devDependencies": {
|
|
12
|
-
"@volter/world": "3.0.
|
|
12
|
+
"@volter/world": "3.0.149",
|
|
13
13
|
"@volter/world-core": "3.0.147",
|
|
14
|
-
"@volter/world-runtime": "3.0.
|
|
14
|
+
"@volter/world-runtime": "3.0.148",
|
|
15
15
|
"@volter/world-console": "3.0.142",
|
|
16
16
|
"@volter/twin-stripe": "3.0.2"
|
|
17
17
|
}
|
|
@@ -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.149 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,9 +11,9 @@
|
|
|
11
11
|
"@slack/web-api": "7.19.0"
|
|
12
12
|
},
|
|
13
13
|
"devDependencies": {
|
|
14
|
-
"@volter/world": "3.0.
|
|
14
|
+
"@volter/world": "3.0.149",
|
|
15
15
|
"@volter/world-core": "3.0.147",
|
|
16
|
-
"@volter/world-runtime": "3.0.
|
|
16
|
+
"@volter/world-runtime": "3.0.148",
|
|
17
17
|
"@volter/world-console": "3.0.142",
|
|
18
18
|
"@volter/twin-github": "3.0.6",
|
|
19
19
|
"@volter/twin-linear": "3.0.4",
|
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); }
|
|
@@ -376,7 +380,35 @@ export class World {
|
|
|
376
380
|
/** Serve this world on a port under `/<org>/<world>/`; returns when listening. */
|
|
377
381
|
serve(opts = {}) { return serveWorld(this.name, { root: this.root, ...opts }); }
|
|
378
382
|
/** `volter world view`: this World, its twins' screens, its branches and the console on one origin (docs/contributing/architecture.md, "Viewing a World"). */
|
|
379
|
-
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
|
+
}
|
|
380
412
|
// ── remotes ─────────────────────────────────────────────────────────────────────────────
|
|
381
413
|
/** The vendors this world has a twin of, as world.json names them (a twin service's package, else its id). */
|
|
382
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.149 example customer-onboarding --dir onboarding
|
|
17
17
|
$ cd onboarding
|
|
18
18
|
$ npm install
|
|
19
19
|
```
|
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
"pg": "8.16.3"
|
|
12
12
|
},
|
|
13
13
|
"devDependencies": {
|
|
14
|
-
"@volter/world": "3.0.
|
|
14
|
+
"@volter/world": "3.0.149",
|
|
15
15
|
"@volter/world-core": "3.0.147",
|
|
16
|
-
"@volter/world-runtime": "3.0.
|
|
16
|
+
"@volter/world-runtime": "3.0.148",
|
|
17
17
|
"@volter/world-console": "3.0.142",
|
|
18
18
|
"@volter/twin-stripe": "3.0.2",
|
|
19
19
|
"@volter/twin-resend": "1.0.1"
|
|
@@ -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.149 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.149 example integration-branches --dir integration
|
|
42
|
+
$ npx @volter/world@3.0.149 example integration-branches --dir worker-a
|
|
43
|
+
$ npx @volter/world@3.0.149 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,9 +9,9 @@
|
|
|
9
9
|
"stripe": "17.7.0"
|
|
10
10
|
},
|
|
11
11
|
"devDependencies": {
|
|
12
|
-
"@volter/world": "3.0.
|
|
12
|
+
"@volter/world": "3.0.149",
|
|
13
13
|
"@volter/world-core": "3.0.147",
|
|
14
|
-
"@volter/world-runtime": "3.0.
|
|
14
|
+
"@volter/world-runtime": "3.0.148",
|
|
15
15
|
"@volter/world-console": "3.0.142",
|
|
16
16
|
"@volter/twin-stripe": "3.0.2"
|
|
17
17
|
}
|
|
@@ -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.149 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,9 +11,9 @@
|
|
|
11
11
|
"@slack/web-api": "7.19.0"
|
|
12
12
|
},
|
|
13
13
|
"devDependencies": {
|
|
14
|
-
"@volter/world": "3.0.
|
|
14
|
+
"@volter/world": "3.0.149",
|
|
15
15
|
"@volter/world-core": "3.0.147",
|
|
16
|
-
"@volter/world-runtime": "3.0.
|
|
16
|
+
"@volter/world-runtime": "3.0.148",
|
|
17
17
|
"@volter/world-console": "3.0.142",
|
|
18
18
|
"@volter/twin-github": "3.0.6",
|
|
19
19
|
"@volter/twin-linear": "3.0.4",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volter/world",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.149",
|
|
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",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@modelcontextprotocol/sdk": "^1.30.1",
|
|
34
34
|
"@volter/world-core": "3.0.147",
|
|
35
|
-
"@volter/world-runtime": "3.0.
|
|
35
|
+
"@volter/world-runtime": "3.0.148",
|
|
36
36
|
"zod": "^4.6.5"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
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); }
|
|
@@ -352,7 +356,25 @@ export class World {
|
|
|
352
356
|
/** Serve this world on a port under `/<org>/<world>/`; returns when listening. */
|
|
353
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 }); }
|
|
354
358
|
/** `volter world view`: this World, its twins' screens, its branches and the console on one origin (docs/contributing/architecture.md, "Viewing a World"). */
|
|
355
|
-
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
|
+
}
|
|
356
378
|
|
|
357
379
|
// ── remotes ─────────────────────────────────────────────────────────────────────────────
|
|
358
380
|
/** The vendors this world has a twin of, as world.json names them (a twin service's package, else its id). */
|