oh-pi 0.1.34 → 0.1.35

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oh-pi",
3
- "version": "0.1.34",
3
+ "version": "0.1.35",
4
4
  "description": "One-click setup for pi-coding-agent. Like oh-my-zsh for pi.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -323,7 +323,7 @@ export async function runColony(opts: QueenOptions): Promise<ColonyState> {
323
323
  };
324
324
 
325
325
  try {
326
- // ═══ Phase 1: 侦察(最多重试2次) ═══
326
+ // ═══ Phase 1: 侦察(接力机制) ═══
327
327
  let scoutAttempt = 0;
328
328
  const MAX_SCOUT_RETRIES = 2;
329
329
  let workerTasks: Task[] = [];
@@ -331,7 +331,7 @@ export async function runColony(opts: QueenOptions): Promise<ColonyState> {
331
331
  while (scoutAttempt <= MAX_SCOUT_RETRIES) {
332
332
  callbacks.onPhase("scouting", scoutAttempt === 0
333
333
  ? "Dispatching scout ants to explore codebase..."
334
- : `Scout retry ${scoutAttempt}/${MAX_SCOUT_RETRIES}...`);
334
+ : `Scout relay ${scoutAttempt}/${MAX_SCOUT_RETRIES} (building on previous discoveries)...`);
335
335
 
336
336
  await runAntWave({ ...waveBase, caste: "scout" });
337
337
 
@@ -340,10 +340,33 @@ export async function runColony(opts: QueenOptions): Promise<ColonyState> {
340
340
 
341
341
  scoutAttempt++;
342
342
  if (scoutAttempt <= MAX_SCOUT_RETRIES) {
343
- // 重置失败的 scout 任务为 pending 以便重试
344
- for (const t of nest.getAllTasks().filter(t => t.caste === "scout" && (t.status === "done" || t.status === "failed"))) {
345
- nest.updateTaskStatus(t.id, "pending");
346
- }
343
+ // 接力:检查是否有信息素(前一只 scout 的部分发现)
344
+ const pheromones = nest.getAllPheromones();
345
+ const hasDiscoveries = pheromones.some(p => p.type === "discovery");
346
+
347
+ // 创建接力 scout 任务(而非重置旧任务)
348
+ const relayDescription = hasDiscoveries
349
+ ? `Continue exploring the codebase. Previous scouts made partial discoveries (see pheromone trail). Focus on areas NOT yet explored and generate worker tasks.\n\nOriginal goal:\n${opts.goal}`
350
+ : `Explore the codebase and identify all files, modules, and dependencies relevant to this goal:\n\n${opts.goal}\n\nBe thorough. The colony depends on your intelligence.`;
351
+
352
+ const relayTask: Task = {
353
+ id: makeTaskId(),
354
+ parentId: null,
355
+ title: hasDiscoveries ? "Scout relay: continue exploration" : "Scout: explore codebase for goal",
356
+ description: relayDescription,
357
+ caste: "scout",
358
+ status: "pending",
359
+ priority: 1,
360
+ files: [],
361
+ claimedBy: null,
362
+ result: null,
363
+ error: null,
364
+ spawnedTasks: [],
365
+ createdAt: Date.now(),
366
+ startedAt: null,
367
+ finishedAt: null,
368
+ };
369
+ nest.writeTask(relayTask);
347
370
  }
348
371
  }
349
372
 
@@ -50,6 +50,7 @@ const CASTE_PROMPTS: Record<AntCaste, string> = {
50
50
  Behavior:
51
51
  - Quickly scan the codebase to understand structure and locate relevant code
52
52
  - Identify files, functions, dependencies related to the goal
53
+ - IMPORTANT: After EACH tool call, summarize what you found so far. Do NOT wait until the end.
53
54
  - Report findings as structured intelligence for Worker Ants
54
55
 
55
56
  Output format (MUST follow exactly):
@@ -261,6 +262,17 @@ export async function spawnAnt(
261
262
  const event = JSON.parse(line);
262
263
  if (event.type === "turn_end") {
263
264
  turnCount++;
265
+ // 实时提取信息素:从当前所有 assistant 消息中提取发现
266
+ if (antConfig.caste === "scout") {
267
+ const currentOutput = getFinalOutput(messages);
268
+ if (currentOutput) {
269
+ const livePheromones = extractPheromones(antId, antConfig.caste, task.id, currentOutput, task.files);
270
+ for (const p of livePheromones) {
271
+ p.id = makePheromoneId(); // 确保唯一 ID
272
+ nest.dropPheromone(p);
273
+ }
274
+ }
275
+ }
264
276
  if (antConfig.maxTurns && turnCount === antConfig.maxTurns) {
265
277
  stderr += `[ant-colony] Warning: ant reached maxTurns (${antConfig.maxTurns}), 1 grace turn remaining\n`;
266
278
  } else if (antConfig.maxTurns && turnCount > antConfig.maxTurns) {
@@ -328,13 +340,13 @@ export async function spawnAnt(
328
340
  return { ant, output, messages, newTasks: [], pheromones: [], rateLimited: true };
329
341
  }
330
342
 
331
- nest.updateTaskStatus(task.id, success ? "done" : "failed", output, success ? undefined : stderr || output);
332
-
333
- // 解析子任务和信息素
343
+ // 无论成功或失败,都尝试解析子任务和信息素(支持部分产出)
334
344
  const newTasks = parseSubTasks(output);
335
345
  const pheromones = extractPheromones(antId, antConfig.caste, task.id, output, task.files);
336
346
  for (const p of pheromones) nest.dropPheromone(p);
337
347
 
348
+ nest.updateTaskStatus(task.id, success ? "done" : "failed", output, success ? undefined : stderr || output);
349
+
338
350
  return { ant, output, messages, newTasks, pheromones, rateLimited: false };
339
351
  } finally {
340
352
  try { fs.unlinkSync(tmpFile); } catch { /* ignore */ }