@link-assistant/hive-mind 2.11.4 → 2.11.6
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/CHANGELOG.md +14 -0
- package/package.json +1 -1
- package/src/agent.lib.mjs +13 -10
- package/src/bidirectional-interactive.lib.mjs +2 -1
- package/src/claude.lib.mjs +13 -14
- package/src/codex.lib.mjs +29 -70
- package/src/codex.run-diagnostics.lib.mjs +117 -0
- package/src/formal-ai-runtime.lib.mjs +439 -0
- package/src/formal-ai.lib.mjs +143 -41
- package/src/gemini.lib.mjs +6 -8
- package/src/git.lib.mjs +10 -1
- package/src/github-error-reporter.lib.mjs +2 -1
- package/src/github-rate-limit.lib.mjs +13 -0
- package/src/github-terminal-state.lib.mjs +7 -1
- package/src/github.lib.mjs +16 -8
- package/src/opencode.lib.mjs +11 -10
- package/src/post-finish-sanitization-sweep.lib.mjs +4 -3
- package/src/quiet-probe.lib.mjs +72 -0
- package/src/qwen.lib.mjs +8 -7
- package/src/solve.auto-continue.lib.mjs +2 -1
- package/src/solve.auto-pr.lib.mjs +11 -5
- package/src/solve.branch-errors.lib.mjs +2 -1
- package/src/solve.execution.lib.mjs +2 -1
- package/src/solve.feedback.lib.mjs +18 -13
- package/src/solve.fork-sync.lib.mjs +2 -1
- package/src/solve.repo-setup.lib.mjs +40 -4
- package/src/solve.repository.lib.mjs +4 -3
- package/src/solve.results.lib.mjs +3 -2
- package/src/solve.validation.lib.mjs +7 -0
- package/src/token-sanitization.lib.mjs +7 -2
|
@@ -14,6 +14,7 @@ const use = globalThis.use;
|
|
|
14
14
|
|
|
15
15
|
// Use command-stream for consistent $ behavior; wrap with rate-limit retry (#1726)
|
|
16
16
|
const { wrapDollarWithGhRetry } = await import('./github-rate-limit.lib.mjs');
|
|
17
|
+
const { QUIET_PROBE } = await import('./quiet-probe.lib.mjs'); // issue #2130: keep read-only probe payloads out of the attached log
|
|
17
18
|
const $ = wrapDollarWithGhRetry((await use('command-stream')).$);
|
|
18
19
|
|
|
19
20
|
// Import shared library functions
|
|
@@ -179,7 +180,7 @@ export const setupUpstreamAndSync = async (tempDir, forkedRepo, upstreamRemote,
|
|
|
179
180
|
// branch. Attempting the push there is guaranteed to be rejected
|
|
180
181
|
// with "permission denied" and is unnecessary, so we skip it and
|
|
181
182
|
// keep working on the PR branch.
|
|
182
|
-
const currentUserResult = await
|
|
183
|
+
const currentUserResult = await $(QUIET_PROBE)`gh api user --jq .login`;
|
|
183
184
|
const currentUser = currentUserResult.code === 0 ? currentUserResult.stdout.toString().trim() : null;
|
|
184
185
|
const pushDecision = shouldPushDefaultBranchToFork({ currentUser, forkedRepo });
|
|
185
186
|
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
// Issue #1625: centralized markers + tracked posting for the "empty repo"
|
|
7
7
|
// issue comment so it's excluded from --auto-attach-solution-summary's check.
|
|
8
8
|
import { REPOSITORY_INITIALIZATION_REQUIRED_MARKER, postTrackedComment } from './tool-comments.lib.mjs';
|
|
9
|
+
import { QUIET_PROBE } from './quiet-probe.lib.mjs'; // issue #2130: keep read-only probe payloads out of the attached log
|
|
9
10
|
|
|
10
11
|
export async function setupRepositoryAndClone({ argv, owner, repo, forkOwner, forkRepoName, tempDir, isContinueMode, issueUrl, log, $, needsClone = true }) {
|
|
11
12
|
// Set up repository and handle forking
|
|
@@ -28,14 +29,49 @@ export async function setupRepositoryAndClone({ argv, owner, repo, forkOwner, fo
|
|
|
28
29
|
const prForkRemote = await setupPrForkRemote(tempDir, argv, prForkOwner, repo, isContinueMode, owner);
|
|
29
30
|
|
|
30
31
|
// Set up git authentication using gh
|
|
31
|
-
|
|
32
|
-
if (authSetupResult.code !== 0) {
|
|
33
|
-
await log('Note: gh auth setup-git had issues, continuing anyway\n');
|
|
34
|
-
}
|
|
32
|
+
await setupGitCredentialHelper({ tempDir, log, $ });
|
|
35
33
|
|
|
36
34
|
return { repoToClone, forkedRepo, upstreamRemote, prForkRemote, prForkOwner };
|
|
37
35
|
}
|
|
38
36
|
|
|
37
|
+
/**
|
|
38
|
+
* Point git at `gh` for GitHub credentials.
|
|
39
|
+
*
|
|
40
|
+
* Issue #2130: `gh auth setup-git` only ever writes the *global* gitconfig. In
|
|
41
|
+
* a container where `~/.gitconfig` is bind-mounted, git cannot replace it and
|
|
42
|
+
* gh reports `failed to set up git credential helper: failed to run git: error:
|
|
43
|
+
* could not write config file /home/box/.gitconfig: Device or resource busy`.
|
|
44
|
+
* Hive Mind used to mirror that line raw and continue with no credential helper
|
|
45
|
+
* at all, so the real failure only surfaced later as a push error.
|
|
46
|
+
*
|
|
47
|
+
* The clone-local config is equivalent for our purposes and is never
|
|
48
|
+
* bind-mounted, so it is used as the fallback. The empty `helper` entry first
|
|
49
|
+
* clears any inherited helper, exactly as `gh auth setup-git` does.
|
|
50
|
+
*/
|
|
51
|
+
export async function setupGitCredentialHelper({ tempDir, log, $, hosts = ['github.com'] }) {
|
|
52
|
+
const authSetupResult = await $({ cwd: tempDir, ...QUIET_PROBE })`gh auth setup-git 2>&1`;
|
|
53
|
+
if (authSetupResult.code === 0) return { scope: 'global', hosts };
|
|
54
|
+
|
|
55
|
+
const reason = (authSetupResult.stdout?.toString() || authSetupResult.stderr?.toString() || '').trim();
|
|
56
|
+
await log(`ℹ️ gh auth setup-git could not write the global gitconfig${reason ? `: ${reason.split('\n')[0]}` : ''}`, { verbose: true });
|
|
57
|
+
|
|
58
|
+
const failures = [];
|
|
59
|
+
for (const host of hosts) {
|
|
60
|
+
const key = `credential.https://${host}.helper`;
|
|
61
|
+
const cleared = await $({ cwd: tempDir, ...QUIET_PROBE })`git config --local --replace-all ${key} ""`;
|
|
62
|
+
const configured = await $({ cwd: tempDir, ...QUIET_PROBE })`git config --local --add ${key} ${'!gh auth git-credential'}`;
|
|
63
|
+
if (cleared.code !== 0 || configured.code !== 0) failures.push(host);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (failures.length) {
|
|
67
|
+
await log(`⚠️ Could not configure a git credential helper for ${failures.join(', ')} - pushes may require credentials in the remote URL`, { level: 'warning' });
|
|
68
|
+
return { scope: 'none', hosts: failures };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
await log('🔑 Configured the gh credential helper for this clone (the global gitconfig is not writable)', { verbose: true });
|
|
72
|
+
return { scope: 'local', hosts };
|
|
73
|
+
}
|
|
74
|
+
|
|
39
75
|
async function setupRepository(argv, owner, repo, forkOwner, issueUrl, forkRepoName) {
|
|
40
76
|
const repository = await import('./solve.repository.lib.mjs');
|
|
41
77
|
const { setupRepository: setupRepoFn } = repository;
|
|
@@ -14,6 +14,7 @@ const use = globalThis.use;
|
|
|
14
14
|
|
|
15
15
|
// Use command-stream for consistent $ behavior; wrap with rate-limit retry (#1726)
|
|
16
16
|
const { wrapDollarWithGhRetry } = await import('./github-rate-limit.lib.mjs');
|
|
17
|
+
const { QUIET_PROBE } = await import('./quiet-probe.lib.mjs'); // issue #2130: keep read-only probe payloads out of the attached log
|
|
17
18
|
const $ = wrapDollarWithGhRetry((await use('command-stream')).$);
|
|
18
19
|
const os = (await use('os')).default;
|
|
19
20
|
const path = (await use('path')).default;
|
|
@@ -57,7 +58,7 @@ export const getRootRepository = async (owner, repo) => {
|
|
|
57
58
|
// Check if current user has a fork of the given root repository
|
|
58
59
|
export const checkExistingForkOfRoot = async rootRepo => {
|
|
59
60
|
try {
|
|
60
|
-
const userResult = await lib.ghCmdRetry(() =>
|
|
61
|
+
const userResult = await lib.ghCmdRetry(() => $(QUIET_PROBE)`gh api user --jq .login`, { label: 'get user (fork check)' });
|
|
61
62
|
if (userResult.code !== 0) return null;
|
|
62
63
|
const currentUser = userResult.stdout.toString().trim();
|
|
63
64
|
// Issue #2119: build the jq expression in JS. Its double quotes belong to jq,
|
|
@@ -378,7 +379,7 @@ export const setupRepository = async (argv, owner, repo, forkOwner = null, issue
|
|
|
378
379
|
await log(`${formatAligned('', 'Checking fork status...', '')}\n`);
|
|
379
380
|
|
|
380
381
|
// Get current user (issue #1536: retry on transient network errors)
|
|
381
|
-
const userResult = await lib.ghCmdRetry(() =>
|
|
382
|
+
const userResult = await lib.ghCmdRetry(() => $(QUIET_PROBE)`gh api user --jq .login`, { label: 'get current user' });
|
|
382
383
|
if (userResult.code !== 0) {
|
|
383
384
|
await log(`${formatAligned('❌', 'Error:', 'Failed to get current user')}`);
|
|
384
385
|
await safeExit(1, 'Repository setup failed');
|
|
@@ -1191,7 +1192,7 @@ export const setupPrForkRemote = async (tempDir, argv, prForkOwner, repo, isCont
|
|
|
1191
1192
|
|
|
1192
1193
|
// Get current user to check if it's someone else's fork
|
|
1193
1194
|
await log(`\n${formatAligned('🔍', 'Checking PR fork:', 'Determining if branch is in another fork...')}`);
|
|
1194
|
-
const userResult = await
|
|
1195
|
+
const userResult = await $(QUIET_PROBE)`gh api user --jq .login`;
|
|
1195
1196
|
if (userResult.code !== 0) {
|
|
1196
1197
|
await log(`${formatAligned('⚠️', 'Warning:', 'Failed to get current user, cannot set up pr-fork remote')}`);
|
|
1197
1198
|
return null;
|
|
@@ -15,6 +15,7 @@ const use = globalThis.use;
|
|
|
15
15
|
// Use command-stream for consistent $ behavior across runtimes
|
|
16
16
|
const { $: __rawDollar$ } = await use('command-stream');
|
|
17
17
|
const { wrapDollarWithGhRetry } = await import('./github-rate-limit.lib.mjs');
|
|
18
|
+
const { QUIET_PROBE } = await import('./quiet-probe.lib.mjs'); // issue #2130: keep read-only probe payloads out of the attached log
|
|
18
19
|
const $ = wrapDollarWithGhRetry(__rawDollar$);
|
|
19
20
|
const path = (await use('path')).default;
|
|
20
21
|
|
|
@@ -719,7 +720,7 @@ export const verifyResults = async (owner, repo, branchName, issueNumber, prNumb
|
|
|
719
720
|
|
|
720
721
|
try {
|
|
721
722
|
// Get the current user's GitHub username
|
|
722
|
-
const userResult = await
|
|
723
|
+
const userResult = await $(QUIET_PROBE)`gh api user --jq .login`;
|
|
723
724
|
|
|
724
725
|
if (userResult.code !== 0) {
|
|
725
726
|
throw new Error(`Failed to get current user: ${userResult.stderr ? userResult.stderr.toString() : 'Unknown error'}`);
|
|
@@ -1139,7 +1140,7 @@ export const { TOOL_GENERATED_COMMENT_MARKERS, isToolGeneratedComment, trackTool
|
|
|
1139
1140
|
export const checkForAiCreatedComments = async (sessionStartTime, owner, repo, prNumber, issueNumber) => {
|
|
1140
1141
|
try {
|
|
1141
1142
|
// Get the current user's GitHub username
|
|
1142
|
-
const userResult = await
|
|
1143
|
+
const userResult = await $(QUIET_PROBE)`gh api user --jq .login`;
|
|
1143
1144
|
if (userResult.code !== 0) {
|
|
1144
1145
|
return false; // Cannot determine, default to not attaching
|
|
1145
1146
|
}
|
|
@@ -308,13 +308,20 @@ export const performSystemChecks = async (minDiskSpace = 10240, skipToolConnecti
|
|
|
308
308
|
const { validateFormalAiToolConnection } = await import('./formal-ai.lib.mjs');
|
|
309
309
|
const formalAiValidation = await validateFormalAiToolConnection(argv.tool || 'claude');
|
|
310
310
|
isToolConnected = formalAiValidation.valid;
|
|
311
|
+
// Record the wrapper version on both paths: the wrapper builds the tool's
|
|
312
|
+
// argv, so its version is the first thing needed to explain a failure
|
|
313
|
+
// (issue #2130's logs recorded neither, which left the round-2 claude
|
|
314
|
+
// failure unattributable).
|
|
315
|
+
const formalAiVersionLine = `📦 Formal AI wrapper version: ${formalAiValidation.formalAiVersion || 'unknown'}`;
|
|
311
316
|
if (isToolConnected) {
|
|
312
317
|
await log(`✅ Formal AI wrapper and ${argv.tool || 'claude'} CLI are available`);
|
|
318
|
+
await log(formalAiVersionLine);
|
|
313
319
|
if (formalAiValidation.version) {
|
|
314
320
|
await log(`📦 ${argv.tool || 'claude'} CLI version: ${formalAiValidation.version}`);
|
|
315
321
|
}
|
|
316
322
|
} else {
|
|
317
323
|
await log(`❌ Formal AI dispatch validation failed: ${formalAiValidation.error}`, { level: 'error' });
|
|
324
|
+
await log(` ${formalAiVersionLine}`, { level: 'error' });
|
|
318
325
|
await log(' Install or update the wrapper with: cargo install formal-ai', { level: 'error' });
|
|
319
326
|
return false;
|
|
320
327
|
}
|
|
@@ -24,6 +24,7 @@ import { reportError } from './sentry.lib.mjs';
|
|
|
24
24
|
export { createCredentialStreamSanitizer };
|
|
25
25
|
|
|
26
26
|
import { wrapDollarWithGhRetry as _wrapDollarWithGhRetry } from './github-rate-limit.lib.mjs'; // rate-limit marker (#1726): gh API calls flow through $ wrapped by caller
|
|
27
|
+
import { QUIET_PROBE } from './quiet-probe.lib.mjs'; // issue #2130: never mirror the call that discovers which secrets must be masked
|
|
27
28
|
// Dynamic imports for runtime dependencies
|
|
28
29
|
const getOsModule = async () => (await import('os')).default;
|
|
29
30
|
const getPathModule = async () => (await import('path')).default;
|
|
@@ -255,8 +256,12 @@ export const getGitHubTokensFromCommand = async () => {
|
|
|
255
256
|
const tokens = [];
|
|
256
257
|
|
|
257
258
|
try {
|
|
258
|
-
// Run gh auth status to get token info
|
|
259
|
-
|
|
259
|
+
// Run gh auth status to get token info.
|
|
260
|
+
// Issue #2130: never mirror this. The whole point of the call is to learn
|
|
261
|
+
// which secrets have to be masked, so its output is the one thing that is
|
|
262
|
+
// guaranteed to be unmasked at this moment - and it was being echoed into
|
|
263
|
+
// the log that later gets attached to the pull request.
|
|
264
|
+
const authResult = await $(QUIET_PROBE)`gh auth status 2>&1`.catch(() => ({ stdout: '', stderr: '' }));
|
|
260
265
|
const authOutput = authResult.stdout?.toString() + authResult.stderr?.toString() || '';
|
|
261
266
|
|
|
262
267
|
// Look for token patterns in the output
|