@volter/twin-standard 1.0.29 → 1.0.31
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/src/archive-source.d.ts +13 -0
- package/dist/src/archive-source.js +176 -0
- package/dist/src/check-sources.d.ts +19 -2
- package/dist/src/check-sources.js +95 -37
- package/dist/src/cli.js +52 -9
- package/dist/src/clients/ai-gateway.d.ts +1 -0
- package/dist/src/clients/ai-gateway.js +3 -0
- package/dist/src/clients/anthropic-messages.d.ts +10 -0
- package/dist/src/clients/anthropic-messages.js +52 -0
- package/dist/src/clients/anthropic.d.ts +1 -0
- package/dist/src/clients/anthropic.js +3 -0
- package/dist/src/clients/aws.d.ts +2 -0
- package/dist/src/clients/aws.js +137 -0
- package/dist/src/clients/cerebras.d.ts +1 -0
- package/dist/src/clients/cerebras.js +3 -0
- package/dist/src/clients/clerk.d.ts +2 -0
- package/dist/src/clients/clerk.js +99 -0
- package/dist/src/clients/cloudflare.d.ts +2 -0
- package/dist/src/clients/cloudflare.js +86 -0
- package/dist/src/clients/elevenlabs.d.ts +2 -0
- package/dist/src/clients/elevenlabs.js +39 -0
- package/dist/src/clients/gemini.d.ts +2 -0
- package/dist/src/clients/gemini.js +92 -0
- package/dist/src/clients/github.d.ts +2 -0
- package/dist/src/clients/github.js +71 -0
- package/dist/src/clients/groq.d.ts +1 -0
- package/dist/src/clients/groq.js +3 -0
- package/dist/src/clients/harness.d.ts +36 -0
- package/dist/src/clients/harness.js +74 -0
- package/dist/src/clients/merge.d.ts +1 -0
- package/dist/src/clients/merge.js +8 -0
- package/dist/src/clients/openai-compatible.d.ts +9 -0
- package/dist/src/clients/openai-compatible.js +51 -0
- package/dist/src/clients/openai.d.ts +2 -0
- package/dist/src/clients/openai.js +65 -0
- package/dist/src/clients/openrouter.d.ts +1 -0
- package/dist/src/clients/openrouter.js +3 -0
- package/dist/src/clients/perplexity.d.ts +1 -0
- package/dist/src/clients/perplexity.js +3 -0
- package/dist/src/clients/planetscale.d.ts +2 -0
- package/dist/src/clients/planetscale.js +109 -0
- package/dist/src/clients/posthog.d.ts +2 -0
- package/dist/src/clients/posthog.js +145 -0
- package/dist/src/clients/run.d.ts +1 -0
- package/dist/src/clients/run.js +25 -0
- package/dist/src/clients/sentry.d.ts +2 -0
- package/dist/src/clients/sentry.js +167 -0
- package/dist/src/clients/slack.d.ts +2 -0
- package/dist/src/clients/slack.js +107 -0
- package/dist/src/clients/stripe.d.ts +2 -0
- package/dist/src/clients/stripe.js +161 -0
- package/dist/src/clients/tinybird.d.ts +2 -0
- package/dist/src/clients/tinybird.js +71 -0
- package/dist/src/clients/tunnel.d.ts +2 -0
- package/dist/src/clients/tunnel.js +99 -0
- package/dist/src/clients/upstash.d.ts +2 -0
- package/dist/src/clients/upstash.js +143 -0
- package/dist/src/clients/volteridentity.d.ts +2 -0
- package/dist/src/clients/volteridentity.js +128 -0
- package/dist/src/clients/xai.d.ts +2 -0
- package/dist/src/clients/xai.js +23 -0
- package/dist/src/conformance.d.ts +33 -0
- package/dist/src/conformance.js +520 -0
- package/dist/src/derive.js +113 -22
- package/dist/src/gate.js +24 -17
- package/dist/src/index.d.ts +5 -3
- package/dist/src/index.js +5 -3
- package/dist/src/lanes.d.ts +2 -0
- package/dist/src/lanes.js +7 -0
- package/dist/src/p3-rules.js +0 -2
- package/dist/src/pack-files.d.ts +2 -0
- package/dist/src/pack-files.js +4 -0
- package/dist/src/protocol-3.d.ts +1 -0
- package/dist/src/protocol-3.js +83 -24
- package/dist/src/published.d.ts +6 -0
- package/dist/src/published.js +65 -11
- package/dist/src/spec-documents.js +2 -1
- package/dist/src/spec-ir-client.d.ts +5 -1
- package/dist/src/spec-ir-client.js +12 -2
- package/dist/src/spec-ir.d.ts +7 -2
- package/dist/src/spec-ir.js +42 -10
- package/dist/src/verdict.d.ts +14 -0
- package/dist/src/verdict.js +30 -0
- package/dist/src/walk/behavior-journey.d.ts +47 -0
- package/dist/src/walk/behavior-journey.js +1138 -0
- package/dist/src/walk/git-client.d.ts +26 -0
- package/dist/src/walk/git-client.js +139 -0
- package/dist/src/walk/journey-kit.d.ts +445 -0
- package/dist/src/walk/journey-kit.js +743 -0
- package/dist/src/walk/shape.d.ts +54 -0
- package/dist/src/walk/shape.js +210 -0
- package/dist/src/walk/sse-example.d.ts +2 -0
- package/dist/src/walk/sse-example.js +32 -0
- package/dist/src/walk/vendor-fetch.d.ts +20 -0
- package/dist/src/walk/vendor-fetch.js +92 -0
- package/dist/src/walk/walk-database.d.ts +12 -0
- package/dist/src/walk/walk-database.js +96 -0
- package/dist/src/walk/xml-view.d.ts +2 -0
- package/dist/src/walk/xml-view.js +55 -0
- package/package.json +39 -3
- package/src/archive-source.ts +141 -0
- package/src/check-sources.ts +83 -33
- package/src/cli.ts +40 -8
- package/src/clients/ai-gateway.ts +4 -0
- package/src/clients/anthropic-messages.ts +60 -0
- package/src/clients/anthropic.ts +4 -0
- package/src/clients/aws.ts +119 -0
- package/src/clients/cerebras.ts +4 -0
- package/src/clients/clerk.ts +97 -0
- package/src/clients/cloudflare.ts +80 -0
- package/src/clients/elevenlabs.ts +38 -0
- package/src/clients/gemini.ts +89 -0
- package/src/clients/github.ts +67 -0
- package/src/clients/groq.ts +4 -0
- package/src/clients/harness.ts +101 -0
- package/src/clients/merge.ts +9 -0
- package/src/clients/openai-compatible.ts +59 -0
- package/src/clients/openai.ts +66 -0
- package/src/clients/openrouter.ts +4 -0
- package/src/clients/perplexity.ts +4 -0
- package/src/clients/planetscale.ts +98 -0
- package/src/clients/posthog.ts +132 -0
- package/src/clients/run.ts +18 -0
- package/src/clients/sentry.ts +157 -0
- package/src/clients/slack.ts +98 -0
- package/src/clients/stripe.ts +129 -0
- package/src/clients/tinybird.ts +69 -0
- package/src/clients/tunnel.ts +79 -0
- package/src/clients/upstash.ts +137 -0
- package/src/clients/volteridentity.ts +108 -0
- package/src/clients/xai.ts +25 -0
- package/src/conformance.ts +446 -0
- package/src/derive.ts +87 -16
- package/src/gate.ts +22 -15
- package/src/index.ts +5 -3
- package/src/lanes.ts +7 -0
- package/src/p3-rules.ts +0 -2
- package/src/pack-files.ts +4 -0
- package/src/protocol-3.ts +77 -22
- package/src/published.ts +59 -11
- package/src/spec-documents.ts +2 -1
- package/src/spec-ir-client.ts +15 -4
- package/src/spec-ir.ts +43 -5
- package/src/verdict.ts +28 -0
- package/src/walk/behavior-journey.ts +806 -0
- package/src/walk/git-client.ts +138 -0
- package/src/walk/journey-kit.ts +858 -0
- package/src/walk/shape.ts +208 -0
- package/src/walk/sse-example.ts +25 -0
- package/src/walk/vendor-fetch.ts +80 -0
- package/src/walk/walk-database.ts +97 -0
- package/src/walk/xml-view.ts +44 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import type { GitFile } from './journey-kit.ts';
|
|
2
|
+
// The git client a journey's git steps are: what `git clone` and `git push` send over smart HTTP (protocol v0),
|
|
3
|
+
// built on the kernel's git library, so a life reaches a pack's git plane with a client's own bytes. It keeps no
|
|
4
|
+
// working copy between steps: a push fetches the ref's tip as a clone would have, writes its files on top and
|
|
5
|
+
// sends the ref command with a pack of what it made.
|
|
6
|
+
import { MemoryBlobStore, git } from '@volter/world-core/runtime';
|
|
7
|
+
|
|
8
|
+
type Fetch = (request: Request) => Promise<Response>;
|
|
9
|
+
export type GitAnswer = { status: number; body: unknown; text: string };
|
|
10
|
+
|
|
11
|
+
const ENC = new TextEncoder();
|
|
12
|
+
const DEC = new TextDecoder();
|
|
13
|
+
const cat = (...parts: Uint8Array[]): Uint8Array => git.concat(...parts);
|
|
14
|
+
|
|
15
|
+
/** The refs a smart-HTTP advertisement names, and the World's date the server answered at. */
|
|
16
|
+
async function advertised(fetch: Fetch, base: string, service: git.Service, headers: Record<string, string>): Promise<{ status: number; refs: Map<string, string>; date: number; text: string }> {
|
|
17
|
+
const res = await fetch(new Request(`${base}/info/refs?service=${service}`, { headers }));
|
|
18
|
+
const bytes = new Uint8Array(await res.arrayBuffer());
|
|
19
|
+
const refs = new Map<string, string>();
|
|
20
|
+
if (res.status !== 200) return { status: res.status, refs, date: 0, text: DEC.decode(bytes) };
|
|
21
|
+
const first = git.readPktLines(bytes);
|
|
22
|
+
for (const line of git.readPktLines(first.rest).lines) {
|
|
23
|
+
const [sha, name] = line.split('\0')[0]!.trim().split(' ');
|
|
24
|
+
if (sha && name && sha !== git.ZERO_SHA) refs.set(name, sha);
|
|
25
|
+
}
|
|
26
|
+
return { status: res.status, refs, date: Date.parse(res.headers.get('date') ?? '') || 0, text: '' };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Fetch `sha` and everything it reaches into `store`, as upload-pack sends it. */
|
|
30
|
+
async function fetchInto(fetch: Fetch, base: string, sha: string, store: git.GitObjectStore, headers: Record<string, string>): Promise<void> {
|
|
31
|
+
const body = cat(git.pktLine(`want ${sha} ofs-delta no-progress\n`), git.FLUSH, git.pktLine('done\n'));
|
|
32
|
+
const res = await fetch(new Request(`${base}/git-upload-pack`, { method: 'POST', headers: { ...headers, 'content-type': 'application/x-git-upload-pack-request' }, body: body as unknown as BodyInit }));
|
|
33
|
+
const bytes = new Uint8Array(await res.arrayBuffer());
|
|
34
|
+
const nak = git.readPktLines(bytes.subarray(0, 8));
|
|
35
|
+
if (!nak.lines[0]?.startsWith('NAK')) throw new Error(`upload-pack answered ${DEC.decode(bytes.subarray(0, 120)).trim()}`);
|
|
36
|
+
await git.readPack(bytes.subarray(8), store);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Every file under `tree`, by path. */
|
|
40
|
+
async function flatten(store: git.GitObjectStore, tree: string, prefix = '', out = new Map<string, { mode: string; sha: string }>()): Promise<Map<string, { mode: string; sha: string }>> {
|
|
41
|
+
const obj = await store.read(tree);
|
|
42
|
+
for (const e of obj ? git.decodeTree(obj.payload) : []) {
|
|
43
|
+
if (e.mode === '40000') await flatten(store, e.sha, `${prefix}${e.name}/`, out);
|
|
44
|
+
else out.set(`${prefix}${e.name}`, { mode: e.mode, sha: e.sha });
|
|
45
|
+
}
|
|
46
|
+
return out;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** The tree of `files`, nested by directory; each object it writes is pushed onto `made`. */
|
|
50
|
+
async function build(store: git.GitObjectStore, files: Map<string, { mode: string; sha: string }>, made: string[]): Promise<string> {
|
|
51
|
+
const here: git.TreeEntry[] = [];
|
|
52
|
+
const dirs = new Map<string, Map<string, { mode: string; sha: string }>>();
|
|
53
|
+
for (const [path, e] of files) {
|
|
54
|
+
const slash = path.indexOf('/');
|
|
55
|
+
if (slash < 0) { here.push({ mode: e.mode, name: path, sha: e.sha }); continue; }
|
|
56
|
+
const dir = path.slice(0, slash);
|
|
57
|
+
if (!dirs.has(dir)) dirs.set(dir, new Map());
|
|
58
|
+
dirs.get(dir)!.set(path.slice(slash + 1), e);
|
|
59
|
+
}
|
|
60
|
+
for (const [dir, inner] of dirs) here.push({ mode: '40000', name: dir, sha: await build(store, inner, made) });
|
|
61
|
+
const sha = await store.write('tree', git.encodeTree(git.sortTreeEntries(here)));
|
|
62
|
+
made.push(sha);
|
|
63
|
+
return sha;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** `git clone`: the ref's tip (HEAD by default) and the paths of its tree. */
|
|
67
|
+
export async function gitClone(fetch: Fetch, base: string, step: { ref?: string }, headers: Record<string, string>): Promise<GitAnswer> {
|
|
68
|
+
const ad = await advertised(fetch, base, 'git-upload-pack', headers);
|
|
69
|
+
if (ad.status !== 200) return { status: ad.status, body: ad.text, text: ad.text };
|
|
70
|
+
const ref = step.ref ?? 'HEAD';
|
|
71
|
+
const sha = ad.refs.get(ref);
|
|
72
|
+
if (!sha) { const text = `fatal: Remote branch ${ref} not found in upstream origin`; return { status: 404, body: text, text }; }
|
|
73
|
+
const store = new git.GitObjectStore(new MemoryBlobStore(), 'clone');
|
|
74
|
+
await fetchInto(fetch, base, sha, store, headers);
|
|
75
|
+
const commit = git.decodeCommit((await store.read(sha))!.payload);
|
|
76
|
+
const files = await flatten(store, commit.tree);
|
|
77
|
+
const body = { sha, message: commit.message.trim(), paths: [...files.keys()].sort(), refs: [...ad.refs.keys()].sort() };
|
|
78
|
+
return { status: 200, body, text: JSON.stringify(body) };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export type GitPush = {
|
|
82
|
+
ref: string;
|
|
83
|
+
/** a path's new content, or null to delete it */
|
|
84
|
+
files?: Record<string, GitFile>;
|
|
85
|
+
message?: string;
|
|
86
|
+
author?: string;
|
|
87
|
+
/** rewrite the tip instead of building on it (`git commit --amend`), which only a force push lands */
|
|
88
|
+
amend?: boolean;
|
|
89
|
+
/** delete the ref (`git push origin :<ref>`) */
|
|
90
|
+
delete?: boolean;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
/** `git push`: a commit of `files` on the ref's tip (a new ref starts from HEAD's), sent with the pack of what it made.
|
|
94
|
+
* The answer is the server's report: `unpack`, the ref's `result` (`ok`, or its `ng` reason) and the pushed `sha`. */
|
|
95
|
+
export async function gitPush(fetch: Fetch, base: string, step: GitPush, headers: Record<string, string>): Promise<GitAnswer> {
|
|
96
|
+
const ad = await advertised(fetch, base, 'git-receive-pack', headers);
|
|
97
|
+
if (ad.status !== 200) return { status: ad.status, body: ad.text, text: ad.text };
|
|
98
|
+
const old = ad.refs.get(step.ref) ?? git.ZERO_SHA;
|
|
99
|
+
const store = new git.GitObjectStore(new MemoryBlobStore(), 'push');
|
|
100
|
+
let next = git.ZERO_SHA;
|
|
101
|
+
const made: string[] = [];
|
|
102
|
+
if (!step.delete) {
|
|
103
|
+
const tip = old !== git.ZERO_SHA ? old : ad.refs.get('HEAD');
|
|
104
|
+
let files = new Map<string, { mode: string; sha: string }>();
|
|
105
|
+
let parents: string[] = [];
|
|
106
|
+
if (tip) {
|
|
107
|
+
await fetchInto(fetch, base, tip, store, headers);
|
|
108
|
+
const commit = git.decodeCommit((await store.read(tip))!.payload);
|
|
109
|
+
files = await flatten(store, commit.tree);
|
|
110
|
+
parents = step.amend ? commit.parents : [tip];
|
|
111
|
+
}
|
|
112
|
+
for (const [path, content] of Object.entries(step.files ?? {})) {
|
|
113
|
+
if (content === null) { files.delete(path); continue; }
|
|
114
|
+
if (typeof content === 'object' && content.mode === '160000') { files.set(path, { mode: content.mode, sha: content.sha }); continue; }
|
|
115
|
+
const sha = await store.write('blob', ENC.encode(typeof content === 'string' ? content : content.content));
|
|
116
|
+
made.push(sha);
|
|
117
|
+
files.set(path, { mode: typeof content === 'string' ? '100644' : content.mode, sha });
|
|
118
|
+
}
|
|
119
|
+
const tree = await build(store, files, made);
|
|
120
|
+
const [name, email] = (step.author ?? 'octocat <octocat@github.com>').split(/\s*<|>/);
|
|
121
|
+
// the commit is dated by the World's clock, as the server's Date header reads it
|
|
122
|
+
const who = { name: name!.trim(), email: (email ?? '').trim(), time: Math.floor(ad.date / 1000), tz: '+0000' };
|
|
123
|
+
next = await store.write('commit', git.encodeCommit({ tree, parents, author: who, committer: who, message: `${step.message ?? 'Update'}\n` }));
|
|
124
|
+
made.push(next);
|
|
125
|
+
}
|
|
126
|
+
const objects = await Promise.all([...new Set(made)].map(async (sha) => ({ ...(await store.read(sha))! })));
|
|
127
|
+
const command = git.pktLine(`${old} ${next} ${step.ref}\0report-status\n`);
|
|
128
|
+
const body = step.delete ? cat(command, git.FLUSH) : cat(command, git.FLUSH, await git.writePack(objects));
|
|
129
|
+
const res = await fetch(new Request(`${base}/git-receive-pack`, { method: 'POST', headers: { ...headers, 'content-type': 'application/x-git-receive-pack-request' }, body: body as unknown as BodyInit }));
|
|
130
|
+
const bytes = new Uint8Array(await res.arrayBuffer());
|
|
131
|
+
if (res.status !== 200) { const text = DEC.decode(bytes); return { status: res.status, body: text, text }; }
|
|
132
|
+
const lines = git.readPktLines(bytes).lines.map((l) => l.trim());
|
|
133
|
+
const unpack = lines.find((l) => l.startsWith('unpack '))?.slice(7) ?? '';
|
|
134
|
+
const verdict = lines.find((l) => l.startsWith('ok ') || l.startsWith('ng '));
|
|
135
|
+
const result = verdict?.startsWith('ok ') ? 'ok' : verdict?.slice(4 + step.ref.length).trim() ?? '';
|
|
136
|
+
const answer = { unpack, result, sha: next, before: old };
|
|
137
|
+
return { status: res.status, body: answer, text: JSON.stringify(answer) };
|
|
138
|
+
}
|