@haystackeditor/cli 0.14.3 → 0.14.5
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/commands/setup.js +32 -2
- package/dist/index.js +5 -1
- package/dist/utils/github-api.js +1 -1
- package/package.json +1 -1
package/dist/commands/setup.js
CHANGED
|
@@ -356,8 +356,17 @@ class GitHubWriteError extends Error {
|
|
|
356
356
|
* the file, and surfaces a real error if the write itself fails. */
|
|
357
357
|
async function fetchFileSha(owner, repo, path, token) {
|
|
358
358
|
const res = await fetch(`${GITHUB_PROXY}/repos/${owner}/${repo}/contents/${path}`, { headers: ghHeaders(token) });
|
|
359
|
-
if (!res.ok)
|
|
359
|
+
if (!res.ok) {
|
|
360
|
+
if (res.status !== 404) {
|
|
361
|
+
trackError('haystack_setup_fetch_file_sha_failed', {
|
|
362
|
+
owner,
|
|
363
|
+
repo,
|
|
364
|
+
path,
|
|
365
|
+
status: res.status,
|
|
366
|
+
});
|
|
367
|
+
}
|
|
360
368
|
return null;
|
|
369
|
+
}
|
|
361
370
|
const data = (await res.json());
|
|
362
371
|
return data.sha ?? null;
|
|
363
372
|
}
|
|
@@ -463,9 +472,11 @@ async function writeOnboardingFilesToRepo(owner, repo, files, autoMergeEnabled,
|
|
|
463
472
|
for (const f of files) {
|
|
464
473
|
shaByPath.set(f.path, await fetchFileSha(owner, repo, f.path, token));
|
|
465
474
|
}
|
|
475
|
+
let successfulWrites = 0;
|
|
466
476
|
try {
|
|
467
477
|
for (const f of files) {
|
|
468
478
|
await putFile(owner, repo, f.path, f.content, f.message, shaByPath.get(f.path) ?? null, token);
|
|
479
|
+
successfulWrites++;
|
|
469
480
|
}
|
|
470
481
|
return {};
|
|
471
482
|
}
|
|
@@ -475,6 +486,9 @@ async function writeOnboardingFilesToRepo(owner, repo, files, autoMergeEnabled,
|
|
|
475
486
|
const status = err instanceof GitHubWriteError ? err.status : 0;
|
|
476
487
|
if (status !== 409 && status !== 422)
|
|
477
488
|
throw err;
|
|
489
|
+
if (successfulWrites > 0) {
|
|
490
|
+
throw err;
|
|
491
|
+
}
|
|
478
492
|
// Probe GitHub's *structured* protection signals to decide: protection
|
|
479
493
|
// (→ PR fallback) vs. a genuine bad request / sha conflict (→ surface the
|
|
480
494
|
// error). This replaces brittle error-message substring matching.
|
|
@@ -514,6 +528,8 @@ async function runUnifiedScan(repo, token) {
|
|
|
514
528
|
if (!runId)
|
|
515
529
|
throw new Error('Scan kickoff returned no runId');
|
|
516
530
|
let lastProgressKey = '';
|
|
531
|
+
let loggedPollFetchError = false;
|
|
532
|
+
let loggedPollStatusError = false;
|
|
517
533
|
// eslint-disable-next-line no-constant-condition
|
|
518
534
|
while (true) {
|
|
519
535
|
await new Promise((resolve) => setTimeout(resolve, SCAN_POLL_INTERVAL_MS));
|
|
@@ -521,9 +537,16 @@ async function runUnifiedScan(repo, token) {
|
|
|
521
537
|
try {
|
|
522
538
|
statusResp = await fetch(`${HAYSTACK_API}/api/onboarding/scan/status?runId=${encodeURIComponent(runId)}`, { headers: { Authorization: `Bearer ${token}` } });
|
|
523
539
|
}
|
|
524
|
-
catch {
|
|
540
|
+
catch (err) {
|
|
525
541
|
// Transient network blip — the KV state is authoritative and won't vanish
|
|
526
542
|
// from one failed poll, so keep going.
|
|
543
|
+
if (!loggedPollFetchError) {
|
|
544
|
+
loggedPollFetchError = true;
|
|
545
|
+
trackError('haystack_setup_scan_status_poll_fetch_error', {
|
|
546
|
+
repo,
|
|
547
|
+
error: err instanceof Error ? err.message : String(err),
|
|
548
|
+
});
|
|
549
|
+
}
|
|
527
550
|
continue;
|
|
528
551
|
}
|
|
529
552
|
if (statusResp.status === 404) {
|
|
@@ -533,6 +556,13 @@ async function runUnifiedScan(repo, token) {
|
|
|
533
556
|
}
|
|
534
557
|
if (!statusResp.ok) {
|
|
535
558
|
// Transient (5xx etc.) — back off and retry on the next tick.
|
|
559
|
+
if (!loggedPollStatusError) {
|
|
560
|
+
loggedPollStatusError = true;
|
|
561
|
+
trackError('haystack_setup_scan_status_poll_non_ok', {
|
|
562
|
+
repo,
|
|
563
|
+
status: statusResp.status,
|
|
564
|
+
});
|
|
565
|
+
}
|
|
536
566
|
continue;
|
|
537
567
|
}
|
|
538
568
|
const state = (await statusResp.json());
|
package/dist/index.js
CHANGED
|
@@ -45,7 +45,11 @@ function getVersion() {
|
|
|
45
45
|
const pkgPath = join(dirname(fileURLToPath(import.meta.url)), '..', 'package.json');
|
|
46
46
|
return JSON.parse(readFileSync(pkgPath, 'utf8')).version ?? '0.0.0';
|
|
47
47
|
}
|
|
48
|
-
catch {
|
|
48
|
+
catch (err) {
|
|
49
|
+
// package.json ships inside the npm tarball, so this should never happen —
|
|
50
|
+
// but log to stderr instead of silently reporting a wrong version
|
|
51
|
+
// (PR001: no silent fallback). stderr keeps the stdout `--version` clean.
|
|
52
|
+
console.error('haystack: could not read version from package.json:', err instanceof Error ? err.message : err);
|
|
49
53
|
return '0.0.0';
|
|
50
54
|
}
|
|
51
55
|
}
|
package/dist/utils/github-api.js
CHANGED
|
@@ -84,7 +84,7 @@ async function githubApiRequest(method, path, token, body) {
|
|
|
84
84
|
// (e.g. the App isn't installed on this owner), fall back to the original
|
|
85
85
|
// response so handleApiError surfaces GitHub's actual "org restricted" 403.
|
|
86
86
|
const proxied = await fetch(`${GITHUB_PROXY_BASE}${path}`, init);
|
|
87
|
-
return proxied.
|
|
87
|
+
return proxied.status === 403 ? direct : proxied;
|
|
88
88
|
}
|
|
89
89
|
/**
|
|
90
90
|
* Handle API errors consistently
|