@dreamboard-games/cli 0.1.30-alpha.2 → 0.1.30-alpha.3
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/agent-verifier/agent-workspace-verifier.mjs +227 -0
- package/dist/agent-verifier/agent-workspace-verifier.mjs.map +1 -0
- package/dist/agent-verifier/chunk-3UKQVWLV.mjs +1744 -0
- package/dist/agent-verifier/chunk-3UKQVWLV.mjs.map +1 -0
- package/dist/agent-verifier/chunk-776W3UGV.mjs +167 -0
- package/dist/agent-verifier/chunk-776W3UGV.mjs.map +1 -0
- package/dist/agent-verifier/chunk-7WWGFAAU.mjs +729 -0
- package/dist/agent-verifier/chunk-7WWGFAAU.mjs.map +1 -0
- package/dist/agent-verifier/chunk-A64ZZUZV.mjs +261 -0
- package/dist/agent-verifier/chunk-A64ZZUZV.mjs.map +1 -0
- package/dist/agent-verifier/chunk-E7SSWJXJ.mjs +3137 -0
- package/dist/agent-verifier/chunk-E7SSWJXJ.mjs.map +1 -0
- package/dist/agent-verifier/chunk-F2DIOJJZ.mjs +302 -0
- package/dist/agent-verifier/chunk-F2DIOJJZ.mjs.map +1 -0
- package/dist/agent-verifier/chunk-G42BGGG2.mjs +70 -0
- package/dist/agent-verifier/chunk-G42BGGG2.mjs.map +1 -0
- package/dist/agent-verifier/chunk-H76MT5UR.mjs +57 -0
- package/dist/agent-verifier/chunk-H76MT5UR.mjs.map +1 -0
- package/dist/agent-verifier/chunk-HGMUAL33.mjs +39 -0
- package/dist/agent-verifier/chunk-HGMUAL33.mjs.map +1 -0
- package/dist/agent-verifier/chunk-IAYRNVUC.mjs +49 -0
- package/dist/agent-verifier/chunk-IAYRNVUC.mjs.map +1 -0
- package/dist/agent-verifier/chunk-JGT4P4UD.mjs +45 -0
- package/dist/agent-verifier/chunk-JGT4P4UD.mjs.map +1 -0
- package/dist/agent-verifier/chunk-LUZ7KE6H.mjs +79 -0
- package/dist/agent-verifier/chunk-LUZ7KE6H.mjs.map +1 -0
- package/dist/agent-verifier/chunk-NAK77WXW.mjs +767 -0
- package/dist/agent-verifier/chunk-NAK77WXW.mjs.map +1 -0
- package/dist/agent-verifier/chunk-O4YCPU7C.mjs +2913 -0
- package/dist/agent-verifier/chunk-O4YCPU7C.mjs.map +1 -0
- package/dist/agent-verifier/chunk-S34FRJHS.mjs +222 -0
- package/dist/agent-verifier/chunk-S34FRJHS.mjs.map +1 -0
- package/dist/agent-verifier/chunk-SH5JKYOB.mjs +226 -0
- package/dist/agent-verifier/chunk-SH5JKYOB.mjs.map +1 -0
- package/dist/agent-verifier/chunk-SKI2ESE5.mjs +44 -0
- package/dist/agent-verifier/chunk-SKI2ESE5.mjs.map +1 -0
- package/dist/agent-verifier/chunk-TAEQKBJB.mjs +107 -0
- package/dist/agent-verifier/chunk-TAEQKBJB.mjs.map +1 -0
- package/dist/agent-verifier/chunk-UIOLGH4A.mjs +150 -0
- package/dist/agent-verifier/chunk-UIOLGH4A.mjs.map +1 -0
- package/dist/agent-verifier/chunk-UIZNWRM6.mjs +2432 -0
- package/dist/agent-verifier/chunk-UIZNWRM6.mjs.map +1 -0
- package/dist/agent-verifier/chunk-VS573ERH.mjs +14523 -0
- package/dist/agent-verifier/chunk-VS573ERH.mjs.map +1 -0
- package/dist/agent-verifier/chunk-W3N3QJ4V.mjs +624 -0
- package/dist/agent-verifier/chunk-W3N3QJ4V.mjs.map +1 -0
- package/dist/agent-verifier/chunk-XGWCY624.mjs +185 -0
- package/dist/agent-verifier/chunk-XGWCY624.mjs.map +1 -0
- package/dist/agent-verifier/chunk-XQXDOBYB.mjs +382 -0
- package/dist/agent-verifier/chunk-XQXDOBYB.mjs.map +1 -0
- package/dist/agent-verifier/chunk-YE7UAO3T.mjs +129 -0
- package/dist/agent-verifier/chunk-YE7UAO3T.mjs.map +1 -0
- package/dist/agent-verifier/chunk-ZEELHSY3.mjs +20 -0
- package/dist/agent-verifier/chunk-ZEELHSY3.mjs.map +1 -0
- package/dist/agent-verifier/compile-TEQVA46V.mjs +312 -0
- package/dist/agent-verifier/compile-TEQVA46V.mjs.map +1 -0
- package/dist/agent-verifier/global-config-Y2NTSK4R.mjs +18 -0
- package/dist/agent-verifier/global-config-Y2NTSK4R.mjs.map +1 -0
- package/dist/agent-verifier/keychain-backend-SPQWGKZN.mjs +135 -0
- package/dist/agent-verifier/keychain-backend-SPQWGKZN.mjs.map +1 -0
- package/dist/agent-verifier/local-files-JFOQQZDL.mjs +45 -0
- package/dist/agent-verifier/local-files-JFOQQZDL.mjs.map +1 -0
- package/dist/agent-verifier/local-typecheck-XVGWI75X.mjs +10 -0
- package/dist/agent-verifier/local-typecheck-XVGWI75X.mjs.map +1 -0
- package/dist/agent-verifier/materialize-workspace-ZAVGQQSF.mjs +89 -0
- package/dist/agent-verifier/materialize-workspace-ZAVGQQSF.mjs.map +1 -0
- package/dist/agent-verifier/project-state-K576C2TE.mjs +33 -0
- package/dist/agent-verifier/project-state-K576C2TE.mjs.map +1 -0
- package/dist/agent-verifier/prompt-MJRJMOGQ.mjs +756 -0
- package/dist/agent-verifier/prompt-MJRJMOGQ.mjs.map +1 -0
- package/dist/agent-verifier/reducer-bundle-preflight-LXNJUBKL.mjs +20 -0
- package/dist/agent-verifier/reducer-bundle-preflight-LXNJUBKL.mjs.map +1 -0
- package/dist/agent-verifier/reducer-contract-preflight-TUMQ43JV.mjs +11 -0
- package/dist/agent-verifier/reducer-contract-preflight-TUMQ43JV.mjs.map +1 -0
- package/dist/agent-verifier/reducer-native-test-harness-CHX5MBL5.mjs +50 -0
- package/dist/agent-verifier/reducer-native-test-harness-CHX5MBL5.mjs.map +1 -0
- package/dist/agent-verifier/static-scaffold-R7SVDRQI.mjs +27 -0
- package/dist/agent-verifier/static-scaffold-R7SVDRQI.mjs.map +1 -0
- package/dist/agent-verifier/sync-THAI546U.mjs +588 -0
- package/dist/agent-verifier/sync-THAI546U.mjs.map +1 -0
- package/dist/agent-verifier/test-AFAQFKOB.mjs +353 -0
- package/dist/agent-verifier/test-AFAQFKOB.mjs.map +1 -0
- package/dist/agent-verifier/workspace-codegen-2ZMQRIKJ.mjs +10 -0
- package/dist/agent-verifier/workspace-codegen-2ZMQRIKJ.mjs.map +1 -0
- package/dist/agent-verifier/workspace-dependencies-NOOQBK6I.mjs +15 -0
- package/dist/agent-verifier/workspace-dependencies-NOOQBK6I.mjs.map +1 -0
- package/package.json +3 -2
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
resolveRemoteProject
|
|
4
|
+
} from "./chunk-HGMUAL33.mjs";
|
|
5
|
+
import {
|
|
6
|
+
CONFIG_FLAG_ARGS,
|
|
7
|
+
defineCommand,
|
|
8
|
+
findProjectCompiledResultsForRevision,
|
|
9
|
+
parseCompileCommandArgs,
|
|
10
|
+
queueProjectRevisionCompileSdk,
|
|
11
|
+
waitForCompiledResultJobSdk
|
|
12
|
+
} from "./chunk-W3N3QJ4V.mjs";
|
|
13
|
+
import {
|
|
14
|
+
getProjectAuthoringState,
|
|
15
|
+
getProjectPendingAuthoringSync,
|
|
16
|
+
setLatestCompileAttempt
|
|
17
|
+
} from "./chunk-YE7UAO3T.mjs";
|
|
18
|
+
import {
|
|
19
|
+
runLocalTypecheck
|
|
20
|
+
} from "./chunk-UIOLGH4A.mjs";
|
|
21
|
+
import {
|
|
22
|
+
formatCliError
|
|
23
|
+
} from "./chunk-S34FRJHS.mjs";
|
|
24
|
+
import {
|
|
25
|
+
assertCompilerPortableDependencies,
|
|
26
|
+
assertReleaseEnvironmentPortableDependencies,
|
|
27
|
+
consola,
|
|
28
|
+
resolveProjectContext
|
|
29
|
+
} from "./chunk-3UKQVWLV.mjs";
|
|
30
|
+
import "./chunk-SH5JKYOB.mjs";
|
|
31
|
+
import {
|
|
32
|
+
getLocalDiff
|
|
33
|
+
} from "./chunk-XGWCY624.mjs";
|
|
34
|
+
import {
|
|
35
|
+
assertCliStaticScaffoldComplete
|
|
36
|
+
} from "./chunk-7WWGFAAU.mjs";
|
|
37
|
+
import "./chunk-F2DIOJJZ.mjs";
|
|
38
|
+
import {
|
|
39
|
+
updateProjectState
|
|
40
|
+
} from "./chunk-776W3UGV.mjs";
|
|
41
|
+
import "./chunk-O4YCPU7C.mjs";
|
|
42
|
+
import "./chunk-VS573ERH.mjs";
|
|
43
|
+
import "./chunk-UIZNWRM6.mjs";
|
|
44
|
+
import "./chunk-NAK77WXW.mjs";
|
|
45
|
+
import "./chunk-TAEQKBJB.mjs";
|
|
46
|
+
import "./chunk-IAYRNVUC.mjs";
|
|
47
|
+
import "./chunk-ZEELHSY3.mjs";
|
|
48
|
+
import "./chunk-H76MT5UR.mjs";
|
|
49
|
+
import "./chunk-SKI2ESE5.mjs";
|
|
50
|
+
|
|
51
|
+
// src/commands/compile.ts
|
|
52
|
+
function formatDiagnosticsSummary(diagnostics) {
|
|
53
|
+
const firstMessage = diagnostics?.find(
|
|
54
|
+
(diagnostic) => diagnostic.message
|
|
55
|
+
)?.message;
|
|
56
|
+
return firstMessage?.trim() || void 0;
|
|
57
|
+
}
|
|
58
|
+
function formatCompileJobProgressMessage(job) {
|
|
59
|
+
const phase = job.phase ? ` [${job.phase}]` : "";
|
|
60
|
+
const detail = job.message ? ` ${job.message}` : "";
|
|
61
|
+
if (job.status === "PENDING") {
|
|
62
|
+
const queue = typeof job.queuePosition === "number" ? ` (queue ${job.queuePosition + 1})` : "";
|
|
63
|
+
return `Compile queued${queue}${phase}${detail}`.trim();
|
|
64
|
+
}
|
|
65
|
+
if (job.status === "RUNNING") {
|
|
66
|
+
return `Compile running${phase}${detail}`.trim();
|
|
67
|
+
}
|
|
68
|
+
if (job.status === "FAILED") {
|
|
69
|
+
return `Compile failed${phase}${detail}`.trim();
|
|
70
|
+
}
|
|
71
|
+
return `Compile ${job.status.toLowerCase()}${phase}${detail}`.trim();
|
|
72
|
+
}
|
|
73
|
+
function formatFailedCompileJobSummary(job) {
|
|
74
|
+
return formatCompileJobProgressMessage({
|
|
75
|
+
status: "FAILED",
|
|
76
|
+
phase: job.phase,
|
|
77
|
+
message: job.errorMessage ?? job.message ?? void 0
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
function formatFailedCompileJobWithCompiledResultMessage(options) {
|
|
81
|
+
return `${formatFailedCompileJobSummary(options.job)}. The backend created compiled result ${options.compiledResultId}, but the compile job did not complete cleanly. Run 'dreamboard compile' again after fixing the backend/compiler issue.`;
|
|
82
|
+
}
|
|
83
|
+
function formatRemoteCompileCommandError(options) {
|
|
84
|
+
const detail = options.message.trim();
|
|
85
|
+
const hasActionableTerminalContext = /^Compile\s+(failed|completed|cancelled|interrupted)\b/i.test(detail);
|
|
86
|
+
if (options.jobId) {
|
|
87
|
+
if (hasActionableTerminalContext) {
|
|
88
|
+
return `Remote compile job ${options.jobId} could not be completed. ${detail}`;
|
|
89
|
+
}
|
|
90
|
+
return `Remote compile job ${options.jobId} could not be completed. ${detail} Check backend health and try 'dreamboard compile' again.`;
|
|
91
|
+
}
|
|
92
|
+
return `Remote compile could not be started. ${detail} Check backend health and try 'dreamboard compile' again.`;
|
|
93
|
+
}
|
|
94
|
+
async function persistFailedCompileAttempt(options) {
|
|
95
|
+
const nextProjectConfig = setLatestCompileAttempt(options.projectConfig, {
|
|
96
|
+
resultId: void 0,
|
|
97
|
+
jobId: options.jobId,
|
|
98
|
+
revisionDigest: options.revisionDigest,
|
|
99
|
+
authoringStateId: options.authoringStateId ?? options.revisionDigest,
|
|
100
|
+
status: "failed",
|
|
101
|
+
diagnosticsSummary: options.diagnosticsSummary
|
|
102
|
+
});
|
|
103
|
+
await updateProjectState(options.projectRoot, nextProjectConfig);
|
|
104
|
+
}
|
|
105
|
+
var compile_default = defineCommand({
|
|
106
|
+
meta: {
|
|
107
|
+
name: "compile",
|
|
108
|
+
description: "Compile the current remote authoring head"
|
|
109
|
+
},
|
|
110
|
+
args: {
|
|
111
|
+
debug: {
|
|
112
|
+
type: "boolean",
|
|
113
|
+
description: "Print additional compile progress context",
|
|
114
|
+
default: false
|
|
115
|
+
},
|
|
116
|
+
"skip-local-check": {
|
|
117
|
+
type: "boolean",
|
|
118
|
+
description: "Skip the best-effort local typecheck before compiling",
|
|
119
|
+
default: false
|
|
120
|
+
},
|
|
121
|
+
...CONFIG_FLAG_ARGS
|
|
122
|
+
},
|
|
123
|
+
async run({ args }) {
|
|
124
|
+
const parsedArgs = parseCompileCommandArgs(args);
|
|
125
|
+
const { projectRoot, projectConfig, config } = await resolveProjectContext(parsedArgs);
|
|
126
|
+
let nextProjectConfig = projectConfig;
|
|
127
|
+
await assertReleaseEnvironmentPortableDependencies({
|
|
128
|
+
projectRoot,
|
|
129
|
+
projectConfig: nextProjectConfig,
|
|
130
|
+
environment: config.environment
|
|
131
|
+
});
|
|
132
|
+
await assertCompilerPortableDependencies({
|
|
133
|
+
projectRoot,
|
|
134
|
+
projectConfig: nextProjectConfig
|
|
135
|
+
});
|
|
136
|
+
const diff = await getLocalDiff(projectRoot);
|
|
137
|
+
await assertCliStaticScaffoldComplete(projectRoot, diff.deleted);
|
|
138
|
+
if (diff.modified.length > 0 || diff.added.length > 0 || diff.deleted.length > 0) {
|
|
139
|
+
throw new Error(
|
|
140
|
+
"Local authored changes are not synced yet. Run 'dreamboard sync' before compiling."
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
const remoteProject = await resolveRemoteProject({
|
|
144
|
+
projectRoot,
|
|
145
|
+
projectConfig: nextProjectConfig,
|
|
146
|
+
config
|
|
147
|
+
});
|
|
148
|
+
nextProjectConfig = remoteProject.projectConfig;
|
|
149
|
+
const localAuthoring = getProjectAuthoringState(nextProjectConfig);
|
|
150
|
+
const pendingSync = getProjectPendingAuthoringSync(nextProjectConfig);
|
|
151
|
+
if (pendingSync) {
|
|
152
|
+
if (pendingSync.phase === "authoring_state_created") {
|
|
153
|
+
throw new Error(
|
|
154
|
+
"Previous sync reached the remote authored head, but local scaffold finalization did not complete. Run 'dreamboard sync' again before compiling."
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
throw new Error(
|
|
158
|
+
"Previous sync uploaded source changes but did not finish creating the authored head. Run 'dreamboard sync' again before compiling."
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
const localRevisionDigest = localAuthoring.revisionDigest ?? nextProjectConfig.remoteHeadDigest;
|
|
162
|
+
if (!localRevisionDigest) {
|
|
163
|
+
throw new Error(
|
|
164
|
+
"This workspace does not know its authored revision yet. Run 'dreamboard sync' first."
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
const remoteRevisionDigest = remoteProject.project.head?.revisionDigest;
|
|
168
|
+
if (!remoteRevisionDigest) {
|
|
169
|
+
throw new Error("Remote has no authored project revision to compile yet.");
|
|
170
|
+
}
|
|
171
|
+
if (remoteRevisionDigest !== localRevisionDigest) {
|
|
172
|
+
throw new Error(
|
|
173
|
+
`Remote project head is ${remoteRevisionDigest} but this workspace is based on ${localRevisionDigest}. Run 'dreamboard pull' before compiling.`
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
if (!parsedArgs["skip-local-check"]) {
|
|
177
|
+
consola.start("Running local typecheck...");
|
|
178
|
+
const typecheckResult = await runLocalTypecheck(projectRoot);
|
|
179
|
+
if (typecheckResult.skipped) {
|
|
180
|
+
if (typecheckResult.output) {
|
|
181
|
+
consola.warn(typecheckResult.output);
|
|
182
|
+
}
|
|
183
|
+
} else if (!typecheckResult.success) {
|
|
184
|
+
if (typecheckResult.output) {
|
|
185
|
+
consola.error(typecheckResult.output);
|
|
186
|
+
}
|
|
187
|
+
throw new Error(
|
|
188
|
+
"Local typecheck failed. Fix the diagnostics or re-run with --skip-local-check."
|
|
189
|
+
);
|
|
190
|
+
} else {
|
|
191
|
+
consola.success("Local typecheck passed.");
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
const existingCompiledResult = (await findProjectCompiledResultsForRevision({
|
|
195
|
+
projectId: nextProjectConfig.projectId,
|
|
196
|
+
revisionDigest: localRevisionDigest
|
|
197
|
+
})).find((result) => result.success);
|
|
198
|
+
if (existingCompiledResult) {
|
|
199
|
+
nextProjectConfig = setLatestCompileAttempt(nextProjectConfig, {
|
|
200
|
+
resultId: existingCompiledResult.id,
|
|
201
|
+
jobId: void 0,
|
|
202
|
+
revisionDigest: localRevisionDigest,
|
|
203
|
+
authoringStateId: existingCompiledResult.authoringStateId ?? localRevisionDigest,
|
|
204
|
+
status: "successful",
|
|
205
|
+
diagnosticsSummary: void 0
|
|
206
|
+
});
|
|
207
|
+
await updateProjectState(projectRoot, nextProjectConfig);
|
|
208
|
+
consola.success(
|
|
209
|
+
`Reusing compiled ${existingCompiledResult.id} for authored state ${existingCompiledResult.authoringStateId}.`
|
|
210
|
+
);
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
let compileJobId;
|
|
214
|
+
let compileJobStatus;
|
|
215
|
+
let compileJobPhase;
|
|
216
|
+
let compileJobMessage;
|
|
217
|
+
let compileJobErrorMessage;
|
|
218
|
+
let compiledResult;
|
|
219
|
+
try {
|
|
220
|
+
const compileJob = await queueProjectRevisionCompileSdk({
|
|
221
|
+
projectId: nextProjectConfig.projectId,
|
|
222
|
+
revisionDigest: localRevisionDigest
|
|
223
|
+
});
|
|
224
|
+
compileJobId = compileJob.jobId;
|
|
225
|
+
if (!compileJobId) {
|
|
226
|
+
throw new Error("Failed to create compile job: missing jobId.");
|
|
227
|
+
}
|
|
228
|
+
({
|
|
229
|
+
job: {
|
|
230
|
+
status: compileJobStatus,
|
|
231
|
+
phase: compileJobPhase,
|
|
232
|
+
message: compileJobMessage,
|
|
233
|
+
errorMessage: compileJobErrorMessage
|
|
234
|
+
},
|
|
235
|
+
compiledResult
|
|
236
|
+
} = await waitForCompiledResultJobSdk({
|
|
237
|
+
projectId: nextProjectConfig.projectId,
|
|
238
|
+
jobId: compileJobId,
|
|
239
|
+
onProgress: (job) => {
|
|
240
|
+
const message = formatCompileJobProgressMessage(job);
|
|
241
|
+
if (parsedArgs.debug) {
|
|
242
|
+
consola.info(message);
|
|
243
|
+
} else {
|
|
244
|
+
consola.start(message);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}));
|
|
248
|
+
} catch (error) {
|
|
249
|
+
const message = formatCliError(error);
|
|
250
|
+
if (compileJobId) {
|
|
251
|
+
await persistFailedCompileAttempt({
|
|
252
|
+
projectRoot,
|
|
253
|
+
projectConfig: nextProjectConfig,
|
|
254
|
+
revisionDigest: localRevisionDigest,
|
|
255
|
+
authoringStateId: localAuthoring.authoringStateId,
|
|
256
|
+
diagnosticsSummary: message,
|
|
257
|
+
jobId: compileJobId
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
throw new Error(
|
|
261
|
+
formatRemoteCompileCommandError({
|
|
262
|
+
message,
|
|
263
|
+
jobId: compileJobId
|
|
264
|
+
})
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
const failedJobProducedCompiledResult = compileJobStatus === "FAILED" && compiledResult.success;
|
|
268
|
+
const failedJobWithCompiledResultSummary = failedJobProducedCompiledResult ? formatFailedCompileJobSummary({
|
|
269
|
+
phase: compileJobPhase,
|
|
270
|
+
message: compileJobMessage,
|
|
271
|
+
errorMessage: compileJobErrorMessage
|
|
272
|
+
}) : void 0;
|
|
273
|
+
nextProjectConfig = setLatestCompileAttempt(nextProjectConfig, {
|
|
274
|
+
resultId: compiledResult.id,
|
|
275
|
+
jobId: compileJobId,
|
|
276
|
+
revisionDigest: localRevisionDigest,
|
|
277
|
+
authoringStateId: compiledResult.authoringStateId ?? localRevisionDigest,
|
|
278
|
+
status: compiledResult.success && !failedJobProducedCompiledResult ? "successful" : "failed",
|
|
279
|
+
diagnosticsSummary: failedJobWithCompiledResultSummary ?? formatDiagnosticsSummary(compiledResult.diagnostics)
|
|
280
|
+
});
|
|
281
|
+
await updateProjectState(projectRoot, nextProjectConfig);
|
|
282
|
+
if (failedJobProducedCompiledResult) {
|
|
283
|
+
throw new Error(
|
|
284
|
+
formatFailedCompileJobWithCompiledResultMessage({
|
|
285
|
+
compiledResultId: compiledResult.id,
|
|
286
|
+
job: {
|
|
287
|
+
phase: compileJobPhase,
|
|
288
|
+
message: compileJobMessage,
|
|
289
|
+
errorMessage: compileJobErrorMessage
|
|
290
|
+
}
|
|
291
|
+
})
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
if (!compiledResult.success) {
|
|
295
|
+
for (const diagnostic of compiledResult.diagnostics ?? []) {
|
|
296
|
+
if (diagnostic.message) {
|
|
297
|
+
consola.error(diagnostic.message);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
throw new Error(
|
|
301
|
+
"Remote compile failed, but your authored state is synced. Fix the diagnostics and run 'dreamboard compile' again."
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
consola.success(
|
|
305
|
+
`Compiled ${compiledResult.id} for revision ${localRevisionDigest}.`
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
export {
|
|
310
|
+
compile_default as default
|
|
311
|
+
};
|
|
312
|
+
//# sourceMappingURL=compile-TEQVA46V.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/commands/compile.ts"],"sourcesContent":["import type { CompiledResult } from \"@dreamboard-games/api-client\";\nimport type { ProjectConfig } from \"../types.js\";\nimport { defineCommand } from \"citty\";\nimport consola from \"consola\";\nimport { CONFIG_FLAG_ARGS } from \"../command-args.js\";\nimport { resolveProjectContext } from \"../config/resolve.js\";\nimport { updateProjectState } from \"../config/project-config.js\";\nimport { parseCompileCommandArgs } from \"../flags.js\";\nimport { getLocalDiff } from \"../services/project/local-files.js\";\nimport { assertCliStaticScaffoldComplete } from \"../services/project/static-scaffold.js\";\nimport {\n assertCompilerPortableDependencies,\n assertReleaseEnvironmentPortableDependencies,\n} from \"../services/project/dependency-portability.js\";\nimport { runLocalTypecheck } from \"../services/project/local-typecheck.js\";\nimport {\n findProjectCompiledResultsForRevision,\n queueProjectRevisionCompileSdk,\n waitForCompiledResultJobSdk,\n} from \"../services/api/index.js\";\nimport {\n getProjectAuthoringState,\n getProjectPendingAuthoringSync,\n setLatestCompileAttempt,\n} from \"../services/project/project-state.js\";\nimport { formatCliError } from \"../utils/errors.js\";\nimport { resolveRemoteProject } from \"../services/project/remote-project.js\";\n\nfunction formatDiagnosticsSummary(\n diagnostics: Array<{ message?: string }> | null | undefined,\n): string | undefined {\n const firstMessage = diagnostics?.find(\n (diagnostic) => diagnostic.message,\n )?.message;\n return firstMessage?.trim() || undefined;\n}\n\nfunction formatCompileJobProgressMessage(job: {\n status: string;\n phase?: string;\n queuePosition?: number;\n message?: string;\n}): string {\n const phase = job.phase ? ` [${job.phase}]` : \"\";\n const detail = job.message ? ` ${job.message}` : \"\";\n if (job.status === \"PENDING\") {\n const queue =\n typeof job.queuePosition === \"number\"\n ? ` (queue ${job.queuePosition + 1})`\n : \"\";\n return `Compile queued${queue}${phase}${detail}`.trim();\n }\n if (job.status === \"RUNNING\") {\n return `Compile running${phase}${detail}`.trim();\n }\n if (job.status === \"FAILED\") {\n return `Compile failed${phase}${detail}`.trim();\n }\n return `Compile ${job.status.toLowerCase()}${phase}${detail}`.trim();\n}\n\nfunction formatFailedCompileJobSummary(job: {\n phase?: string;\n message?: string | null;\n errorMessage?: string | null;\n}): string {\n return formatCompileJobProgressMessage({\n status: \"FAILED\",\n phase: job.phase,\n message: job.errorMessage ?? job.message ?? undefined,\n });\n}\n\nfunction formatFailedCompileJobWithCompiledResultMessage(options: {\n compiledResultId: string;\n job: {\n phase?: string;\n message?: string | null;\n errorMessage?: string | null;\n };\n}): string {\n return `${formatFailedCompileJobSummary(options.job)}. The backend created compiled result ${options.compiledResultId}, but the compile job did not complete cleanly. Run 'dreamboard compile' again after fixing the backend/compiler issue.`;\n}\n\nfunction formatRemoteCompileCommandError(options: {\n message: string;\n jobId?: string;\n}): string {\n const detail = options.message.trim();\n const hasActionableTerminalContext =\n /^Compile\\s+(failed|completed|cancelled|interrupted)\\b/i.test(detail);\n if (options.jobId) {\n if (hasActionableTerminalContext) {\n return `Remote compile job ${options.jobId} could not be completed. ${detail}`;\n }\n return `Remote compile job ${options.jobId} could not be completed. ${detail} Check backend health and try 'dreamboard compile' again.`;\n }\n return `Remote compile could not be started. ${detail} Check backend health and try 'dreamboard compile' again.`;\n}\n\nasync function persistFailedCompileAttempt(options: {\n projectRoot: string;\n projectConfig: ProjectConfig;\n revisionDigest: string;\n authoringStateId?: string;\n diagnosticsSummary: string;\n jobId?: string;\n}): Promise<void> {\n const nextProjectConfig = setLatestCompileAttempt(options.projectConfig, {\n resultId: undefined,\n jobId: options.jobId,\n revisionDigest: options.revisionDigest,\n authoringStateId: options.authoringStateId ?? options.revisionDigest,\n status: \"failed\",\n diagnosticsSummary: options.diagnosticsSummary,\n });\n await updateProjectState(options.projectRoot, nextProjectConfig);\n}\n\nexport default defineCommand({\n meta: {\n name: \"compile\",\n description: \"Compile the current remote authoring head\",\n },\n args: {\n debug: {\n type: \"boolean\",\n description: \"Print additional compile progress context\",\n default: false,\n },\n \"skip-local-check\": {\n type: \"boolean\",\n description: \"Skip the best-effort local typecheck before compiling\",\n default: false,\n },\n ...CONFIG_FLAG_ARGS,\n },\n async run({ args }) {\n const parsedArgs = parseCompileCommandArgs(args);\n const { projectRoot, projectConfig, config } =\n await resolveProjectContext(parsedArgs);\n let nextProjectConfig = projectConfig;\n await assertReleaseEnvironmentPortableDependencies({\n projectRoot,\n projectConfig: nextProjectConfig,\n environment: config.environment,\n });\n await assertCompilerPortableDependencies({\n projectRoot,\n projectConfig: nextProjectConfig,\n });\n\n const diff = await getLocalDiff(projectRoot);\n await assertCliStaticScaffoldComplete(projectRoot, diff.deleted);\n if (\n diff.modified.length > 0 ||\n diff.added.length > 0 ||\n diff.deleted.length > 0\n ) {\n throw new Error(\n \"Local authored changes are not synced yet. Run 'dreamboard sync' before compiling.\",\n );\n }\n\n const remoteProject = await resolveRemoteProject({\n projectRoot,\n projectConfig: nextProjectConfig,\n config,\n });\n nextProjectConfig = remoteProject.projectConfig;\n\n const localAuthoring = getProjectAuthoringState(nextProjectConfig);\n const pendingSync = getProjectPendingAuthoringSync(nextProjectConfig);\n if (pendingSync) {\n if (pendingSync.phase === \"authoring_state_created\") {\n throw new Error(\n \"Previous sync reached the remote authored head, but local scaffold finalization did not complete. Run 'dreamboard sync' again before compiling.\",\n );\n }\n throw new Error(\n \"Previous sync uploaded source changes but did not finish creating the authored head. Run 'dreamboard sync' again before compiling.\",\n );\n }\n const localRevisionDigest =\n localAuthoring.revisionDigest ?? nextProjectConfig.remoteHeadDigest;\n if (!localRevisionDigest) {\n throw new Error(\n \"This workspace does not know its authored revision yet. Run 'dreamboard sync' first.\",\n );\n }\n\n const remoteRevisionDigest = remoteProject.project.head?.revisionDigest;\n if (!remoteRevisionDigest) {\n throw new Error(\"Remote has no authored project revision to compile yet.\");\n }\n if (remoteRevisionDigest !== localRevisionDigest) {\n throw new Error(\n `Remote project head is ${remoteRevisionDigest} but this workspace is based on ${localRevisionDigest}. Run 'dreamboard pull' before compiling.`,\n );\n }\n\n if (!parsedArgs[\"skip-local-check\"]) {\n consola.start(\"Running local typecheck...\");\n const typecheckResult = await runLocalTypecheck(projectRoot);\n if (typecheckResult.skipped) {\n if (typecheckResult.output) {\n consola.warn(typecheckResult.output);\n }\n } else if (!typecheckResult.success) {\n if (typecheckResult.output) {\n consola.error(typecheckResult.output);\n }\n throw new Error(\n \"Local typecheck failed. Fix the diagnostics or re-run with --skip-local-check.\",\n );\n } else {\n consola.success(\"Local typecheck passed.\");\n }\n }\n\n const existingCompiledResult = (\n await findProjectCompiledResultsForRevision({\n projectId: nextProjectConfig.projectId,\n revisionDigest: localRevisionDigest,\n })\n ).find((result) => result.success);\n if (existingCompiledResult) {\n nextProjectConfig = setLatestCompileAttempt(nextProjectConfig, {\n resultId: existingCompiledResult.id,\n jobId: undefined,\n revisionDigest: localRevisionDigest,\n authoringStateId:\n existingCompiledResult.authoringStateId ?? localRevisionDigest,\n status: \"successful\",\n diagnosticsSummary: undefined,\n });\n await updateProjectState(projectRoot, nextProjectConfig);\n consola.success(\n `Reusing compiled ${existingCompiledResult.id} for authored state ${existingCompiledResult.authoringStateId}.`,\n );\n return;\n }\n\n let compileJobId: string | undefined;\n let compileJobStatus: string | undefined;\n let compileJobPhase: string | undefined;\n let compileJobMessage: string | null | undefined;\n let compileJobErrorMessage: string | null | undefined;\n let compiledResult: CompiledResult;\n try {\n const compileJob = await queueProjectRevisionCompileSdk({\n projectId: nextProjectConfig.projectId,\n revisionDigest: localRevisionDigest,\n });\n compileJobId = compileJob.jobId;\n if (!compileJobId) {\n throw new Error(\"Failed to create compile job: missing jobId.\");\n }\n\n ({\n job: {\n status: compileJobStatus,\n phase: compileJobPhase,\n message: compileJobMessage,\n errorMessage: compileJobErrorMessage,\n },\n compiledResult,\n } = await waitForCompiledResultJobSdk({\n projectId: nextProjectConfig.projectId,\n jobId: compileJobId,\n onProgress: (job) => {\n const message = formatCompileJobProgressMessage(job);\n if (parsedArgs.debug) {\n consola.info(message);\n } else {\n consola.start(message);\n }\n },\n }));\n } catch (error) {\n const message = formatCliError(error);\n if (compileJobId) {\n await persistFailedCompileAttempt({\n projectRoot,\n projectConfig: nextProjectConfig,\n revisionDigest: localRevisionDigest,\n authoringStateId: localAuthoring.authoringStateId,\n diagnosticsSummary: message,\n jobId: compileJobId,\n });\n }\n throw new Error(\n formatRemoteCompileCommandError({\n message,\n jobId: compileJobId,\n }),\n );\n }\n\n const failedJobProducedCompiledResult =\n compileJobStatus === \"FAILED\" && compiledResult.success;\n const failedJobWithCompiledResultSummary = failedJobProducedCompiledResult\n ? formatFailedCompileJobSummary({\n phase: compileJobPhase,\n message: compileJobMessage,\n errorMessage: compileJobErrorMessage,\n })\n : undefined;\n\n nextProjectConfig = setLatestCompileAttempt(nextProjectConfig, {\n resultId: compiledResult.id,\n jobId: compileJobId,\n revisionDigest: localRevisionDigest,\n authoringStateId: compiledResult.authoringStateId ?? localRevisionDigest,\n status:\n compiledResult.success && !failedJobProducedCompiledResult\n ? \"successful\"\n : \"failed\",\n diagnosticsSummary:\n failedJobWithCompiledResultSummary ??\n formatDiagnosticsSummary(compiledResult.diagnostics),\n });\n await updateProjectState(projectRoot, nextProjectConfig);\n\n if (failedJobProducedCompiledResult) {\n throw new Error(\n formatFailedCompileJobWithCompiledResultMessage({\n compiledResultId: compiledResult.id,\n job: {\n phase: compileJobPhase,\n message: compileJobMessage,\n errorMessage: compileJobErrorMessage,\n },\n }),\n );\n }\n\n if (!compiledResult.success) {\n for (const diagnostic of compiledResult.diagnostics ?? []) {\n if (diagnostic.message) {\n consola.error(diagnostic.message);\n }\n }\n throw new Error(\n \"Remote compile failed, but your authored state is synced. Fix the diagnostics and run 'dreamboard compile' again.\",\n );\n }\n\n consola.success(\n `Compiled ${compiledResult.id} for revision ${localRevisionDigest}.`,\n );\n },\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BA,SAAS,yBACP,aACoB;AACpB,QAAM,eAAe,aAAa;AAAA,IAChC,CAAC,eAAe,WAAW;AAAA,EAC7B,GAAG;AACH,SAAO,cAAc,KAAK,KAAK;AACjC;AAEA,SAAS,gCAAgC,KAK9B;AACT,QAAM,QAAQ,IAAI,QAAQ,KAAK,IAAI,KAAK,MAAM;AAC9C,QAAM,SAAS,IAAI,UAAU,IAAI,IAAI,OAAO,KAAK;AACjD,MAAI,IAAI,WAAW,WAAW;AAC5B,UAAM,QACJ,OAAO,IAAI,kBAAkB,WACzB,WAAW,IAAI,gBAAgB,CAAC,MAChC;AACN,WAAO,iBAAiB,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK;AAAA,EACxD;AACA,MAAI,IAAI,WAAW,WAAW;AAC5B,WAAO,kBAAkB,KAAK,GAAG,MAAM,GAAG,KAAK;AAAA,EACjD;AACA,MAAI,IAAI,WAAW,UAAU;AAC3B,WAAO,iBAAiB,KAAK,GAAG,MAAM,GAAG,KAAK;AAAA,EAChD;AACA,SAAO,WAAW,IAAI,OAAO,YAAY,CAAC,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK;AACrE;AAEA,SAAS,8BAA8B,KAI5B;AACT,SAAO,gCAAgC;AAAA,IACrC,QAAQ;AAAA,IACR,OAAO,IAAI;AAAA,IACX,SAAS,IAAI,gBAAgB,IAAI,WAAW;AAAA,EAC9C,CAAC;AACH;AAEA,SAAS,gDAAgD,SAO9C;AACT,SAAO,GAAG,8BAA8B,QAAQ,GAAG,CAAC,yCAAyC,QAAQ,gBAAgB;AACvH;AAEA,SAAS,gCAAgC,SAG9B;AACT,QAAM,SAAS,QAAQ,QAAQ,KAAK;AACpC,QAAM,+BACJ,yDAAyD,KAAK,MAAM;AACtE,MAAI,QAAQ,OAAO;AACjB,QAAI,8BAA8B;AAChC,aAAO,sBAAsB,QAAQ,KAAK,4BAA4B,MAAM;AAAA,IAC9E;AACA,WAAO,sBAAsB,QAAQ,KAAK,4BAA4B,MAAM;AAAA,EAC9E;AACA,SAAO,wCAAwC,MAAM;AACvD;AAEA,eAAe,4BAA4B,SAOzB;AAChB,QAAM,oBAAoB,wBAAwB,QAAQ,eAAe;AAAA,IACvE,UAAU;AAAA,IACV,OAAO,QAAQ;AAAA,IACf,gBAAgB,QAAQ;AAAA,IACxB,kBAAkB,QAAQ,oBAAoB,QAAQ;AAAA,IACtD,QAAQ;AAAA,IACR,oBAAoB,QAAQ;AAAA,EAC9B,CAAC;AACD,QAAM,mBAAmB,QAAQ,aAAa,iBAAiB;AACjE;AAEA,IAAO,kBAAQ,cAAc;AAAA,EAC3B,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,EACf;AAAA,EACA,MAAM;AAAA,IACJ,OAAO;AAAA,MACL,MAAM;AAAA,MACN,aAAa;AAAA,MACb,SAAS;AAAA,IACX;AAAA,IACA,oBAAoB;AAAA,MAClB,MAAM;AAAA,MACN,aAAa;AAAA,MACb,SAAS;AAAA,IACX;AAAA,IACA,GAAG;AAAA,EACL;AAAA,EACA,MAAM,IAAI,EAAE,KAAK,GAAG;AAClB,UAAM,aAAa,wBAAwB,IAAI;AAC/C,UAAM,EAAE,aAAa,eAAe,OAAO,IACzC,MAAM,sBAAsB,UAAU;AACxC,QAAI,oBAAoB;AACxB,UAAM,6CAA6C;AAAA,MACjD;AAAA,MACA,eAAe;AAAA,MACf,aAAa,OAAO;AAAA,IACtB,CAAC;AACD,UAAM,mCAAmC;AAAA,MACvC;AAAA,MACA,eAAe;AAAA,IACjB,CAAC;AAED,UAAM,OAAO,MAAM,aAAa,WAAW;AAC3C,UAAM,gCAAgC,aAAa,KAAK,OAAO;AAC/D,QACE,KAAK,SAAS,SAAS,KACvB,KAAK,MAAM,SAAS,KACpB,KAAK,QAAQ,SAAS,GACtB;AACA,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,UAAM,gBAAgB,MAAM,qBAAqB;AAAA,MAC/C;AAAA,MACA,eAAe;AAAA,MACf;AAAA,IACF,CAAC;AACD,wBAAoB,cAAc;AAElC,UAAM,iBAAiB,yBAAyB,iBAAiB;AACjE,UAAM,cAAc,+BAA+B,iBAAiB;AACpE,QAAI,aAAa;AACf,UAAI,YAAY,UAAU,2BAA2B;AACnD,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AAAA,MACF;AACA,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,UAAM,sBACJ,eAAe,kBAAkB,kBAAkB;AACrD,QAAI,CAAC,qBAAqB;AACxB,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,UAAM,uBAAuB,cAAc,QAAQ,MAAM;AACzD,QAAI,CAAC,sBAAsB;AACzB,YAAM,IAAI,MAAM,yDAAyD;AAAA,IAC3E;AACA,QAAI,yBAAyB,qBAAqB;AAChD,YAAM,IAAI;AAAA,QACR,0BAA0B,oBAAoB,mCAAmC,mBAAmB;AAAA,MACtG;AAAA,IACF;AAEA,QAAI,CAAC,WAAW,kBAAkB,GAAG;AACnC,cAAQ,MAAM,4BAA4B;AAC1C,YAAM,kBAAkB,MAAM,kBAAkB,WAAW;AAC3D,UAAI,gBAAgB,SAAS;AAC3B,YAAI,gBAAgB,QAAQ;AAC1B,kBAAQ,KAAK,gBAAgB,MAAM;AAAA,QACrC;AAAA,MACF,WAAW,CAAC,gBAAgB,SAAS;AACnC,YAAI,gBAAgB,QAAQ;AAC1B,kBAAQ,MAAM,gBAAgB,MAAM;AAAA,QACtC;AACA,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AAAA,MACF,OAAO;AACL,gBAAQ,QAAQ,yBAAyB;AAAA,MAC3C;AAAA,IACF;AAEA,UAAM,0BACJ,MAAM,sCAAsC;AAAA,MAC1C,WAAW,kBAAkB;AAAA,MAC7B,gBAAgB;AAAA,IAClB,CAAC,GACD,KAAK,CAAC,WAAW,OAAO,OAAO;AACjC,QAAI,wBAAwB;AAC1B,0BAAoB,wBAAwB,mBAAmB;AAAA,QAC7D,UAAU,uBAAuB;AAAA,QACjC,OAAO;AAAA,QACP,gBAAgB;AAAA,QAChB,kBACE,uBAAuB,oBAAoB;AAAA,QAC7C,QAAQ;AAAA,QACR,oBAAoB;AAAA,MACtB,CAAC;AACD,YAAM,mBAAmB,aAAa,iBAAiB;AACvD,cAAQ;AAAA,QACN,oBAAoB,uBAAuB,EAAE,uBAAuB,uBAAuB,gBAAgB;AAAA,MAC7G;AACA;AAAA,IACF;AAEA,QAAI;AACJ,QAAI;AACJ,QAAI;AACJ,QAAI;AACJ,QAAI;AACJ,QAAI;AACJ,QAAI;AACF,YAAM,aAAa,MAAM,+BAA+B;AAAA,QACtD,WAAW,kBAAkB;AAAA,QAC7B,gBAAgB;AAAA,MAClB,CAAC;AACD,qBAAe,WAAW;AAC1B,UAAI,CAAC,cAAc;AACjB,cAAM,IAAI,MAAM,8CAA8C;AAAA,MAChE;AAEA,OAAC;AAAA,QACC,KAAK;AAAA,UACH,QAAQ;AAAA,UACR,OAAO;AAAA,UACP,SAAS;AAAA,UACT,cAAc;AAAA,QAChB;AAAA,QACA;AAAA,MACF,IAAI,MAAM,4BAA4B;AAAA,QACpC,WAAW,kBAAkB;AAAA,QAC7B,OAAO;AAAA,QACP,YAAY,CAAC,QAAQ;AACnB,gBAAM,UAAU,gCAAgC,GAAG;AACnD,cAAI,WAAW,OAAO;AACpB,oBAAQ,KAAK,OAAO;AAAA,UACtB,OAAO;AACL,oBAAQ,MAAM,OAAO;AAAA,UACvB;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH,SAAS,OAAO;AACd,YAAM,UAAU,eAAe,KAAK;AACpC,UAAI,cAAc;AAChB,cAAM,4BAA4B;AAAA,UAChC;AAAA,UACA,eAAe;AAAA,UACf,gBAAgB;AAAA,UAChB,kBAAkB,eAAe;AAAA,UACjC,oBAAoB;AAAA,UACpB,OAAO;AAAA,QACT,CAAC;AAAA,MACH;AACA,YAAM,IAAI;AAAA,QACR,gCAAgC;AAAA,UAC9B;AAAA,UACA,OAAO;AAAA,QACT,CAAC;AAAA,MACH;AAAA,IACF;AAEA,UAAM,kCACJ,qBAAqB,YAAY,eAAe;AAClD,UAAM,qCAAqC,kCACvC,8BAA8B;AAAA,MAC5B,OAAO;AAAA,MACP,SAAS;AAAA,MACT,cAAc;AAAA,IAChB,CAAC,IACD;AAEJ,wBAAoB,wBAAwB,mBAAmB;AAAA,MAC7D,UAAU,eAAe;AAAA,MACzB,OAAO;AAAA,MACP,gBAAgB;AAAA,MAChB,kBAAkB,eAAe,oBAAoB;AAAA,MACrD,QACE,eAAe,WAAW,CAAC,kCACvB,eACA;AAAA,MACN,oBACE,sCACA,yBAAyB,eAAe,WAAW;AAAA,IACvD,CAAC;AACD,UAAM,mBAAmB,aAAa,iBAAiB;AAEvD,QAAI,iCAAiC;AACnC,YAAM,IAAI;AAAA,QACR,gDAAgD;AAAA,UAC9C,kBAAkB,eAAe;AAAA,UACjC,KAAK;AAAA,YACH,OAAO;AAAA,YACP,SAAS;AAAA,YACT,cAAc;AAAA,UAChB;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAEA,QAAI,CAAC,eAAe,SAAS;AAC3B,iBAAW,cAAc,eAAe,eAAe,CAAC,GAAG;AACzD,YAAI,WAAW,SAAS;AACtB,kBAAQ,MAAM,WAAW,OAAO;AAAA,QAClC;AAAA,MACF;AACA,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,YAAQ;AAAA,MACN,YAAY,eAAe,EAAE,iBAAiB,mBAAmB;AAAA,IACnE;AAAA,EACF;AACF,CAAC;","names":[]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
getGlobalAuthPath,
|
|
4
|
+
getGlobalConfigPath,
|
|
5
|
+
loadGlobalConfig,
|
|
6
|
+
saveGlobalConfig
|
|
7
|
+
} from "./chunk-SH5JKYOB.mjs";
|
|
8
|
+
import "./chunk-TAEQKBJB.mjs";
|
|
9
|
+
import "./chunk-IAYRNVUC.mjs";
|
|
10
|
+
import "./chunk-H76MT5UR.mjs";
|
|
11
|
+
import "./chunk-SKI2ESE5.mjs";
|
|
12
|
+
export {
|
|
13
|
+
getGlobalAuthPath,
|
|
14
|
+
getGlobalConfigPath,
|
|
15
|
+
loadGlobalConfig,
|
|
16
|
+
saveGlobalConfig
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=global-config-Y2NTSK4R.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import "./chunk-SKI2ESE5.mjs";
|
|
3
|
+
|
|
4
|
+
// src/config/keychain-backend.ts
|
|
5
|
+
var KEYCHAIN_SERVICE = "dreamboard-cli";
|
|
6
|
+
var KEYCHAIN_ACCOUNT = "session";
|
|
7
|
+
var cachedModule;
|
|
8
|
+
async function loadKeyringModule() {
|
|
9
|
+
if (cachedModule !== void 0) return cachedModule;
|
|
10
|
+
try {
|
|
11
|
+
const mod = await import("@napi-rs/keyring");
|
|
12
|
+
cachedModule = mod;
|
|
13
|
+
} catch {
|
|
14
|
+
cachedModule = null;
|
|
15
|
+
}
|
|
16
|
+
return cachedModule;
|
|
17
|
+
}
|
|
18
|
+
function keychainProbe(entry) {
|
|
19
|
+
try {
|
|
20
|
+
entry.getPassword();
|
|
21
|
+
return true;
|
|
22
|
+
} catch {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function parsePayload(raw) {
|
|
27
|
+
if (raw === null || raw === void 0) return null;
|
|
28
|
+
const trimmed = raw.trim();
|
|
29
|
+
if (trimmed.length === 0) return null;
|
|
30
|
+
try {
|
|
31
|
+
const parsed = JSON.parse(trimmed);
|
|
32
|
+
if (!parsed.accessToken && !parsed.refreshToken) return null;
|
|
33
|
+
return {
|
|
34
|
+
accessToken: parsed.accessToken || void 0,
|
|
35
|
+
refreshToken: parsed.refreshToken || void 0,
|
|
36
|
+
tokenExpiresAt: parsed.tokenExpiresAt || void 0,
|
|
37
|
+
clerkOAuthIssuer: parsed.clerkOAuthIssuer || void 0,
|
|
38
|
+
clerkOAuthClientId: parsed.clerkOAuthClientId || void 0,
|
|
39
|
+
clerkOAuthTokenUrl: parsed.clerkOAuthTokenUrl || void 0,
|
|
40
|
+
environment: parsed.environment || void 0
|
|
41
|
+
};
|
|
42
|
+
} catch {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function writeFull(entry, creds) {
|
|
47
|
+
if (!creds.accessToken || !creds.refreshToken) {
|
|
48
|
+
throw new Error(
|
|
49
|
+
"Refusing to persist credentials with an empty accessToken or refreshToken."
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
const payload = {
|
|
53
|
+
accessToken: creds.accessToken,
|
|
54
|
+
refreshToken: creds.refreshToken,
|
|
55
|
+
tokenExpiresAt: creds.tokenExpiresAt,
|
|
56
|
+
clerkOAuthIssuer: creds.clerkOAuthIssuer,
|
|
57
|
+
clerkOAuthClientId: creds.clerkOAuthClientId,
|
|
58
|
+
clerkOAuthTokenUrl: creds.clerkOAuthTokenUrl,
|
|
59
|
+
environment: creds.environment
|
|
60
|
+
};
|
|
61
|
+
entry.setPassword(JSON.stringify(payload));
|
|
62
|
+
}
|
|
63
|
+
function writeAccessOnly(entry, accessToken) {
|
|
64
|
+
if (!accessToken) {
|
|
65
|
+
throw new Error("Refusing to persist an empty access token.");
|
|
66
|
+
}
|
|
67
|
+
const payload = { accessToken };
|
|
68
|
+
entry.setPassword(JSON.stringify(payload));
|
|
69
|
+
}
|
|
70
|
+
function clear(entry) {
|
|
71
|
+
try {
|
|
72
|
+
entry.deletePassword();
|
|
73
|
+
} catch {
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
async function tryKeychainBackend() {
|
|
77
|
+
const mod = await loadKeyringModule();
|
|
78
|
+
if (!mod) {
|
|
79
|
+
return {
|
|
80
|
+
available: false,
|
|
81
|
+
reason: "@napi-rs/keyring is not installed for this platform"
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
let entry;
|
|
85
|
+
try {
|
|
86
|
+
entry = new mod.Entry(KEYCHAIN_SERVICE, KEYCHAIN_ACCOUNT);
|
|
87
|
+
} catch (err) {
|
|
88
|
+
return {
|
|
89
|
+
available: false,
|
|
90
|
+
reason: `Failed to construct keyring entry: ${String(err.message ?? err)}`
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
if (!keychainProbe(entry)) {
|
|
94
|
+
return {
|
|
95
|
+
available: false,
|
|
96
|
+
reason: "OS keyring is not accessible from this process"
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
const backend = {
|
|
100
|
+
name: "keychain",
|
|
101
|
+
async read() {
|
|
102
|
+
try {
|
|
103
|
+
return parsePayload(entry.getPassword());
|
|
104
|
+
} catch (err) {
|
|
105
|
+
const message = String(err.message ?? err);
|
|
106
|
+
if (/no matching entry|not found/i.test(message)) {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
throw err;
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
async writeFull(creds) {
|
|
113
|
+
writeFull(entry, creds);
|
|
114
|
+
},
|
|
115
|
+
async writeAccessOnly(accessToken) {
|
|
116
|
+
writeAccessOnly(entry, accessToken);
|
|
117
|
+
},
|
|
118
|
+
async clear() {
|
|
119
|
+
clear(entry);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
return { available: true, backend };
|
|
123
|
+
}
|
|
124
|
+
function _setKeyringModuleForTests(mod) {
|
|
125
|
+
cachedModule = mod;
|
|
126
|
+
}
|
|
127
|
+
function _resetKeyringModuleForTests() {
|
|
128
|
+
cachedModule = void 0;
|
|
129
|
+
}
|
|
130
|
+
export {
|
|
131
|
+
_resetKeyringModuleForTests,
|
|
132
|
+
_setKeyringModuleForTests,
|
|
133
|
+
tryKeychainBackend
|
|
134
|
+
};
|
|
135
|
+
//# sourceMappingURL=keychain-backend-SPQWGKZN.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/config/keychain-backend.ts"],"sourcesContent":["/**\n * OS keychain-backed `CredentialBackend` built on top of `@napi-rs/keyring`.\n *\n * Keychain is an *opt-in* storage backend, enabled by setting\n * `credentialBackend: \"keychain\"` in `~/.dreamboard/config.json` (see\n * `credential-store.ts` for the resolver). When enabled, it gives us:\n * - A refresh token encrypted at rest by the OS (Keychain on macOS,\n * Credential Vault on Windows, Secret Service on Linux).\n * - Protection against other processes running as the same user tailing\n * `~/.dreamboard/auth.json` to scrape the token.\n *\n * It is not the default because on macOS the first keychain write\n * triggers a login-password prompt, and macOS re-prompts whenever the\n * executing Node binary's code signature changes (e.g. after an\n * `nvm`/`volta` upgrade). The zero-prompt file backend is a better\n * out-of-the-box experience for CLI users.\n *\n * This module is loaded optionally: `@napi-rs/keyring` is declared as an\n * `optionalDependencies` entry so environments where the native binary is\n * unavailable (e.g. Alpine containers, Linux without libsecret, some CI\n * images) still get a working CLI via the file backend fallback.\n *\n * One-time migration: when a user opts into the keychain and `auth.json`\n * still has tokens, `credential-store.ts` copies them into the keychain\n * and deletes the file. This is the only path that intentionally mutates\n * both backends.\n */\n\nimport type {\n CredentialBackend,\n Credentials,\n StoredSessionSnapshot,\n} from \"./credential-store.js\";\n\n/** Keychain service id. Shared across all Dreamboard CLI builds. */\nconst KEYCHAIN_SERVICE = \"dreamboard-cli\";\n/**\n * Keychain account id. The `user@host` shape is conventional but we keep\n * it fixed for now because the CLI only cares about \"the session for this\n * OS user\", not per-process sessions.\n */\nconst KEYCHAIN_ACCOUNT = \"session\";\n\ntype EntryInstance = {\n setPassword(value: string): void;\n getPassword(): string | null | undefined;\n deletePassword(): boolean;\n};\n\ntype KeyringModule = {\n Entry: new (service: string, account: string) => EntryInstance;\n};\n\nlet cachedModule: KeyringModule | null | undefined;\n\nasync function loadKeyringModule(): Promise<KeyringModule | null> {\n if (cachedModule !== undefined) return cachedModule;\n try {\n // `@napi-rs/keyring` is an optional dependency. If the native binary is\n // missing on this platform the dynamic import throws; we swallow that\n // and fall back to the file backend.\n const mod = (await import(\"@napi-rs/keyring\")) as unknown as KeyringModule;\n cachedModule = mod;\n } catch {\n cachedModule = null;\n }\n return cachedModule;\n}\n\nfunction keychainProbe(entry: EntryInstance): boolean {\n // Some platforms have the module installed but no accessible keyring\n // (e.g. headless Linux without DBus). Touch getPassword to verify we\n // can talk to the service without side effects.\n try {\n entry.getPassword();\n return true;\n } catch {\n return false;\n }\n}\n\ntype KeychainPayload = {\n accessToken?: string;\n refreshToken?: string;\n tokenExpiresAt?: string;\n clerkOAuthIssuer?: string;\n clerkOAuthClientId?: string;\n clerkOAuthTokenUrl?: string;\n environment?: string;\n};\n\nfunction parsePayload(\n raw: string | null | undefined,\n): StoredSessionSnapshot | null {\n if (raw === null || raw === undefined) return null;\n const trimmed = raw.trim();\n if (trimmed.length === 0) return null;\n try {\n const parsed = JSON.parse(trimmed) as KeychainPayload;\n if (!parsed.accessToken && !parsed.refreshToken) return null;\n return {\n accessToken: parsed.accessToken || undefined,\n refreshToken: parsed.refreshToken || undefined,\n tokenExpiresAt: parsed.tokenExpiresAt || undefined,\n clerkOAuthIssuer: parsed.clerkOAuthIssuer || undefined,\n clerkOAuthClientId: parsed.clerkOAuthClientId || undefined,\n clerkOAuthTokenUrl: parsed.clerkOAuthTokenUrl || undefined,\n environment: parsed.environment || undefined,\n };\n } catch {\n return null;\n }\n}\n\nfunction writeFull(entry: EntryInstance, creds: Credentials): void {\n if (!creds.accessToken || !creds.refreshToken) {\n throw new Error(\n \"Refusing to persist credentials with an empty accessToken or refreshToken.\",\n );\n }\n const payload: KeychainPayload = {\n accessToken: creds.accessToken,\n refreshToken: creds.refreshToken,\n tokenExpiresAt: creds.tokenExpiresAt,\n clerkOAuthIssuer: creds.clerkOAuthIssuer,\n clerkOAuthClientId: creds.clerkOAuthClientId,\n clerkOAuthTokenUrl: creds.clerkOAuthTokenUrl,\n environment: creds.environment,\n };\n entry.setPassword(JSON.stringify(payload));\n}\n\nfunction writeAccessOnly(entry: EntryInstance, accessToken: string): void {\n if (!accessToken) {\n throw new Error(\"Refusing to persist an empty access token.\");\n }\n const payload: KeychainPayload = { accessToken };\n entry.setPassword(JSON.stringify(payload));\n}\n\nfunction clear(entry: EntryInstance): void {\n try {\n entry.deletePassword();\n } catch {\n // keyring-rs throws when the entry does not exist. That is fine -\n // `clearCredentials` contracts as idempotent.\n }\n}\n\nexport type KeychainAvailability =\n | { available: true; backend: CredentialBackend }\n | { available: false; reason: string };\n\n/**\n * Attempt to construct a keychain-backed `CredentialBackend`. Returns an\n * `available: false` result (with a reason) if the native module, the\n * OS keyring, or the probe fails.\n */\nexport async function tryKeychainBackend(): Promise<KeychainAvailability> {\n const mod = await loadKeyringModule();\n if (!mod) {\n return {\n available: false,\n reason: \"@napi-rs/keyring is not installed for this platform\",\n };\n }\n\n let entry: EntryInstance;\n try {\n entry = new mod.Entry(KEYCHAIN_SERVICE, KEYCHAIN_ACCOUNT);\n } catch (err) {\n return {\n available: false,\n reason: `Failed to construct keyring entry: ${String((err as Error).message ?? err)}`,\n };\n }\n\n if (!keychainProbe(entry)) {\n return {\n available: false,\n reason: \"OS keyring is not accessible from this process\",\n };\n }\n\n const backend: CredentialBackend = {\n name: \"keychain\",\n async read() {\n try {\n return parsePayload(entry.getPassword());\n } catch (err) {\n const message = String((err as Error).message ?? err);\n // Transient keychain access errors (e.g. Touch ID prompt\n // cancelled) should not surface as \"session wiped\". Treat the\n // unreadable state as \"no session\" so the caller can fall back\n // to prompting for login.\n if (/no matching entry|not found/i.test(message)) {\n return null;\n }\n throw err;\n }\n },\n async writeFull(creds) {\n writeFull(entry, creds);\n },\n async writeAccessOnly(accessToken) {\n writeAccessOnly(entry, accessToken);\n },\n async clear() {\n clear(entry);\n },\n };\n return { available: true, backend };\n}\n\n/**\n * Test-only escape hatch so unit tests can install a fake keyring module\n * without going through the dynamic import cache.\n */\nexport function _setKeyringModuleForTests(mod: KeyringModule | null): void {\n cachedModule = mod;\n}\n\nexport function _resetKeyringModuleForTests(): void {\n cachedModule = undefined;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
collectLocalFiles,
|
|
4
|
+
getLocalDiff,
|
|
5
|
+
isAllowedGamePath,
|
|
6
|
+
isLibraryPath,
|
|
7
|
+
loadManifest,
|
|
8
|
+
loadRule,
|
|
9
|
+
removeExtraneousFiles,
|
|
10
|
+
walkDir,
|
|
11
|
+
writeManifest,
|
|
12
|
+
writeRule,
|
|
13
|
+
writeScaffoldFiles,
|
|
14
|
+
writeSnapshot,
|
|
15
|
+
writeSnapshotFromFiles,
|
|
16
|
+
writeSourceFiles
|
|
17
|
+
} from "./chunk-XGWCY624.mjs";
|
|
18
|
+
import {
|
|
19
|
+
computeManifestHash
|
|
20
|
+
} from "./chunk-O4YCPU7C.mjs";
|
|
21
|
+
import "./chunk-VS573ERH.mjs";
|
|
22
|
+
import "./chunk-UIZNWRM6.mjs";
|
|
23
|
+
import "./chunk-NAK77WXW.mjs";
|
|
24
|
+
import "./chunk-TAEQKBJB.mjs";
|
|
25
|
+
import "./chunk-IAYRNVUC.mjs";
|
|
26
|
+
import "./chunk-H76MT5UR.mjs";
|
|
27
|
+
import "./chunk-SKI2ESE5.mjs";
|
|
28
|
+
export {
|
|
29
|
+
collectLocalFiles,
|
|
30
|
+
computeManifestHash,
|
|
31
|
+
getLocalDiff,
|
|
32
|
+
isAllowedGamePath,
|
|
33
|
+
isLibraryPath,
|
|
34
|
+
loadManifest,
|
|
35
|
+
loadRule,
|
|
36
|
+
removeExtraneousFiles,
|
|
37
|
+
walkDir,
|
|
38
|
+
writeManifest,
|
|
39
|
+
writeRule,
|
|
40
|
+
writeScaffoldFiles,
|
|
41
|
+
writeSnapshot,
|
|
42
|
+
writeSnapshotFromFiles,
|
|
43
|
+
writeSourceFiles
|
|
44
|
+
};
|
|
45
|
+
//# sourceMappingURL=local-files-JFOQQZDL.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|