@linzumi/cli 1.0.116 → 1.0.118
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 +1 -1
- package/dist/index.js +359 -359
- package/package.json +2 -1
- package/scripts/build-onboarding-demo-evidence.mjs +186 -0
- package/scripts/build-onboarding-discovery-parity-oracle.mjs +380 -0
- package/scripts/build-onboarding-flow-parity-oracle.mjs +562 -0
- package/scripts/build-onboarding-gateway-parity-oracle.mjs +313 -0
- package/scripts/build-onboarding-support-parity-oracle.mjs +484 -0
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
// Spec: kandan/plans/2026-07-10-compute-nodes-rescript-commander-zero-ts-program.md
|
|
2
|
+
// (M3 cluster 13, onboarding - the gateway slice).
|
|
3
|
+
// Relationship: Builds the TS-side PARITY ORACLE for the onboarding
|
|
4
|
+
// gateway of the ReScript commander port, the sibling of
|
|
5
|
+
// build-auth-parity-oracle.mjs (cluster 3). The oracle bundles the REAL TS
|
|
6
|
+
// modules this slice ports - signupServerClient.ts's mission-control legs
|
|
7
|
+
// (completeMissionControl / startMissionControlTasks) and oauth.ts's
|
|
8
|
+
// browser loopback-callback flow (oauthCallbackTimeoutMs,
|
|
9
|
+
// oauthCallbackHost, isPrivateCallbackHost, authorizationUrl,
|
|
10
|
+
// exchangeCodeForToken, oauthResultHtml, escapeUrlForWindowsStart,
|
|
11
|
+
// acquireLocalRunnerTokenDetails, fetchLocalRunnerStartTarget) - behind
|
|
12
|
+
// the same one-shot stdin/stdout batch driver: a JSON array of cases in, a
|
|
13
|
+
// JSON array of results out.
|
|
14
|
+
//
|
|
15
|
+
// FLOW cases carry a `serviceUrl`/`httpBaseUrl` pointing at the ReScript
|
|
16
|
+
// parity suite's scripted auth HTTP server (ScriptedAuthServer.res), so
|
|
17
|
+
// the REAL TS flow functions run their real fetch legs against the same
|
|
18
|
+
// scripted wire the ReScript port runs against - outcome AND recorded
|
|
19
|
+
// wire-transcript equivalence is asserted on both sides by
|
|
20
|
+
// OnboardingGatewayParityConformance.res.
|
|
21
|
+
//
|
|
22
|
+
// The `browserAcquire` op is the REAL end-to-end loopback leg: it runs
|
|
23
|
+
// acquireLocalRunnerTokenDetails with openAuthorizationUrl injected as a
|
|
24
|
+
// deterministic scripted browser (the same plain-data call script the
|
|
25
|
+
// ReScript suite drives), records every rendered callback page
|
|
26
|
+
// (status + HTML bytes) plus the shape of the authorization URL, and lets
|
|
27
|
+
// the flow's exchange hit the scripted token endpoint. The random state
|
|
28
|
+
// nonce and ephemeral callback port never ride the comparison surface
|
|
29
|
+
// (the conformance normalizes the port; the state is only ever echoed).
|
|
30
|
+
//
|
|
31
|
+
// Determinism: no clocks are consumed beyond timeouts injected per case.
|
|
32
|
+
// SECRETS: the oracle only ever sees the conformance suite's synthetic
|
|
33
|
+
// tokens/codes; nothing here logs case payloads.
|
|
34
|
+
import { dirname, join } from 'node:path';
|
|
35
|
+
import { fileURLToPath } from 'node:url';
|
|
36
|
+
import { build } from 'esbuild';
|
|
37
|
+
|
|
38
|
+
const packageRoot = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
39
|
+
|
|
40
|
+
const driverSource = `
|
|
41
|
+
import { createSignupServerClient } from './src/signupServerClient';
|
|
42
|
+
import {
|
|
43
|
+
acquireLocalRunnerTokenDetails,
|
|
44
|
+
authorizationUrl,
|
|
45
|
+
escapeUrlForWindowsStart,
|
|
46
|
+
exchangeCodeForToken,
|
|
47
|
+
fetchLocalRunnerStartTarget,
|
|
48
|
+
isPrivateCallbackHost,
|
|
49
|
+
oauthCallbackHost,
|
|
50
|
+
oauthCallbackTimeoutMs,
|
|
51
|
+
oauthResultHtml,
|
|
52
|
+
} from './src/oauth';
|
|
53
|
+
|
|
54
|
+
// --- Shared plumbing (the cluster 3 conventions) -----------------------------------
|
|
55
|
+
|
|
56
|
+
function outcome(run) {
|
|
57
|
+
try {
|
|
58
|
+
const value = run();
|
|
59
|
+
return value === undefined ? { defined: false } : { defined: true, value };
|
|
60
|
+
} catch (error) {
|
|
61
|
+
return errorOutcome(error);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function outcomeAsync(run) {
|
|
66
|
+
try {
|
|
67
|
+
const value = await run();
|
|
68
|
+
return value === undefined ? { defined: false } : { defined: true, value };
|
|
69
|
+
} catch (error) {
|
|
70
|
+
return errorOutcome(error);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function errorOutcome(error) {
|
|
75
|
+
const shaped = {
|
|
76
|
+
threw: true,
|
|
77
|
+
message: error instanceof Error ? error.message : String(error),
|
|
78
|
+
};
|
|
79
|
+
if (error instanceof Error && error.name === 'SignupServerError') {
|
|
80
|
+
shaped.name = error.name;
|
|
81
|
+
shaped.status = error.status;
|
|
82
|
+
shaped.code = error.code;
|
|
83
|
+
}
|
|
84
|
+
return shaped;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// --- Pure transforms -----------------------------------------------------------------
|
|
88
|
+
|
|
89
|
+
function handleCallbackTimeoutMs(testCase) {
|
|
90
|
+
return outcome(() =>
|
|
91
|
+
oauthCallbackTimeoutMs(testCase.override ?? undefined, testCase.env ?? {})
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function handleCallbackHost(testCase) {
|
|
96
|
+
return outcome(() =>
|
|
97
|
+
oauthCallbackHost(testCase.kandanUrl, testCase.explicitHost ?? undefined)
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function handlePrivateCallbackHost(testCase) {
|
|
102
|
+
return outcome(() => isPrivateCallbackHost(testCase.host));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function handleAuthorizationUrl(testCase) {
|
|
106
|
+
return outcome(() =>
|
|
107
|
+
authorizationUrl({
|
|
108
|
+
httpBaseUrl: testCase.httpBaseUrl,
|
|
109
|
+
redirectUri: testCase.redirectUri,
|
|
110
|
+
state: testCase.state,
|
|
111
|
+
workspaceSlug: testCase.workspaceSlug ?? undefined,
|
|
112
|
+
channelSlug: testCase.channelSlug ?? undefined,
|
|
113
|
+
onboarding: testCase.onboarding ?? undefined,
|
|
114
|
+
purpose: testCase.purpose ?? undefined,
|
|
115
|
+
})
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function handleResultHtml(testCase) {
|
|
120
|
+
return outcome(() =>
|
|
121
|
+
oauthResultHtml({
|
|
122
|
+
title: testCase.title,
|
|
123
|
+
body: testCase.body,
|
|
124
|
+
status: testCase.status,
|
|
125
|
+
})
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function handleWindowsStartUrl(testCase) {
|
|
130
|
+
return outcome(() => escapeUrlForWindowsStart(testCase.url));
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// --- HTTP flow legs (against the scripted auth server) ----------------------------------
|
|
134
|
+
|
|
135
|
+
async function handleMissionControlComplete(testCase) {
|
|
136
|
+
const client = createSignupServerClient({ serviceUrl: testCase.serviceUrl });
|
|
137
|
+
return outcomeAsync(() =>
|
|
138
|
+
client.completeMissionControl({
|
|
139
|
+
accessToken: testCase.accessToken,
|
|
140
|
+
workspaceName: testCase.workspaceName ?? undefined,
|
|
141
|
+
selectedProjectPaths: testCase.selectedProjectPaths,
|
|
142
|
+
starterProjectPath: testCase.starterProjectPath ?? undefined,
|
|
143
|
+
selectedTasks: testCase.selectedTasks,
|
|
144
|
+
})
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async function handleMissionControlStartTasks(testCase) {
|
|
149
|
+
const client = createSignupServerClient({ serviceUrl: testCase.serviceUrl });
|
|
150
|
+
return outcomeAsync(() =>
|
|
151
|
+
client.startMissionControlTasks({
|
|
152
|
+
accessToken: testCase.accessToken,
|
|
153
|
+
workspaceSlug: testCase.workspaceSlug,
|
|
154
|
+
officeChannelSlug: testCase.officeChannelSlug,
|
|
155
|
+
runnerId: testCase.runnerId,
|
|
156
|
+
starterProjectPath: testCase.starterProjectPath,
|
|
157
|
+
threads: testCase.threads,
|
|
158
|
+
model: testCase.model ?? undefined,
|
|
159
|
+
reasoningEffort: testCase.reasoningEffort ?? undefined,
|
|
160
|
+
})
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
async function handleFetchStartTarget(testCase) {
|
|
165
|
+
return outcomeAsync(() =>
|
|
166
|
+
fetchLocalRunnerStartTarget({
|
|
167
|
+
kandanUrl: testCase.kandanUrl,
|
|
168
|
+
accessToken: testCase.accessToken,
|
|
169
|
+
})
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
async function handleExchangeCode(testCase) {
|
|
174
|
+
return outcomeAsync(() =>
|
|
175
|
+
exchangeCodeForToken({
|
|
176
|
+
httpBaseUrl: testCase.httpBaseUrl,
|
|
177
|
+
code: testCase.code,
|
|
178
|
+
redirectUri: testCase.redirectUri,
|
|
179
|
+
})
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// --- The end-to-end browser loopback leg -------------------------------------------------
|
|
184
|
+
|
|
185
|
+
// The scripted browser: for each call in the plain-data script, dial the
|
|
186
|
+
// advertised redirect_uri with the scripted query ("$STATE" substitutes
|
|
187
|
+
// the live state nonce) and record the rendered page. This loop is
|
|
188
|
+
// mirrored byte-for-byte by the ReScript conformance's opener.
|
|
189
|
+
async function runScriptedBrowser(authorizeUrl, calls, pages, openedShapes) {
|
|
190
|
+
const parsed = new URL(authorizeUrl);
|
|
191
|
+
const redirectUri = parsed.searchParams.get('redirect_uri') ?? '';
|
|
192
|
+
const state = parsed.searchParams.get('state') ?? '';
|
|
193
|
+
openedShapes.push({
|
|
194
|
+
origin: parsed.origin,
|
|
195
|
+
pathname: parsed.pathname,
|
|
196
|
+
keys: [...parsed.searchParams.keys()],
|
|
197
|
+
workspace: parsed.searchParams.get('workspace'),
|
|
198
|
+
channel: parsed.searchParams.get('channel'),
|
|
199
|
+
onboarding: parsed.searchParams.get('onboarding'),
|
|
200
|
+
purpose: parsed.searchParams.get('purpose'),
|
|
201
|
+
redirectHost: new URL(redirectUri).hostname,
|
|
202
|
+
redirectPath: new URL(redirectUri).pathname,
|
|
203
|
+
});
|
|
204
|
+
for (const call of calls) {
|
|
205
|
+
const target = new URL(redirectUri);
|
|
206
|
+
for (const [key, value] of call) {
|
|
207
|
+
target.searchParams.set(key, value === '$STATE' ? state : value);
|
|
208
|
+
}
|
|
209
|
+
try {
|
|
210
|
+
const response = await fetch(target);
|
|
211
|
+
pages.push({ status: response.status, body: await response.text() });
|
|
212
|
+
} catch (error) {
|
|
213
|
+
pages.push({
|
|
214
|
+
status: -1,
|
|
215
|
+
body: error instanceof Error ? error.message : String(error),
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
async function handleBrowserAcquire(testCase) {
|
|
222
|
+
const pages = [];
|
|
223
|
+
const openedShapes = [];
|
|
224
|
+
const result = await outcomeAsync(() =>
|
|
225
|
+
acquireLocalRunnerTokenDetails({
|
|
226
|
+
kandanUrl: testCase.kandanUrl,
|
|
227
|
+
workspaceSlug: testCase.workspaceSlug ?? undefined,
|
|
228
|
+
channelSlug: testCase.channelSlug ?? undefined,
|
|
229
|
+
onboarding: testCase.onboarding ?? undefined,
|
|
230
|
+
purpose: testCase.purpose ?? undefined,
|
|
231
|
+
callbackHost: testCase.callbackHost ?? undefined,
|
|
232
|
+
waitForTokenTimeoutMs: testCase.waitForTokenTimeoutMs ?? undefined,
|
|
233
|
+
openAuthorizationUrl: (authorizeUrl) =>
|
|
234
|
+
runScriptedBrowser(authorizeUrl, testCase.calls ?? [], pages, openedShapes),
|
|
235
|
+
})
|
|
236
|
+
);
|
|
237
|
+
return { result, openedShapes, pages };
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// --- Dispatch --------------------------------------------------------------------------------
|
|
241
|
+
|
|
242
|
+
async function handle(testCase) {
|
|
243
|
+
switch (testCase.op) {
|
|
244
|
+
case 'callbackTimeoutMs':
|
|
245
|
+
return handleCallbackTimeoutMs(testCase);
|
|
246
|
+
case 'callbackHost':
|
|
247
|
+
return handleCallbackHost(testCase);
|
|
248
|
+
case 'privateCallbackHost':
|
|
249
|
+
return handlePrivateCallbackHost(testCase);
|
|
250
|
+
case 'authorizationUrl':
|
|
251
|
+
return handleAuthorizationUrl(testCase);
|
|
252
|
+
case 'resultHtml':
|
|
253
|
+
return handleResultHtml(testCase);
|
|
254
|
+
case 'windowsStartUrl':
|
|
255
|
+
return handleWindowsStartUrl(testCase);
|
|
256
|
+
case 'missionControlComplete':
|
|
257
|
+
return handleMissionControlComplete(testCase);
|
|
258
|
+
case 'missionControlStartTasks':
|
|
259
|
+
return handleMissionControlStartTasks(testCase);
|
|
260
|
+
case 'fetchStartTarget':
|
|
261
|
+
return handleFetchStartTarget(testCase);
|
|
262
|
+
case 'exchangeCode':
|
|
263
|
+
return handleExchangeCode(testCase);
|
|
264
|
+
case 'browserAcquire':
|
|
265
|
+
return handleBrowserAcquire(testCase);
|
|
266
|
+
default:
|
|
267
|
+
return { threw: true, message: 'unknown op ' + String(testCase.op) };
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
let stdin = '';
|
|
272
|
+
process.stdin.setEncoding('utf8');
|
|
273
|
+
for await (const chunk of process.stdin) {
|
|
274
|
+
stdin += chunk;
|
|
275
|
+
}
|
|
276
|
+
const cases = JSON.parse(stdin);
|
|
277
|
+
const results = [];
|
|
278
|
+
// Sequential on purpose: the scripted server's per-route response queues
|
|
279
|
+
// assume one case at a time.
|
|
280
|
+
for (const testCase of cases) {
|
|
281
|
+
results.push(await handle(testCase));
|
|
282
|
+
}
|
|
283
|
+
process.stdout.write(JSON.stringify(results));
|
|
284
|
+
`;
|
|
285
|
+
|
|
286
|
+
// Renamed banner import (the build-differential-entry.mjs convention): this
|
|
287
|
+
// bundle keeps source-level identifiers and the commander sources import
|
|
288
|
+
// createRequire themselves - a bare banner name would collide.
|
|
289
|
+
const banner = {
|
|
290
|
+
js: "import { createRequire as __onboardingGatewayOracleCreateRequire } from 'node:module';\nconst require = __onboardingGatewayOracleCreateRequire(import.meta.url);",
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
await build({
|
|
294
|
+
stdin: {
|
|
295
|
+
contents: driverSource,
|
|
296
|
+
resolveDir: packageRoot,
|
|
297
|
+
sourcefile: 'onboarding-gateway-parity-driver.ts',
|
|
298
|
+
loader: 'ts',
|
|
299
|
+
},
|
|
300
|
+
banner,
|
|
301
|
+
bundle: true,
|
|
302
|
+
platform: 'node',
|
|
303
|
+
target: 'node20',
|
|
304
|
+
format: 'esm',
|
|
305
|
+
outfile: join(packageRoot, '.differential/onboarding-gateway-parity-oracle.mjs'),
|
|
306
|
+
minify: false,
|
|
307
|
+
sourcemap: false,
|
|
308
|
+
legalComments: 'none',
|
|
309
|
+
// oauth.ts pulls runnerLogger (and its graph); the same runtime externals
|
|
310
|
+
// as the differential entry build stay external (installed in this
|
|
311
|
+
// package's node_modules; the oracle only exercises the exports above).
|
|
312
|
+
external: ['ws', 'undici', 'blessed', '@anthropic-ai/claude-agent-sdk'],
|
|
313
|
+
});
|