@volter/twin-standard 1.0.90 → 1.0.92
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 +13 -3
- package/dist/src/assessment.d.ts +43 -0
- package/dist/src/assessment.js +10 -2
- package/dist/src/cli.js +25 -2
- package/dist/src/clients/anthropic.first-use.json +17 -0
- package/dist/src/clients/clerk.first-use.json +21 -0
- package/dist/src/clients/cloudflare.first-use.json +21 -0
- package/dist/src/clients/github.first-use.json +21 -0
- package/dist/src/clients/openai.first-use.json +17 -0
- package/dist/src/clients/resend.first-use.json +25 -0
- package/dist/src/clients/run.js +2 -0
- package/dist/src/clients/slack.first-use.json +21 -0
- package/dist/src/clients/stripe.first-use.json +21 -0
- package/dist/src/clients/supabase.first-use.json +21 -0
- package/dist/src/clients/tavily.first-use.json +17 -0
- package/dist/src/clients/upstash.first-use.json +21 -0
- package/dist/src/conformance.js +2 -0
- package/dist/src/consumer.d.ts +67 -0
- package/dist/src/consumer.js +190 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.js +1 -0
- package/dist/src/protocol-3.js +1 -1
- package/package.json +2 -2
- package/src/assessment.ts +7 -3
- package/src/cli.ts +19 -2
- package/src/clients/anthropic.first-use.json +17 -0
- package/src/clients/clerk.first-use.json +21 -0
- package/src/clients/cloudflare.first-use.json +21 -0
- package/src/clients/github.first-use.json +21 -0
- package/src/clients/openai.first-use.json +17 -0
- package/src/clients/resend.first-use.json +25 -0
- package/src/clients/run.ts +1 -0
- package/src/clients/slack.first-use.json +21 -0
- package/src/clients/stripe.first-use.json +21 -0
- package/src/clients/supabase.first-use.json +21 -0
- package/src/clients/tavily.first-use.json +17 -0
- package/src/clients/upstash.first-use.json +21 -0
- package/src/conformance.ts +1 -0
- package/src/consumer.ts +168 -0
- package/src/index.ts +1 -0
- package/src/protocol-3.ts +1 -1
package/README.md
CHANGED
|
@@ -14,7 +14,8 @@ twin-standard grade <pack or lane dir>… [--static] [--form] # each criterion'
|
|
|
14
14
|
twin-standard derive <pack or lane dir> [--out <dir>] # write src/generated/ from the vendored spec
|
|
15
15
|
twin-standard check-sources <pack or lane dir> [--recheck] # fetch and record the sources the unit cites
|
|
16
16
|
twin-standard facts <pack dir> [--out <file>] # package-local facts from its descriptor
|
|
17
|
-
twin-standard
|
|
17
|
+
twin-standard prepare-consumer <pack dir> --app <new dir> --cli <volter executable> --integrity <sha512> --out <json>
|
|
18
|
+
twin-standard assess <pack dir> --prepared-consumer <json> [--browser] [--out <file>] # inside a World
|
|
18
19
|
twin-standard --version # this package's version and each standard's
|
|
19
20
|
```
|
|
20
21
|
|
|
@@ -23,7 +24,16 @@ What each criterion asks, and the rules for changing one, are twin-world's
|
|
|
23
24
|
A changed criterion is a release of this package: a criterion's id never changes meaning; a changed criterion takes a
|
|
24
25
|
new id and a new standard version, and a tightened check names what newly fails.
|
|
25
26
|
|
|
26
|
-
The public `assessPack(packDir, { browser: true })` API runs inside a World, reports actual operation coverage from
|
|
27
|
+
The public `assessPack(packDir, { browser: true, consumer })` API runs inside a World, reports actual operation coverage from
|
|
27
28
|
kernel dispatch and replays journeys through Chromium when their wire is HTTP. Install Playwright and Chromium for
|
|
28
29
|
that target. Its report distinguishes API support, operations exercised, journey failures and replay, and does not
|
|
29
|
-
claim DOM interaction coverage.
|
|
30
|
+
claim DOM interaction coverage. `consumer` contains absolute `appDir` and `cli` paths and the candidate's
|
|
31
|
+
`artifactIntegrity`. Prepare the pack's `journeys/first-use.json` with `prepareConsumerApp(packDir, newAppDir)`,
|
|
32
|
+
then install its exact SDK dependencies with scripts disabled before the assessment World starts. The public
|
|
33
|
+
`runConsumerWorkflow(packDir, consumer)` lets a builder walk only that entry journey while authoring; it runs no
|
|
34
|
+
grade or conformance checks. Installed readiness requires ordinary CLI initialization against the exact candidate,
|
|
35
|
+
SDK assertions, read-only state inspection after stop/resume for stored workflows, and verified teardown. A
|
|
36
|
+
stateless workflow records why retained-state inspection does not apply. Empty SDK case execution fails.
|
|
37
|
+
|
|
38
|
+
The [canonical pack procedure](https://github.com/volter-ai/twin-world/blob/main/docs/contributing/architecture.md#creating-a-pack)
|
|
39
|
+
owns the recipe format and completion requirements. Catalog controllers own provenance, admission and publication.
|
package/dist/src/assessment.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { type ConsumerOptions } from './consumer.js';
|
|
1
2
|
export type AssessmentOptions = {
|
|
2
3
|
browser?: boolean;
|
|
3
4
|
conformance?: boolean;
|
|
5
|
+
consumer?: ConsumerOptions;
|
|
4
6
|
};
|
|
5
7
|
/** Surface coverage counts actual kernel dispatch, and retains every declared gap in the denominator. */
|
|
6
8
|
export declare function assessPack(packDir: string, options?: AssessmentOptions): Promise<{
|
|
@@ -46,4 +48,45 @@ export declare function assessPack(packDir: string, options?: AssessmentOptions)
|
|
|
46
48
|
};
|
|
47
49
|
browser: Record<string, unknown>;
|
|
48
50
|
conformance: import("./conformance.js").ConformanceResult[] | null;
|
|
51
|
+
consumer: {
|
|
52
|
+
node: string;
|
|
53
|
+
at: string;
|
|
54
|
+
retentionNotApplicable?: string | undefined;
|
|
55
|
+
measured: boolean;
|
|
56
|
+
passed: boolean;
|
|
57
|
+
scope: string;
|
|
58
|
+
package: any;
|
|
59
|
+
version: any;
|
|
60
|
+
integrity: string;
|
|
61
|
+
tools: {
|
|
62
|
+
'@volter/world': string;
|
|
63
|
+
'@volter/world-core': string;
|
|
64
|
+
'@volter/world-runtime': string;
|
|
65
|
+
};
|
|
66
|
+
sourceInputsSha256: string;
|
|
67
|
+
recipeSha256: string;
|
|
68
|
+
fixture: string;
|
|
69
|
+
appDir: string;
|
|
70
|
+
appName: string;
|
|
71
|
+
commands: {
|
|
72
|
+
label: string;
|
|
73
|
+
argv: string[];
|
|
74
|
+
exitCode: number | null;
|
|
75
|
+
stdout: string;
|
|
76
|
+
stderr: string;
|
|
77
|
+
}[];
|
|
78
|
+
failures: string[];
|
|
79
|
+
teardownVerified: boolean;
|
|
80
|
+
retainedReadback: boolean;
|
|
81
|
+
clock: {
|
|
82
|
+
at: string;
|
|
83
|
+
advanceAfterRun?: string;
|
|
84
|
+
} | {
|
|
85
|
+
mode: string;
|
|
86
|
+
};
|
|
87
|
+
} | {
|
|
88
|
+
measured: boolean;
|
|
89
|
+
passed: boolean;
|
|
90
|
+
failures: string[];
|
|
91
|
+
};
|
|
49
92
|
}>;
|
package/dist/src/assessment.js
CHANGED
|
@@ -16,6 +16,7 @@ import { conformance } from "./conformance.js";
|
|
|
16
16
|
import { inMemoryWorld, walk, withPinnedWorldDraws, usePacks } from "./walk/behavior-journey.js";
|
|
17
17
|
import { compilePackFacts } from "./pack-facts.js";
|
|
18
18
|
import { expandFills } from "./walk/journey-kit.js";
|
|
19
|
+
import { runConsumerWorkflow } from "./consumer.js";
|
|
19
20
|
const canonical = (value) => value && typeof value === 'object' ? Array.isArray(value) ? value.map(canonical) : Object.fromEntries(Object.entries(value).sort(([a], [b]) => a.localeCompare(b)).map(([key, item]) => [key, canonical(item)])) : value;
|
|
20
21
|
const json = (value) => JSON.stringify(canonical(value));
|
|
21
22
|
const hash = (value) => createHash('sha256').update(json(value)).digest('hex');
|
|
@@ -119,6 +120,13 @@ export async function assessPack(packDir, options = {}) {
|
|
|
119
120
|
}
|
|
120
121
|
}
|
|
121
122
|
const conform = options.conformance === false ? null : await conformance(packDir);
|
|
122
|
-
|
|
123
|
-
|
|
123
|
+
let consumer;
|
|
124
|
+
try {
|
|
125
|
+
consumer = options.consumer ? await runConsumerWorkflow(packDir, options.consumer) : { measured: false, passed: false, failures: ['Installed customer workflow was not prepared'] };
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
consumer = { measured: false, passed: false, failures: [error.message] };
|
|
129
|
+
}
|
|
130
|
+
const ready = gates.length > 0 && gates.every((gate) => !gate.failures.length) && !quick.failures.length && replayEqual && conform !== null && conform.length > 0 && conform.every((result) => !result.failures.length) && consumer.measured && consumer.passed && (!options.browser || !httpOnly || browser.measured === true && browser.failures.length === 0 && browser.replay.equal);
|
|
131
|
+
return { schemaVersion: 1, vendor, package: manifest.name, version: manifest.version, ready, gates: gates.map((gate) => ({ ...gate, unit: gate.unit === packDir ? vendor : `${vendor}/${gate.unit.slice(packDir.length + 1)}` })), quick, browser, conformance: conform, consumer };
|
|
124
132
|
}
|
package/dist/src/cli.js
CHANGED
|
@@ -31,7 +31,7 @@ import { standardPackageFile } from "./package-file.js";
|
|
|
31
31
|
import { gatePublished } from "./published.js";
|
|
32
32
|
const [command, ...args] = process.argv.slice(2);
|
|
33
33
|
const usage = () => {
|
|
34
|
-
console.error('usage: twin-standard gate <repo> [units…] | gate-published <name>@<version>… [--registry <url>] | grade <unit>… [--static] [--form] | derive <unit> [--out <dir>] | read-page <url> [--raw] | check-sources <unit> [--recheck] | conform <pack dir> | <name>@<version> [--registry <url>] | create <dir> --init <vendor> --package <@scope/name> | create <unit> --index | facts <pack dir> [--out <file>] | assess <pack dir> [--browser] [--out <file>] | --version');
|
|
34
|
+
console.error('usage: twin-standard gate <repo> [units…] | gate-published <name>@<version>… [--registry <url>] | grade <unit>… [--static] [--form] | derive <unit> [--out <dir>] | read-page <url> [--raw] | check-sources <unit> [--recheck] | conform <pack dir> | <name>@<version> [--registry <url>] | create <dir> --init <vendor> --package <@scope/name> | create <unit> --index | facts <pack dir> [--out <file>] | prepare-consumer <pack dir> --app <new dir> --cli <volter executable> --integrity <sha512> --out <json> | assess <pack dir> --prepared-consumer <json> [--browser] [--out <file>] | --version');
|
|
35
35
|
process.exit(2);
|
|
36
36
|
};
|
|
37
37
|
if (command === '--version') {
|
|
@@ -109,11 +109,34 @@ else if (command === 'create') {
|
|
|
109
109
|
throw new Error('Name your scoped package with --package');
|
|
110
110
|
await (await import("./create-pack.js")).createPack(args);
|
|
111
111
|
}
|
|
112
|
+
else if (command === 'prepare-consumer') {
|
|
113
|
+
if (!args[0])
|
|
114
|
+
usage();
|
|
115
|
+
const value = (name) => { const at = args.indexOf(name); if (at < 0 || !args[at + 1])
|
|
116
|
+
usage(); return args[at + 1]; };
|
|
117
|
+
const appDir = resolve(value('--app'));
|
|
118
|
+
const cli = resolve(value('--cli'));
|
|
119
|
+
const artifactIntegrity = value('--integrity');
|
|
120
|
+
if (!/^sha512-[A-Za-z0-9+/]{86}==$/.test(artifactIntegrity))
|
|
121
|
+
throw new Error('Consumer preparation requires candidate SHA-512 integrity');
|
|
122
|
+
const out = resolve(value('--out'));
|
|
123
|
+
if (existsSync(out))
|
|
124
|
+
throw new Error('Prepared consumer output already exists');
|
|
125
|
+
const { prepareConsumerApp } = await import("./consumer.js");
|
|
126
|
+
const fixture = prepareConsumerApp(resolve(args[0]), appDir);
|
|
127
|
+
const { writeFileSync } = await import('node:fs');
|
|
128
|
+
writeFileSync(out, JSON.stringify({ appDir, cli, artifactIntegrity }, null, 2) + '\n');
|
|
129
|
+
console.log(JSON.stringify({ appDir, fixture, preparedConsumer: out, next: 'Install the app SDK dependencies with scripts disabled before assessing inside a World' }));
|
|
130
|
+
}
|
|
112
131
|
else if (command === 'assess') {
|
|
113
132
|
if (!args[0])
|
|
114
133
|
usage();
|
|
115
134
|
const { assessPack } = await import("./assessment.js");
|
|
116
|
-
const
|
|
135
|
+
const consumerAt = args.indexOf('--prepared-consumer');
|
|
136
|
+
if (consumerAt >= 0 && !args[consumerAt + 1])
|
|
137
|
+
usage();
|
|
138
|
+
const consumer = consumerAt >= 0 ? JSON.parse(readFileSync(resolve(args[consumerAt + 1]), 'utf8')) : undefined;
|
|
139
|
+
const report = await assessPack(resolve(args[0]), { browser: args.includes('--browser'), ...(consumer ? { consumer } : {}) });
|
|
117
140
|
const at = args.indexOf('--out');
|
|
118
141
|
if (at >= 0) {
|
|
119
142
|
if (!args[at + 1])
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"source": "https://www.npmjs.com/package/@anthropic-ai/sdk/v/0.131.0",
|
|
4
|
+
"about": "Use the official SDK for Messages and streaming, checking the explicitly labeled model stub.",
|
|
5
|
+
"files": {
|
|
6
|
+
"package.json": "{\n \"name\": \"anthropic-installed-customer\",\n \"private\": true,\n \"type\": \"module\",\n \"dependencies\": {\n \"@anthropic-ai/sdk\": \"0.131.0\"\n }\n}\n",
|
|
7
|
+
".env.example": "ANTHROPIC_API_KEY=\n",
|
|
8
|
+
"app.mjs": "import Anthropic from '@anthropic-ai/sdk';\nimport assert from 'node:assert/strict';\nimport { writeFileSync } from 'node:fs';\nassert.ok(process.env.VOLTER_WORLD, 'must run in the World');\nconst client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY, maxRetries:0 });\nconst input = {model:'claude-sonnet-4-5', max_tokens:128, messages:[{role:'user',content:'first-user deterministic fixture'}]};\nconst response = await client.messages.create(input);\nconst text = response.content.filter(x=>x.type==='text').map(x=>x.text).join('');\nassert.match(text,/\\[twin-stub:/);\nassert.equal(response.role,'assistant');\nassert.equal(response.stop_reason,'end_turn');\nlet streamed='';\nfor await (const event of await client.messages.create({...input,stream:true})) if (event.type==='content_block_delta' && event.delta.type==='text_delta') streamed+=event.delta.text;\nassert.equal(streamed,text);\nconst receipt={passed:true,scope:'unchanged official Anthropic SDK non-streamed and streamed Messages; labeled deterministic stub, no prose quality claim',};\nwriteFileSync('first-use-receipt.json',JSON.stringify(receipt,null,2)+'\\n');console.log(JSON.stringify(receipt));\n"
|
|
9
|
+
},
|
|
10
|
+
"run": [
|
|
11
|
+
"node",
|
|
12
|
+
"app.mjs"
|
|
13
|
+
],
|
|
14
|
+
"retention": {
|
|
15
|
+
"none": "This workflow requests an unstored message and stream; it creates no vendor resource to read after restart."
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"source": "https://www.npmjs.com/package/@clerk/backend/v/2.33.3",
|
|
4
|
+
"about": "A first user creates a user and organization, adds a member, verifies a signed session token and removes the member; after resume the original owner and membership remain.",
|
|
5
|
+
"files": {
|
|
6
|
+
"package.json": "{\n \"name\": \"clerk-installed-customer\",\n \"private\": true,\n \"type\": \"module\",\n \"dependencies\": {\n \"@clerk/backend\": \"2.33.3\"\n }\n}\n",
|
|
7
|
+
".env.example": "CLERK_SECRET_KEY=\nCLERK_PUBLISHABLE_KEY=\nCLERK_JWT_KEY=\n",
|
|
8
|
+
"workflow.mjs": "import assert from 'node:assert/strict';\nimport { writeFileSync } from 'node:fs';\nimport { createClerkClient, verifyToken } from '@clerk/backend';\n\nassert.ok(process.env.VOLTER_WORLD);\nconst clerk = createClerkClient({ secretKey: process.env.CLERK_SECRET_KEY });\nawait clerk.instance.updateOrganizationSettings({ enabled: true });\nconst owner = await clerk.users.createUser({ emailAddress: ['owner@catalog-clerk.example'], firstName: 'First', skipPasswordRequirement: true });\nconst org = await clerk.organizations.createOrganization({ name: 'Catalog first user', createdBy: owner.id });\nconst guest = await clerk.users.createUser({ emailAddress: ['member@catalog-clerk.example'], firstName: 'Member', skipPasswordRequirement: true });\nawait clerk.organizations.createOrganizationMembership({ organizationId: org.id, userId: guest.id, role: 'org:member' });\nconst before = await clerk.organizations.getOrganizationMembershipList({ organizationId: org.id, limit: 100 });\nassert.equal(before.totalCount, 2);\nassert.ok(before.data.some(member => member.publicUserData.userId === guest.id));\nconst session = await clerk.sessions.createSession({ userId: guest.id });\nconst { jwt } = await clerk.sessions.getToken(session.id);\nconst payload = await verifyToken(jwt, { secretKey: process.env.CLERK_SECRET_KEY });\nassert.equal(payload.sub, guest.id);\nassert.equal(payload.sid, session.id);\nawait clerk.users.deleteUser(guest.id);\nconst after = await clerk.organizations.getOrganizationMembershipList({ organizationId: org.id, limit: 100 });\nassert.equal(after.totalCount, 1);\nassert.equal(after.data[0].publicUserData.userId, owner.id);\nwriteFileSync('workflow-receipt.json', JSON.stringify({ owner: owner.id, organization: org.id, deletedMember: guest.id, remainingMemberships: after.totalCount, tokenVerified: true }, null, 2) + '\\n');\nconsole.log('Clerk SDK user, membership, signed token and deletion journey passed');\n",
|
|
9
|
+
"readback.mjs": "import assert from 'node:assert/strict';\nimport { readFileSync } from 'node:fs';\nimport { createClerkClient } from '@clerk/backend';\n\nassert.ok(process.env.VOLTER_WORLD);\nconst previous = JSON.parse(readFileSync('workflow-receipt.json', 'utf8'));\nconst clerk = createClerkClient({ secretKey: process.env.CLERK_SECRET_KEY });\nconst owner = await clerk.users.getUser(previous.owner);\nassert.equal(owner.emailAddresses[0].emailAddress, 'owner@catalog-clerk.example');\nconst memberships = await clerk.organizations.getOrganizationMembershipList({ organizationId: previous.organization, limit: 100 });\nassert.equal(memberships.totalCount, 1);\nassert.equal(memberships.data[0].publicUserData.userId, previous.owner);\nassert.ok(memberships.data.every(member => member.publicUserData.userId !== previous.deletedMember));\nconsole.log(JSON.stringify({ retained: true, organization: previous.organization, remainingMemberships: memberships.totalCount }));\n"
|
|
10
|
+
},
|
|
11
|
+
"run": [
|
|
12
|
+
"node",
|
|
13
|
+
"workflow.mjs"
|
|
14
|
+
],
|
|
15
|
+
"retention": {
|
|
16
|
+
"readback": [
|
|
17
|
+
"node",
|
|
18
|
+
"readback.mjs"
|
|
19
|
+
]
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"source": "https://www.npmjs.com/package/cloudflare/v/7.2.0",
|
|
4
|
+
"about": "Create a zone and DNS record through the official SDK, then read the retained record after restart.",
|
|
5
|
+
"files": {
|
|
6
|
+
"package.json": "{\n \"name\": \"cloudflare-installed-customer\",\n \"private\": true,\n \"type\": \"module\",\n \"dependencies\": {\n \"cloudflare\": \"7.2.0\"\n }\n}\n",
|
|
7
|
+
".env.example": "CLOUDFLARE_API_TOKEN=\nCLOUDFLARE_ACCOUNT_ID=\n",
|
|
8
|
+
"resume.mjs": "import assert from 'node:assert/strict';\nimport { readFileSync, writeFileSync } from 'node:fs';\nimport Cloudflare from 'cloudflare';\nassert.ok(process.env.VOLTER_WORLD);\nconst held = JSON.parse(readFileSync('first-use-receipt.json', 'utf8'));\nconst client = new Cloudflare({ apiToken: process.env.CLOUDFLARE_API_TOKEN, maxRetries: 0 });\nconst saved = await client.dns.records.get(held.record, { zone_id: held.zone });\nassert.equal(saved.content, '192.0.2.10');\nconst receipt = { passed: true, scope: 'down/up retains DNS record and World-issued credentials remain usable', };\nwriteFileSync('resume-receipt.json', JSON.stringify(receipt, null, 2) + '\\n');\nconsole.log(JSON.stringify(receipt));\n",
|
|
9
|
+
"app.mjs": "import assert from 'node:assert/strict';\nimport { writeFileSync } from 'node:fs';\nimport Cloudflare from 'cloudflare';\nassert.ok(process.env.VOLTER_WORLD);\nconst client = new Cloudflare({ apiToken: process.env.CLOUDFLARE_API_TOKEN, maxRetries: 0 });\nconst zone = await client.zones.create({ account: { id: process.env.CLOUDFLARE_ACCOUNT_ID }, name: 'first-user.example', type: 'full' });\nconst record = await client.dns.records.create({ zone_id: zone.id, type: 'A', name: 'www.first-user.example', content: '192.0.2.10', ttl: 1, proxied: true });\nconst saved = await client.dns.records.get(record.id, { zone_id: zone.id });\nassert.equal(saved.name, 'www.first-user.example');\nassert.equal(saved.content, '192.0.2.10');\nassert.equal(saved.proxied, true);\nconst receipt = { passed: true, scope: 'fresh published CLI init/up/run/log/down; unchanged official Cloudflare SDK zone create and DNS write/read', zone: zone.id, record: record.id, };\nwriteFileSync('first-use-receipt.json', JSON.stringify(receipt, null, 2) + '\\n');\nconsole.log(JSON.stringify(receipt));\n"
|
|
10
|
+
},
|
|
11
|
+
"run": [
|
|
12
|
+
"node",
|
|
13
|
+
"app.mjs"
|
|
14
|
+
],
|
|
15
|
+
"retention": {
|
|
16
|
+
"readback": [
|
|
17
|
+
"node",
|
|
18
|
+
"resume.mjs"
|
|
19
|
+
]
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"source": "https://www.npmjs.com/package/@octokit/rest/v/22.0.1",
|
|
4
|
+
"about": "Create a repository and issue through Octokit, inspect a missing issue refusal, then read the retained issue after restart.",
|
|
5
|
+
"files": {
|
|
6
|
+
"package.json": "{\n \"name\": \"github-installed-customer\",\n \"private\": true,\n \"type\": \"module\",\n \"dependencies\": {\n \"@octokit/rest\": \"22.0.1\"\n }\n}\n",
|
|
7
|
+
".env.example": "GITHUB_TOKEN=\n",
|
|
8
|
+
"resume.mjs": "import assert from 'node:assert/strict';\nimport { readFileSync, writeFileSync } from 'node:fs';\nimport { Octokit } from '@octokit/rest';\nassert.ok(process.env.VOLTER_WORLD);\nconst prior = JSON.parse(readFileSync('first-use-receipt.json', 'utf8'));\nconst client = new Octokit({ auth: process.env.GITHUB_TOKEN });\nconst saved = (await client.rest.issues.get({ owner: prior.owner, repo: prior.repo, issue_number: prior.issue })).data;\nassert.equal(saved.title, prior.title);\nconst receipt = { passed: true, scope: 'ordinary down then up retains stored GitHub issue and usable throwaway credentials', title: saved.title, issue: saved.number, };\nwriteFileSync('resume-receipt.json', JSON.stringify(receipt, null, 2) + '\\n');\nconsole.log(JSON.stringify(receipt));\n",
|
|
9
|
+
"app.mjs": "import assert from 'node:assert/strict';\nimport { writeFileSync } from 'node:fs';\nimport { Octokit } from '@octokit/rest';\nassert.ok(process.env.VOLTER_WORLD, 'Run the app through its World');\nassert.ok(process.env.GITHUB_TOKEN, 'The World supplies a throwaway token');\nconst client = new Octokit({ auth: process.env.GITHUB_TOKEN });\nconst created = await client.graphql('mutation($name: String!) { createRepository(input: { name: $name, visibility: PUBLIC }) { repository { nameWithOwner } } }', { name: 'first-catalog-app' });\nconst [owner, repo] = created.createRepository.repository.nameWithOwner.split('/');\nconst made = (await client.rest.issues.create({ owner, repo, title: 'First local issue', body: 'Created through the real Octokit SDK inside a World.' })).data;\nconst saved = (await client.rest.issues.get({ owner, repo, issue_number: made.number })).data;\nassert.equal(saved.title, made.title);\nassert.equal(saved.body, made.body);\nassert.equal(saved.state, 'open');\nawait assert.rejects(() => client.rest.issues.get({ owner, repo, issue_number: 99999 }), error => error.status === 404);\nconst receipt = { passed: true, scope: 'fresh published CLI init/up/run/log/down with unmodified Octokit; repository create and issue write/read/missing read', owner, repo, issue: saved.number, title: saved.title, };\nwriteFileSync('first-use-receipt.json', JSON.stringify(receipt, null, 2) + '\\n');\nconsole.log(JSON.stringify(receipt));\n"
|
|
10
|
+
},
|
|
11
|
+
"run": [
|
|
12
|
+
"node",
|
|
13
|
+
"app.mjs"
|
|
14
|
+
],
|
|
15
|
+
"retention": {
|
|
16
|
+
"readback": [
|
|
17
|
+
"node",
|
|
18
|
+
"resume.mjs"
|
|
19
|
+
]
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"source": "https://www.npmjs.com/package/openai/v/7.28.0",
|
|
4
|
+
"about": "Use the official SDK for Chat Completions and SSE streaming, checking the explicitly labeled model stub.",
|
|
5
|
+
"files": {
|
|
6
|
+
"package.json": "{\n \"name\": \"openai-installed-customer\",\n \"private\": true,\n \"type\": \"module\",\n \"dependencies\": {\n \"openai\": \"7.28.0\"\n }\n}\n",
|
|
7
|
+
".env.example": "OPENAI_API_KEY=\n",
|
|
8
|
+
"app.mjs": "import OpenAI from 'openai';\nimport assert from 'node:assert/strict';\nimport {writeFileSync} from 'node:fs';\nassert.ok(process.env.VOLTER_WORLD,'run through the World');\nconst client=new OpenAI({apiKey:process.env.OPENAI_API_KEY,maxRetries:0});\nconst input={model:'gpt-4o',messages:[{role:'user',content:'first-user deterministic fixture'}]};\nconst answer=await client.chat.completions.create(input);\nconst text=answer.choices[0].message.content;\nassert.match(text,/\\[twin-stub:/);\nassert.equal(answer.choices[0].message.role,'assistant');\nassert.equal(answer.choices[0].finish_reason,'stop');\nlet streamed='';\nfor await(const event of await client.chat.completions.create({...input,stream:true})) streamed+=event.choices[0]?.delta?.content??'';\nassert.equal(streamed,text);\nconst receipt={passed:true,scope:'unchanged official OpenAI SDK Chat Completions and SSE stream; labeled default model stub; no generated prose quality or Realtime/browser claim',};\nwriteFileSync('first-use-receipt.json',JSON.stringify(receipt,null,2)+'\\n');console.log(JSON.stringify(receipt));\n"
|
|
9
|
+
},
|
|
10
|
+
"run": [
|
|
11
|
+
"node",
|
|
12
|
+
"app.mjs"
|
|
13
|
+
],
|
|
14
|
+
"retention": {
|
|
15
|
+
"none": "This workflow requests an unstored completion and stream; it creates no vendor resource to read after restart."
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"source": "https://www.npmjs.com/package/resend/v/6.6.0",
|
|
4
|
+
"about": "Send a synthetic sign-in email through the official SDK and inspect the retained message and local inbox after restart. Advance the frozen World clock to settle synthetic delivery before retained-state inspection.",
|
|
5
|
+
"files": {
|
|
6
|
+
"package.json": "{\n \"name\": \"resend-installed-customer\",\n \"private\": true,\n \"type\": \"module\",\n \"dependencies\": {\n \"resend\": \"6.6.0\"\n }\n}\n",
|
|
7
|
+
".env.example": "RESEND_API_KEY=\n",
|
|
8
|
+
"inspect-email.mjs": "import assert from 'node:assert/strict';\nimport { readFileSync } from 'node:fs';\nimport { Resend } from 'resend';\n\nassert.ok(process.env.VOLTER_WORLD, 'run this script through the World');\nconst { id } = JSON.parse(readFileSync('last-email.json', 'utf8'));\nconst resend = new Resend(process.env.RESEND_API_KEY);\nconst saved = await resend.emails.get(id);\nassert.equal(saved.error, null);\nassert.equal(saved.data.last_event, 'delivered');\nconst response = await fetch(`${process.env.RESEND_TWIN_URL}/_twin/mail?to=owner%40world.test`);\nassert.equal(response.status, 200);\nconst inbox = await response.json();\nconst email = inbox.mail.find((message) => message.id === id);\nassert.ok(email, 'the delivered message must be in the local inbox');\nassert.equal(email.subject, 'Your local sign-in code');\nassert.match(email.text, /123456/);\nassert.match(email.html, /<strong>123456<\\/strong>/);\nconsole.log('local inbox contains the delivered email and sign-in code');\n",
|
|
9
|
+
"send-email.mjs": "import assert from 'node:assert/strict';\nimport { writeFileSync } from 'node:fs';\nimport { Resend } from 'resend';\n\nassert.ok(process.env.VOLTER_WORLD, 'run this script through the World');\nconst resend = new Resend(process.env.RESEND_API_KEY);\nconst email = {\n from: 'Example app <onboarding@resend.dev>',\n to: ['owner@world.test'],\n subject: 'Your local sign-in code',\n text: 'Your synthetic sign-in code is 123456.',\n html: '<p>Your synthetic sign-in code is <strong>123456</strong>.</p>'\n};\nconst sent = await resend.emails.send(email);\nassert.equal(sent.error, null);\nassert.ok(sent.data.id);\nconst saved = await resend.emails.get(sent.data.id);\nassert.equal(saved.error, null);\nassert.equal(saved.data.id, sent.data.id);\nassert.equal(saved.data.subject, email.subject);\nassert.equal(saved.data.text, email.text);\nassert.deepEqual(saved.data.to, email.to);\nwriteFileSync('last-email.json', JSON.stringify({ id: sent.data.id }) + '\\n');\nconsole.log('email sent and read back locally');\n"
|
|
10
|
+
},
|
|
11
|
+
"run": [
|
|
12
|
+
"node",
|
|
13
|
+
"send-email.mjs"
|
|
14
|
+
],
|
|
15
|
+
"retention": {
|
|
16
|
+
"readback": [
|
|
17
|
+
"node",
|
|
18
|
+
"inspect-email.mjs"
|
|
19
|
+
]
|
|
20
|
+
},
|
|
21
|
+
"clock": {
|
|
22
|
+
"at": "2026-10-06T12:00:00Z",
|
|
23
|
+
"advanceAfterRun": "10s"
|
|
24
|
+
}
|
|
25
|
+
}
|
package/dist/src/clients/run.js
CHANGED
|
@@ -16,6 +16,8 @@ import { fileURLToPath } from 'node:url';
|
|
|
16
16
|
import { clientContext, worldProxy } from "./harness.js";
|
|
17
17
|
const job = JSON.parse(readFileSync(process.argv[2], 'utf8'));
|
|
18
18
|
const { cases } = (await import(__rewriteRelativeImportExtension(`./${job.vendor}${extname(fileURLToPath(import.meta.url))}`)));
|
|
19
|
+
if (!Array.isArray(cases) || cases.length === 0)
|
|
20
|
+
throw new Error(`${job.vendor} client module declares no cases; there is no SDK execution evidence`);
|
|
19
21
|
// every connection a case makes goes through the World's proxy, as an application's does in a World
|
|
20
22
|
const proxy = await worldProxy(job.port);
|
|
21
23
|
// Bind only this artifact's declared vendor hosts to the assessed server. The enclosing World's
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"source": "https://www.npmjs.com/package/@slack/web-api/v/7.19.0",
|
|
4
|
+
"about": "Create a Slack Connect invitation through the official SDK, then inspect the retained invitation after restart.",
|
|
5
|
+
"files": {
|
|
6
|
+
"package.json": "{\n \"name\": \"slack-installed-customer\",\n \"private\": true,\n \"type\": \"module\",\n \"dependencies\": {\n \"@slack/web-api\": \"7.19.0\"\n }\n}\n",
|
|
7
|
+
".env.example": "SLACK_BOT_TOKEN=\nSLACK_APP_TOKEN=\nSLACK_SIGNING_SECRET=\n",
|
|
8
|
+
"readback.mjs": "import assert from 'node:assert/strict';\nimport {readFileSync} from 'node:fs';\nimport {WebClient} from '@slack/web-api';\nconst old=JSON.parse(readFileSync('workflow-receipt.json','utf8'));\nconst slack=new WebClient(process.env.SLACK_BOT_TOKEN);\nconst identity=await slack.auth.test();\nassert.equal(identity.team,'World');\nconst pending=await slack.conversations.listConnectInvites({count:1});\nassert.equal(pending.invites[0].invite.id,old.invitation);\nassert.equal(pending.invites[0].channel.id,old.channel);\nconsole.log(JSON.stringify({retained:true,workspace:identity.team,invitation:old.invitation}));\n",
|
|
9
|
+
"workflow.mjs": "import assert from 'node:assert/strict';\nimport { writeFileSync } from 'node:fs';\nimport { WebClient } from '@slack/web-api';\nassert.ok(process.env.VOLTER_WORLD);\nconst slack = new WebClient(process.env.SLACK_BOT_TOKEN);\nconst identity = await slack.auth.test();\nconst channel = await slack.conversations.create({ name: 'catalog-first-user-support' });\nconst invitation = await slack.conversations.inviteShared({ channel: channel.channel.id, emails: ['customer@outside.test'], external_limited: true });\nconst pending = await slack.conversations.listConnectInvites({ count: 1 });\nassert.equal(pending.invites[0].invite.id, invitation.invite_id);\nassert.equal(pending.invites[0].channel.id, channel.channel.id);\nwriteFileSync('workflow-receipt.json', JSON.stringify({ identity: { team_id: identity.team_id, team: identity.team }, channel: channel.channel.id, invitation: invitation.invite_id, pending: true }, null, 2) + '\\n');\n"
|
|
10
|
+
},
|
|
11
|
+
"run": [
|
|
12
|
+
"node",
|
|
13
|
+
"workflow.mjs"
|
|
14
|
+
],
|
|
15
|
+
"retention": {
|
|
16
|
+
"readback": [
|
|
17
|
+
"node",
|
|
18
|
+
"readback.mjs"
|
|
19
|
+
]
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"source": "https://www.npmjs.com/package/stripe/v/17.7.0",
|
|
4
|
+
"about": "Create and retrieve a customer through the official SDK. Read the retained customer after restart.",
|
|
5
|
+
"files": {
|
|
6
|
+
"package.json": "{\n \"name\": \"stripe-installed-customer\",\n \"private\": true,\n \"type\": \"module\",\n \"dependencies\": {\n \"stripe\": \"17.7.0\"\n }\n}\n",
|
|
7
|
+
".env.example": "STRIPE_SECRET_KEY=\n",
|
|
8
|
+
"signup.mjs": "import { writeFileSync } from 'node:fs';\nimport assert from 'node:assert/strict';\nimport Stripe from 'stripe';\n\nassert.ok(process.env.VOLTER_WORLD);\nconst stripe = new Stripe(process.env.STRIPE_SECRET_KEY);\nconst customer = await stripe.customers.create({ email: 'ada@example.com', name: 'Ada' });\nconst saved = await stripe.customers.retrieve(customer.id);\nassert.equal(saved.email, 'ada@example.com');\nassert.equal(saved.name, 'Ada');\nconsole.log(`created ${customer.id}`);\nconsole.log('customer read-back passed');\nwriteFileSync('customer.json', JSON.stringify({ id: customer.id }) + '\\n');\n",
|
|
9
|
+
"readback.mjs": "import assert from 'node:assert/strict';\nimport { readFileSync } from 'node:fs';\nimport Stripe from 'stripe';\nassert.ok(process.env.VOLTER_WORLD);\nconst { id } = JSON.parse(readFileSync('customer.json', 'utf8'));\nconst stripe = new Stripe(process.env.STRIPE_SECRET_KEY);\nconst saved = await stripe.customers.retrieve(id);\nassert.equal(saved.email, 'ada@example.com');\nassert.equal(saved.name, 'Ada');\nconsole.log('retained customer read-back passed');\n"
|
|
10
|
+
},
|
|
11
|
+
"run": [
|
|
12
|
+
"node",
|
|
13
|
+
"signup.mjs"
|
|
14
|
+
],
|
|
15
|
+
"retention": {
|
|
16
|
+
"readback": [
|
|
17
|
+
"node",
|
|
18
|
+
"readback.mjs"
|
|
19
|
+
]
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"source": "https://www.npmjs.com/package/pg/v/8.16.3",
|
|
4
|
+
"about": "Use the issued Supabase database connection with unchanged node-postgres: schema, write and read, then read retained data after restart. This does not establish Supabase HTTP client compatibility.",
|
|
5
|
+
"files": {
|
|
6
|
+
"package.json": "{\n \"name\": \"supabase-installed-customer\",\n \"private\": true,\n \"type\": \"module\",\n \"dependencies\": {\n \"pg\": \"8.16.3\"\n }\n}\n",
|
|
7
|
+
".env.example": "SUPABASE_DB_URL=\n",
|
|
8
|
+
"app.mjs": "import pg from 'pg';\nimport assert from 'node:assert/strict';\nimport {writeFileSync} from 'node:fs';\nassert.ok(process.env.VOLTER_WORLD,'run through the World');\nassert.ok(process.env.SUPABASE_DB_URL,'the World must issue the database URL');\nconst client=new pg.Client({connectionString:process.env.SUPABASE_DB_URL});\nawait client.connect();\ntry {\n if(process.argv[2]!=='resumed'){\n await client.query('CREATE TABLE IF NOT EXISTS catalog_signup (id text PRIMARY KEY, email text NOT NULL)');\n await client.query('INSERT INTO catalog_signup (id,email) VALUES ($1,$2) ON CONFLICT (id) DO NOTHING',['new-user','new-user@example.test']);\n }\n const {rows}=await client.query('SELECT id,email FROM catalog_signup WHERE id=$1',['new-user']);\n assert.deepEqual(rows,[{id:'new-user',email:'new-user@example.test'}]);\n const receipt={passed:true,phase:process.argv[2]??'first-boot',scope:'unchanged node-postgres client; project credential issuance and native PostgreSQL schema, insert and readback; no Supabase HTTP data-plane claim',};\n writeFileSync(`first-use-${receipt.phase}.json`,JSON.stringify(receipt,null,2)+'\\n');console.log(JSON.stringify(receipt));\n} finally {await client.end();}\n"
|
|
9
|
+
},
|
|
10
|
+
"run": [
|
|
11
|
+
"node",
|
|
12
|
+
"app.mjs"
|
|
13
|
+
],
|
|
14
|
+
"retention": {
|
|
15
|
+
"readback": [
|
|
16
|
+
"node",
|
|
17
|
+
"app.mjs",
|
|
18
|
+
"resumed"
|
|
19
|
+
]
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"source": "https://www.npmjs.com/package/@tavily/core/v/0.7.14",
|
|
4
|
+
"about": "Seed an explicitly synthetic World page through its existing door, then search and extract through the official SDK. No public web or model runs.",
|
|
5
|
+
"files": {
|
|
6
|
+
"package.json": "{\n \"name\": \"tavily-installed-customer\",\n \"private\": true,\n \"type\": \"module\",\n \"dependencies\": {\n \"@tavily/core\": \"0.7.14\"\n }\n}\n",
|
|
7
|
+
".env.example": "TAVILY_API_KEY=\n",
|
|
8
|
+
"workflow.mjs": "import assert from 'node:assert/strict';\nimport { tavily } from '@tavily/core';\nassert.ok(process.env.VOLTER_WORLD);\nconst page = { url: 'https://schedule.example/yoga', title: 'Yoga schedule', content: 'Yoga on Tuesdays at 18:00.' };\nconst setup = await fetch('https://api.tavily.com/_twin/pages', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(page) });\nassert.equal(setup.status, 201);\nconst client = tavily({ apiKey: process.env.TAVILY_API_KEY });\nconst search = await client.search('Yoga schedule', { includeAnswer: true });\nassert.equal(search.results[0].url, page.url);\nassert.match(search.answer, /\\[twin-stub\\]/);\nconst extract = await client.extract([page.url]);\nassert.equal(extract.results[0].url, page.url);\nassert.match(extract.results[0].rawContent, /Yoga on Tuesdays/);\nconsole.log('Official Tavily SDK search and extract over the synthetic World corpus passed');\n"
|
|
9
|
+
},
|
|
10
|
+
"run": [
|
|
11
|
+
"node",
|
|
12
|
+
"workflow.mjs"
|
|
13
|
+
],
|
|
14
|
+
"retention": {
|
|
15
|
+
"none": "Search and extraction create no stored Tavily resource; the pages door supplies synthetic World corpus, not vendor state."
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"source": "https://www.npmjs.com/package/@upstash/redis/v/1.38.2",
|
|
4
|
+
"about": "Store and read a profile and counter through the Redis SDK, then inspect both after restart.",
|
|
5
|
+
"files": {
|
|
6
|
+
"package.json": "{\n \"name\": \"upstash-installed-customer\",\n \"private\": true,\n \"type\": \"module\",\n \"dependencies\": {\n \"@upstash/redis\": \"1.38.2\"\n }\n}\n",
|
|
7
|
+
".env.example": "UPSTASH_REDIS_REST_URL=\nUPSTASH_REDIS_REST_TOKEN=\n",
|
|
8
|
+
"resume.mjs": "import assert from 'node:assert/strict';\nimport { writeFileSync } from 'node:fs';\nimport { Redis } from '@upstash/redis';\nassert.ok(process.env.VOLTER_WORLD);\nconst redis = Redis.fromEnv();\nassert.deepEqual(await redis.get('first-user:profile'), { email: 'first-user@example.test', plan: 'free' });\nassert.equal(await redis.get('first-user:visits'), 1);\nconst receipt = { passed: true, scope: 'down/up retains Redis data and throwaway credentials remain usable', };\nwriteFileSync('resume-receipt.json', JSON.stringify(receipt, null, 2) + '\\n');\nconsole.log(JSON.stringify(receipt));\n",
|
|
9
|
+
"app.mjs": "import assert from 'node:assert/strict';\nimport { writeFileSync } from 'node:fs';\nimport { Redis } from '@upstash/redis';\nassert.ok(process.env.VOLTER_WORLD);\nconst redis = Redis.fromEnv();\nconst value = { email: 'first-user@example.test', plan: 'free' };\nassert.equal(await redis.set('first-user:profile', value), 'OK');\nassert.deepEqual(await redis.get('first-user:profile'), value);\nassert.equal(await redis.incr('first-user:visits'), 1);\nassert.equal(await redis.get('first-user:missing'), null);\nconst receipt = { passed: true, scope: 'fresh published CLI init/up/run/log/down; unchanged official Redis SDK set/get/incr/missing read', };\nwriteFileSync('first-use-receipt.json', JSON.stringify(receipt, null, 2) + '\\n');\nconsole.log(JSON.stringify(receipt));\n"
|
|
10
|
+
},
|
|
11
|
+
"run": [
|
|
12
|
+
"node",
|
|
13
|
+
"app.mjs"
|
|
14
|
+
],
|
|
15
|
+
"retention": {
|
|
16
|
+
"readback": [
|
|
17
|
+
"node",
|
|
18
|
+
"resume.mjs"
|
|
19
|
+
]
|
|
20
|
+
}
|
|
21
|
+
}
|
package/dist/src/conformance.js
CHANGED
|
@@ -467,6 +467,8 @@ async function clientCases(pack, scratch) {
|
|
|
467
467
|
child.on('close', (code) => { clearTimeout(timer); resolve(code === 0 ? text : `${text}\n${JSON.stringify({ id: 'runner', asks: 'the cases run', failures: [`node exited ${code}: ${errors.trim().split('\n').slice(0, 12).join(' ')}`] })}`); });
|
|
468
468
|
});
|
|
469
469
|
const results = out.split('\n').filter((l) => l.startsWith('{')).map((l) => JSON.parse(l));
|
|
470
|
+
if (results.length === 0)
|
|
471
|
+
return { failures: [`${vendor} client runner returned no case results; there is no SDK execution evidence`] };
|
|
470
472
|
return { failures: results.flatMap((r) => r.failures.map((f) => `${r.id} (${r.asks}): ${f}`)), note: `${results.length} case(s) through the vendor's client` };
|
|
471
473
|
}
|
|
472
474
|
finally {
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
export type ConsumerRecipe = {
|
|
2
|
+
schemaVersion: 1;
|
|
3
|
+
source: string;
|
|
4
|
+
about: string;
|
|
5
|
+
files: Record<string, string>;
|
|
6
|
+
clock?: {
|
|
7
|
+
at: string;
|
|
8
|
+
advanceAfterRun?: string;
|
|
9
|
+
};
|
|
10
|
+
run: string[];
|
|
11
|
+
retention: {
|
|
12
|
+
readback: string[];
|
|
13
|
+
} | {
|
|
14
|
+
none: string;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
export type ConsumerOptions = {
|
|
18
|
+
appDir: string;
|
|
19
|
+
cli: string;
|
|
20
|
+
artifactIntegrity: string;
|
|
21
|
+
};
|
|
22
|
+
/** Bind behavior inputs on both source and packed layouts; compiled outputs and score caches are not inputs. */
|
|
23
|
+
export declare function consumerSourceDigest(pack: string): string;
|
|
24
|
+
/** A pack supplies its own entry journey; older immutable releases use a versioned standard fixture. */
|
|
25
|
+
export declare function consumerRecipe(vendor: string, packDir?: string): ConsumerRecipe;
|
|
26
|
+
/** Materialize only a new caller-owned app. Normal dependency installation happens before offline assessment. */
|
|
27
|
+
export declare function prepareConsumerApp(packDir: string, appDir: string): {
|
|
28
|
+
recipeSha256: string;
|
|
29
|
+
dependencies: Record<string, string>;
|
|
30
|
+
};
|
|
31
|
+
export declare function runConsumerWorkflow(packDir: string, options: ConsumerOptions): Promise<{
|
|
32
|
+
node: string;
|
|
33
|
+
at: string;
|
|
34
|
+
retentionNotApplicable?: string | undefined;
|
|
35
|
+
measured: boolean;
|
|
36
|
+
passed: boolean;
|
|
37
|
+
scope: string;
|
|
38
|
+
package: any;
|
|
39
|
+
version: any;
|
|
40
|
+
integrity: string;
|
|
41
|
+
tools: {
|
|
42
|
+
'@volter/world': string;
|
|
43
|
+
'@volter/world-core': string;
|
|
44
|
+
'@volter/world-runtime': string;
|
|
45
|
+
};
|
|
46
|
+
sourceInputsSha256: string;
|
|
47
|
+
recipeSha256: string;
|
|
48
|
+
fixture: string;
|
|
49
|
+
appDir: string;
|
|
50
|
+
appName: string;
|
|
51
|
+
commands: {
|
|
52
|
+
label: string;
|
|
53
|
+
argv: string[];
|
|
54
|
+
exitCode: number | null;
|
|
55
|
+
stdout: string;
|
|
56
|
+
stderr: string;
|
|
57
|
+
}[];
|
|
58
|
+
failures: string[];
|
|
59
|
+
teardownVerified: boolean;
|
|
60
|
+
retainedReadback: boolean;
|
|
61
|
+
clock: {
|
|
62
|
+
at: string;
|
|
63
|
+
advanceAfterRun?: string;
|
|
64
|
+
} | {
|
|
65
|
+
mode: string;
|
|
66
|
+
};
|
|
67
|
+
}>;
|