@withtruing/companion 0.14.1 → 0.14.2

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.
Files changed (2) hide show
  1. package/dist/cli.js +75 -26
  2. 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
- let verified = false;
1207
- try {
1208
- const acquired = await input.sharedSources.acquire(wholeReadSharedSourceKey(input.pairing, input.assignment), async (lease, signal) => {
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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@withtruing/companion",
3
- "version": "0.14.1",
3
+ "version": "0.14.2",
4
4
  "description": "The Truing companion: reads your code and runs AI on your own computer, for Truing.",
5
5
  "type": "module",
6
6
  "license": "MIT",