@link-assistant/hive-mind 1.72.6 → 1.72.7

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 CHANGED
@@ -1,5 +1,11 @@
1
1
  # @link-assistant/hive-mind
2
2
 
3
+ ## 1.72.7
4
+
5
+ ### Patch Changes
6
+
7
+ - 61e2935: Fix "Failed to add .gitkeep" abort during auto-PR creation when the target repository's `.gitignore` matches the seed placeholder (issue #1825). Placeholder staging now routes through `addPlaceholderFileToGit`, which detects the ignored path with `git check-ignore` and retries with `git add -f`. Because the placeholder is created by the solver to seed the initial commit and removed once the task completes, force-adding it is safe.
8
+
3
9
  ## 1.72.6
4
10
 
5
11
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@link-assistant/hive-mind",
3
- "version": "1.72.6",
3
+ "version": "1.72.7",
4
4
  "description": "AI-powered issue solver and hive mind for collaborative problem solving",
5
5
  "main": "src/hive.mjs",
6
6
  "type": "module",
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Placeholder-staging helper for auto PR creation.
3
+ *
4
+ * Extracted from solve.auto-pr.lib.mjs (issue #1825) to keep that module under
5
+ * the max-lines lint budget.
6
+ */
7
+
8
+ /**
9
+ * Stage the temporary placeholder file (CLAUDE.md or .gitkeep) used to seed the
10
+ * initial auto-PR commit.
11
+ *
12
+ * The solver writes this placeholder deliberately to create the first commit so
13
+ * a draft PR can be opened, and removes it again once the task completes (see
14
+ * cleanupClaudeFile in solve.results.lib.mjs). When the target repository's
15
+ * .gitignore matches the placeholder — issue #1825: e.g. rumaster/tg-games
16
+ * ignores `.gitkeep` — a plain `git add <file>` exits non-zero with
17
+ * "The following paths are ignored by one of your .gitignore files", which
18
+ * previously aborted PR creation with a fatal "Failed to add .gitkeep".
19
+ *
20
+ * Because the placeholder belongs to us and is short-lived, we confirm the path
21
+ * is actually ignored with `git check-ignore` and then retry with
22
+ * `git add -f`. Force-adding only happens for the ignored-placeholder case;
23
+ * any other add failure is surfaced unchanged so genuine errors are not masked.
24
+ *
25
+ * @param {object} params
26
+ * @param {Function} params.$ - command-stream tagged-template runner.
27
+ * @param {string} params.tempDir - repository working directory.
28
+ * @param {string} params.fileName - placeholder file name (CLAUDE.md or .gitkeep).
29
+ * @param {Function} [params.log] - async logger.
30
+ * @param {Function} [params.formatAligned] - log line formatter.
31
+ * @param {boolean} [params.verbose] - emit verbose diagnostics.
32
+ * @returns {Promise<{code: number, forced: boolean, ignored: boolean, stderr: string}>}
33
+ */
34
+ export async function addPlaceholderFileToGit({ $, tempDir, fileName, log, formatAligned, verbose = false }) {
35
+ // Run silently: `git add` is quiet on success and only emits the noisy
36
+ // "paths are ignored ... Use -f" hint on failure, which we capture in
37
+ // `stderr` and re-surface from the caller only when the failure is genuine.
38
+ const addResult = await $({ cwd: tempDir, silent: true })`git add ${fileName}`;
39
+ if (addResult.code === 0) {
40
+ return { code: 0, forced: false, ignored: false, stderr: '' };
41
+ }
42
+
43
+ const stderr = addResult.stderr ? addResult.stderr.toString() : '';
44
+
45
+ // Determine whether the add failed because the placeholder is git-ignored.
46
+ // `git check-ignore` exits 0 when the path matches a .gitignore rule.
47
+ const checkIgnore = await $({ cwd: tempDir, silent: true })`git check-ignore ${fileName}`;
48
+ const ignored = checkIgnore.code === 0;
49
+
50
+ if (!ignored) {
51
+ // The failure was not caused by .gitignore — surface the original error so
52
+ // genuine problems (permissions, corrupt index, ...) are not masked.
53
+ return { code: addResult.code, forced: false, ignored: false, stderr };
54
+ }
55
+
56
+ if (log && formatAligned) {
57
+ await log(formatAligned('ℹ️', `${fileName} is ignored:`, 'Force-adding placeholder (git add -f)'));
58
+ }
59
+ if (verbose && log) {
60
+ await log(` ${fileName} matched a .gitignore rule; retrying with: git add -f ${fileName}`, { verbose: true });
61
+ }
62
+
63
+ const forcedResult = await $({ cwd: tempDir, silent: true })`git add -f ${fileName}`;
64
+ return {
65
+ code: forcedResult.code,
66
+ forced: true,
67
+ ignored: true,
68
+ stderr: forcedResult.stderr ? forcedResult.stderr.toString() : '',
69
+ };
70
+ }
@@ -8,6 +8,7 @@ import { handleRejectedPushForAutoPr, synchronizeExistingIssueBranchBeforeAutoPr
8
8
  import { emitForkAwareDiagnostic } from './solve.auto-pr-fork-diagnostic.lib.mjs';
9
9
 
10
10
  import { wrapDollarWithGhRetry as _wrapDollarWithGhRetry, execGhWithRetry } from './github-rate-limit.lib.mjs'; // rate-limit marker (#1726): gh API calls flow through $ wrapped by caller. Issue #1756: execGhWithRetry retries on transient 5xx (504) too.
11
+ import { addPlaceholderFileToGit } from './solve.auto-pr-placeholder.lib.mjs'; // Issue #1825: force-adds the seed placeholder when the target repo gitignores it.
11
12
 
12
13
  export async function handleAutoPrCreation({ argv, tempDir, branchName, issueNumber, owner, repo, defaultBranch, forkedRepo, isContinueMode, prNumber, log, formatAligned, $, reportError, path, fs }) {
13
14
  // Skip auto-PR creation if:
@@ -166,12 +167,13 @@ Proceed.
166
167
  // Add and commit the file
167
168
  await log(formatAligned('📦', 'Adding file:', 'To git staging'));
168
169
 
169
- // Use explicit cwd option for better reliability
170
- const addResult = await $({ cwd: tempDir })`git add ${fileName}`;
170
+ // Issue #1825: force-adds the placeholder when the target repo gitignores
171
+ // it (e.g. ignores `.gitkeep`), so PR creation is no longer aborted.
172
+ const addResult = await addPlaceholderFileToGit({ $, tempDir, fileName, log, formatAligned, verbose: argv.verbose });
171
173
 
172
174
  if (addResult.code !== 0) {
173
175
  await log(`❌ Failed to add ${fileName}`, { level: 'error' });
174
- await log(` Error: ${addResult.stderr ? addResult.stderr.toString() : 'Unknown error'}`, { level: 'error' });
176
+ await log(` Error: ${addResult.stderr || 'Unknown error'}`, { level: 'error' });
175
177
  throw new Error(`Failed to add ${fileName}`);
176
178
  }
177
179
 
@@ -212,12 +214,12 @@ Proceed.
212
214
  await fs.writeFile(gitkeepPath, gitkeepContent);
213
215
  await log(formatAligned('✅', 'Created:', '.gitkeep file'));
214
216
 
215
- // Try to add .gitkeep
216
- const gitkeepAddResult = await $({ cwd: tempDir })`git add .gitkeep`;
217
+ // Try to add .gitkeep (force-added if it too is gitignored — issue #1825)
218
+ const gitkeepAddResult = await addPlaceholderFileToGit({ $, tempDir, fileName: '.gitkeep', log, formatAligned, verbose: argv.verbose });
217
219
 
218
220
  if (gitkeepAddResult.code !== 0) {
219
221
  await log('❌ Failed to add .gitkeep', { level: 'error' });
220
- await log(` Error: ${gitkeepAddResult.stderr ? gitkeepAddResult.stderr.toString() : 'Unknown error'}`, {
222
+ await log(` Error: ${gitkeepAddResult.stderr || 'Unknown error'}`, {
221
223
  level: 'error',
222
224
  });
223
225
  throw new Error('Failed to add .gitkeep');