@withtruing/companion 0.14.1 → 0.14.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/cli.js +75 -26
- package/dist/whole-read-temp.js +4 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -21,7 +21,7 @@ import { AttemptSourceCleanupError, createCompanionAttemptSourceManager, startAt
|
|
|
21
21
|
import { createWholeReadAssignmentPool, } from './whole-read-pool.js';
|
|
22
22
|
import { createWholeReadSharedSourceManager, } from './whole-read-shared-source.js';
|
|
23
23
|
import { checkConnectionRepositoryReadiness, createRepositoryProvider, proveManagedRepositoryAccess, RepositoryProviderError, } from './repository-provider.js';
|
|
24
|
-
import { WholeReadGitError } from './whole-read-git.js';
|
|
24
|
+
import { WholeReadGitError, resolveLocalBuildCommit } from './whole-read-git.js';
|
|
25
25
|
import { acquireGithubCompanionSource, acquireAssignedSource, assignmentRouteReadinessCode, acquireLocalSource, dispatchWholeReadClaim, } from './whole-read-runner.js';
|
|
26
26
|
import { WHOLE_READ_PHASE_POLICY } from './whole-read/phase-policy.js';
|
|
27
27
|
import { acquireInstanceLock, installService, isNpxCachePath, releaseInstanceLock, runDaemon, servicePaths, serviceStatus, startService, stopService, uninstallService, } from './service.js';
|
|
@@ -1182,6 +1182,74 @@ function wholeReadTransport(client, onUsageLimit) {
|
|
|
1182
1182
|
function wholeReadBackendName(runtime) {
|
|
1183
1183
|
return sharedWholeReadBackendName(runtime.backend);
|
|
1184
1184
|
}
|
|
1185
|
+
export function assignmentSourceProblem(reason) {
|
|
1186
|
+
if (!(reason instanceof WholeReadGitError))
|
|
1187
|
+
return 'git_failed';
|
|
1188
|
+
if (reason.code === 'snapshot_unavailable')
|
|
1189
|
+
return 'snapshot_unavailable';
|
|
1190
|
+
if (reason.code === 'branch_unavailable')
|
|
1191
|
+
return 'branch_missing';
|
|
1192
|
+
if (reason.code === 'repository_unavailable')
|
|
1193
|
+
return 'folder_missing';
|
|
1194
|
+
return 'git_failed';
|
|
1195
|
+
}
|
|
1196
|
+
function safeReason(reason) {
|
|
1197
|
+
const text = reason instanceof Error ? reason.message : String(reason);
|
|
1198
|
+
return text.replace(/\b([a-z][a-z0-9+.-]*:\/\/)[^\s/@]+@/gi, '$1').replace(/\s+/g, ' ').slice(0, 200);
|
|
1199
|
+
}
|
|
1200
|
+
/** Runs the offered assignment's source check; says why on failure instead of swallowing it. */
|
|
1201
|
+
export async function verifyAssignmentSource(input) {
|
|
1202
|
+
const { assignment, local } = input;
|
|
1203
|
+
try {
|
|
1204
|
+
const acquired = await input.sharedSources.acquire(wholeReadSharedSourceKey(input.pairing, assignment), async (lease, signal) => {
|
|
1205
|
+
const source = await acquireAssignedSource({
|
|
1206
|
+
route: assignment.route,
|
|
1207
|
+
acquireLocal: () => local?.branch
|
|
1208
|
+
? acquireLocalSource({ repoPath: local.repoPath, branch: local.branch,
|
|
1209
|
+
snapshotSha: assignment.snapshotSha, signal })
|
|
1210
|
+
: Promise.reject(new WholeReadGitError(local ? 'branch_unavailable' : 'repository_unavailable')),
|
|
1211
|
+
acquireGithubCompanion: () => {
|
|
1212
|
+
const repositoryUrl = `https://github.com/${githubLabel(parseGitHubRepo(assignment.canonicalRepository))}.git`;
|
|
1213
|
+
return acquireGithubCompanionSource({ lease, repositoryUrl,
|
|
1214
|
+
snapshotSha: assignment.snapshotSha, signal });
|
|
1215
|
+
},
|
|
1216
|
+
});
|
|
1217
|
+
if (!source)
|
|
1218
|
+
throw new WholeReadGitError('snapshot_unavailable');
|
|
1219
|
+
return source;
|
|
1220
|
+
});
|
|
1221
|
+
await acquired.release();
|
|
1222
|
+
input.reportedFailures?.delete(`${assignment.id}:${assignment.assignmentRevision}`);
|
|
1223
|
+
return { verified: true };
|
|
1224
|
+
}
|
|
1225
|
+
catch (reason) {
|
|
1226
|
+
const sourceProblem = assignmentSourceProblem(reason);
|
|
1227
|
+
const failureKey = `${assignment.id}:${assignment.assignmentRevision}`;
|
|
1228
|
+
if (input.reportedFailures?.get(failureKey) === sourceProblem)
|
|
1229
|
+
return { verified: false, sourceProblem };
|
|
1230
|
+
input.reportedFailures?.set(failureKey, sourceProblem);
|
|
1231
|
+
const name = assignment.canonicalRepository.split('/').filter(Boolean).pop() ?? 'the repository';
|
|
1232
|
+
const prefix = `[${new Date().toISOString()}] Couldn't prepare ${name} for the build`;
|
|
1233
|
+
if (sourceProblem === 'snapshot_unavailable' && assignment.route === 'local' && local?.branch) {
|
|
1234
|
+
let folderCommit = 'unknown';
|
|
1235
|
+
try {
|
|
1236
|
+
folderCommit = (await resolveLocalBuildCommit(local.repoPath, local.branch, new AbortController().signal)).slice(0, 7);
|
|
1237
|
+
}
|
|
1238
|
+
catch { /* the reason below still names the code */ }
|
|
1239
|
+
input.log(`${prefix}: the folder's ${local.branch} branch is at ${folderCommit}, but Truing asked for ${assignment.snapshotSha.slice(0, 7)} (snapshot_unavailable). Bring the folder level with GitHub and start the map again.`);
|
|
1240
|
+
}
|
|
1241
|
+
else if (reason instanceof WholeReadGitError) {
|
|
1242
|
+
input.log(`${prefix}: ${sourceProblem === 'branch_missing' ? "the folder's branch isn't set"
|
|
1243
|
+
: sourceProblem === 'folder_missing' ? "the folder isn't where Truing expects it"
|
|
1244
|
+
: sourceProblem === 'snapshot_unavailable' ? 'the code Truing asked for could not be fetched'
|
|
1245
|
+
: 'git could not read the code'} (${reason.code}).`);
|
|
1246
|
+
}
|
|
1247
|
+
else {
|
|
1248
|
+
input.log(`${prefix}: ${safeReason(reason)} (${sourceProblem}).`);
|
|
1249
|
+
}
|
|
1250
|
+
return { verified: false, sourceProblem };
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1185
1253
|
async function runWholeReadAssignment(input) {
|
|
1186
1254
|
const connection = input.connections.find((candidate) => candidate.connectionId === input.assignment.connectionId);
|
|
1187
1255
|
const local = connection && !connection.managed ? connection : undefined;
|
|
@@ -1203,35 +1271,14 @@ async function runWholeReadAssignment(input) {
|
|
|
1203
1271
|
return { status: 'not_claimed' };
|
|
1204
1272
|
}
|
|
1205
1273
|
if (input.assignment.state === 'offered') {
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
const source = await acquireAssignedSource({
|
|
1210
|
-
route: input.assignment.route,
|
|
1211
|
-
acquireLocal: () => local?.branch
|
|
1212
|
-
? acquireLocalSource({ repoPath: local.repoPath, branch: local.branch,
|
|
1213
|
-
snapshotSha: input.assignment.snapshotSha, signal })
|
|
1214
|
-
: Promise.reject(new WholeReadGitError('snapshot_unavailable')),
|
|
1215
|
-
acquireGithubCompanion: () => {
|
|
1216
|
-
const repositoryUrl = `https://github.com/${githubLabel(parseGitHubRepo(input.assignment.canonicalRepository))}.git`;
|
|
1217
|
-
return acquireGithubCompanionSource({ lease, repositoryUrl,
|
|
1218
|
-
snapshotSha: input.assignment.snapshotSha, signal });
|
|
1219
|
-
},
|
|
1220
|
-
});
|
|
1221
|
-
if (!source)
|
|
1222
|
-
throw new WholeReadGitError('snapshot_unavailable');
|
|
1223
|
-
return source;
|
|
1224
|
-
});
|
|
1225
|
-
await acquired.release();
|
|
1226
|
-
verified = true;
|
|
1227
|
-
}
|
|
1228
|
-
catch {
|
|
1229
|
-
verified = false;
|
|
1230
|
-
}
|
|
1274
|
+
const check = await verifyAssignmentSource({ pairing: input.pairing, assignment: input.assignment,
|
|
1275
|
+
local, sharedSources: input.sharedSources, log: input.log, reportedFailures: input.reportedFailures });
|
|
1276
|
+
const verified = check.verified;
|
|
1231
1277
|
const acceptance = await input.client.acceptBuildAssignment(input.assignment, {
|
|
1232
1278
|
lsRemoteVerified: verified, exactCommitFetched: verified,
|
|
1233
1279
|
backend: input.assignment.frozenBackend, backendReady,
|
|
1234
1280
|
routeSupported: routeReadiness === 'ready',
|
|
1281
|
+
...(check.verified ? {} : { sourceProblem: check.sourceProblem }),
|
|
1235
1282
|
});
|
|
1236
1283
|
if (acceptance.status !== 'ready')
|
|
1237
1284
|
return { status: 'not_claimed' };
|
|
@@ -1500,6 +1547,7 @@ async function runPairing(pairing, options) {
|
|
|
1500
1547
|
const sharedSources = createWholeReadSharedSourceManager({
|
|
1501
1548
|
onCleanupPending: () => { error('[whole-read-temp] cleanup_pending'); },
|
|
1502
1549
|
});
|
|
1550
|
+
const reportedFailures = new Map();
|
|
1503
1551
|
const wholeReadPool = createWholeReadAssignmentPool({
|
|
1504
1552
|
key: (assignment) => assignment.id,
|
|
1505
1553
|
mayClaim,
|
|
@@ -1508,6 +1556,7 @@ async function runPairing(pairing, options) {
|
|
|
1508
1556
|
usageClaimLimit--; },
|
|
1509
1557
|
run: (assignment) => runWholeReadAssignment({ pairing, client, assignment,
|
|
1510
1558
|
connections: activeConnections, runtimes, workspaceRuntime, sharedSources,
|
|
1559
|
+
log: (message) => error(message), reportedFailures,
|
|
1511
1560
|
onUsageLimit: () => recordCompletedClaim('usage limit reached'),
|
|
1512
1561
|
shouldStop: options.shouldStop }),
|
|
1513
1562
|
onError: (reason) => {
|
package/dist/whole-read-temp.js
CHANGED
|
@@ -174,7 +174,10 @@ export function createCompanionAttemptSourceManager(dependencies = {}) {
|
|
|
174
174
|
const reportCleanup = dependencies.reportCleanup ?? (async () => false);
|
|
175
175
|
const scheduleInterval = dependencies.setInterval ?? setInterval;
|
|
176
176
|
const cancelInterval = dependencies.clearInterval ?? clearInterval;
|
|
177
|
-
|
|
177
|
+
// On by default: Truing's server decides whether build 3 runs (its own WHOLE_READ_BUILDS switch), and a
|
|
178
|
+
// released connector must carry it without the user setting anything (TRUING.md §9). WHOLE_READ_BUILDS=0
|
|
179
|
+
// on the user's computer is an emergency off switch.
|
|
180
|
+
const buildsEnabled = dependencies.buildsEnabled ?? (() => process.env.WHOLE_READ_BUILDS !== '0');
|
|
178
181
|
const readers = new Map();
|
|
179
182
|
const activeLocations = new Set();
|
|
180
183
|
const cleanupJobs = new Map();
|