@link-assistant/hive-mind 2.4.1 → 2.5.1

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,17 @@
1
1
  # @link-assistant/hive-mind
2
2
 
3
+ ## 2.5.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 4054bcf: Commit the `--development-log` artifacts before signalling pull request readiness (issue #2048), so the development-log commit is part of the diff that CI and `--auto-restart-until-mergeable` evaluate. Previously the log commit landed after the "Ready to merge" signal and could break CI (e.g. a missing changeset) with no readiness re-evaluation.
8
+
9
+ ## 2.5.0
10
+
11
+ ### Minor Changes
12
+
13
+ - 152f55a: Add generation-relative `sol`, `terra`, and `luna` Codex aliases and accept `openai/` and `openai.` prefixes for every known OpenAI model.
14
+
3
15
  ## 2.4.1
4
16
 
5
17
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@link-assistant/hive-mind",
3
- "version": "2.4.1",
3
+ "version": "2.5.1",
4
4
  "description": "AI-powered issue solver and hive mind for collaborative problem solving",
5
5
  "main": "src/hive.mjs",
6
6
  "type": "module",
@@ -234,6 +234,9 @@ export const collectAndCommitDevelopmentLogArtifacts = async ({ enabled, reposit
234
234
  return { skipped: 'missing-repository-path' };
235
235
  }
236
236
 
237
+ // Issue #2048: verbose trace so the commit timing (relative to PR readiness signals) is diagnosable from logs.
238
+ await log?.(`🔍 Development log finalize: issue #${issueNumber ?? '?'}, PR #${prNumber ?? 'pending'}, branch ${branchName ?? 'none'}, session ${sessionId ?? 'none'}`, { verbose: true });
239
+
237
240
  try {
238
241
  const artifacts = await writeDevelopmentLogArtifacts({
239
242
  repositoryPath,
@@ -151,6 +151,47 @@ export const codexModels = {
151
151
  'gpt-4o': 'gpt-4o',
152
152
  };
153
153
 
154
+ const CODEX_GENERATION_ALIAS_PATTERN = /^gpt-(\d+(?:\.\d+)?)-(sol|terra|luna)$/;
155
+ const OPENAI_MODEL_PREFIX_PATTERN = /^openai([/.])/;
156
+
157
+ /**
158
+ * Resolve sol/terra/luna to the newest generation that contains the complete
159
+ * alias family. A complete family prevents a partially rolled-out catalog from
160
+ * moving only some aliases to a newer generation.
161
+ */
162
+ export const getLatestCodexGenerationAliases = (models = codexModels) => {
163
+ const generations = new Map();
164
+
165
+ for (const modelId of Object.values(models)) {
166
+ const bareModelId = modelId.replace(OPENAI_MODEL_PREFIX_PATTERN, '');
167
+ const match = bareModelId.match(CODEX_GENERATION_ALIAS_PATTERN);
168
+ if (!match) continue;
169
+
170
+ const [, generation, alias] = match;
171
+ if (!generations.has(generation)) generations.set(generation, {});
172
+ generations.get(generation)[alias] = bareModelId;
173
+ }
174
+
175
+ const latestCompleteGeneration = [...generations.entries()].filter(([, aliases]) => ['sol', 'terra', 'luna'].every(alias => aliases[alias])).sort(([left], [right]) => right.localeCompare(left, undefined, { numeric: true }))[0];
176
+
177
+ return latestCompleteGeneration?.[1] || {};
178
+ };
179
+
180
+ const getCodexModelVariants = () => {
181
+ const bareModels = [...new Set(Object.values(codexModels).map(modelId => modelId.replace(OPENAI_MODEL_PREFIX_PATTERN, '')))];
182
+ const aliases = getLatestCodexGenerationAliases();
183
+ const variants = { ...codexModels, ...aliases };
184
+
185
+ for (const [name, modelId] of Object.entries({ ...Object.fromEntries(bareModels.map(modelId => [modelId, modelId])), ...aliases })) {
186
+ variants[`openai/${name}`] = `openai/${modelId}`;
187
+ variants[`openai.${name}`] = `openai.${modelId}`;
188
+ }
189
+
190
+ return variants;
191
+ };
192
+
193
+ export const CODEX_MODEL_VARIANTS = getCodexModelVariants();
194
+
154
195
  // Qwen Code models
155
196
  export const qwenModels = {
156
197
  qwen: 'qwen3-coder-plus',
@@ -269,7 +310,7 @@ export const OPENCODE_MODELS = {
269
310
  };
270
311
 
271
312
  export const CODEX_MODELS = {
272
- ...codexModels,
313
+ ...CODEX_MODEL_VARIANTS,
273
314
  'gpt-5': 'gpt-5',
274
315
  'gpt-5.5': 'gpt-5.5',
275
316
  'gpt-5.5-mini': 'gpt-5.5-mini',
@@ -346,7 +387,7 @@ export const getModelMapForTool = tool => {
346
387
  case 'opencode':
347
388
  return opencodeModels;
348
389
  case 'codex':
349
- return codexModels;
390
+ return CODEX_MODEL_VARIANTS;
350
391
  case 'gemini':
351
392
  return geminiModels;
352
393
  case 'qwen':
@@ -429,7 +470,7 @@ export const mapModelForTool = (tool, model) => {
429
470
  case 'opencode':
430
471
  return opencodeModels[model] || model;
431
472
  case 'codex':
432
- return codexModels[model] || model;
473
+ return CODEX_MODEL_VARIANTS[model] || model;
433
474
  case 'gemini':
434
475
  return geminiModels[model] || model;
435
476
  case 'qwen':
@@ -456,7 +497,7 @@ export const isModelCompatibleWithTool = (tool, model) => {
456
497
  case 'opencode':
457
498
  return mappedModel.includes('/') || Object.keys(opencodeModels).includes(model);
458
499
  case 'codex':
459
- return Object.keys(codexModels).includes(model) || mappedModel.startsWith('gpt-');
500
+ return Object.hasOwn(CODEX_MODEL_VARIANTS, model);
460
501
  case 'gemini':
461
502
  return Object.keys(geminiModels).includes(model) || mappedModel.startsWith('gemini-');
462
503
  case 'qwen':
@@ -480,7 +521,7 @@ export const getValidModelsForTool = tool => {
480
521
  case 'opencode':
481
522
  return Object.keys(opencodeModels);
482
523
  case 'codex':
483
- return Object.keys(codexModels);
524
+ return Object.keys(CODEX_MODEL_VARIANTS);
484
525
  case 'gemini':
485
526
  return Object.keys(geminiModels);
486
527
  case 'qwen':
package/src/solve.mjs CHANGED
@@ -1227,6 +1227,8 @@ try {
1227
1227
 
1228
1228
  await enforceRequestedBaseBranch();
1229
1229
 
1230
+ // Issue #2048: commit+push dev log BEFORE any PR readiness signal so its CI gates readiness (was last, breaking CI post-signal; PR #2046, docs/case-studies/issue-2048). Idempotent: trailing call is a no-op. prettier-ignore
1231
+ await finalizeDevelopmentLog();
1230
1232
  // Issue #1263 / #1728: Working session summary attachment.
1231
1233
  // Routed through the shared maybeAttachWorkingSessionSummary helper so that
1232
1234
  // top-level solve, auto-restart-until-mergeable, and watch-mode iterations
@@ -1466,7 +1468,7 @@ try {
1466
1468
  // Issue #1516: Cleanup after all signals (was before verifyResults, caused premature commits)
1467
1469
  await cleanupClaudeFile(tempDir, branchName, claudeCommitHash, argv);
1468
1470
 
1469
- await finalizeDevelopmentLog(); // Issue #1596: preserve session before ending work.
1471
+ await finalizeDevelopmentLog(); // Issue #1596/#2048: idempotent no-op on the success path (already committed before readiness signal); still preserves late/error work.
1470
1472
  await endWorkSession({ isContinueMode, prNumber, argv, log, formatAligned, $, logsAttached });
1471
1473
  } catch (error) {
1472
1474
  await finalizeDevelopmentLog(); // Preserve failed/interrupted sessions too.