@bill10/agent-007 0.7.0 → 0.7.1000

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/VERSION CHANGED
@@ -1 +1 @@
1
- 0.7.0.0
1
+ 0.7.1.0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bill10/agent-007",
3
- "version": "0.7.0",
3
+ "version": "0.7.1000",
4
4
  "description": "From web terminals for your coding agents to a self-running agent company: Claude Code and Codex in parallel git worktrees, a job board they pick work from, and one agent that runs the board from a goal.",
5
5
  "license": "MIT",
6
6
  "repository": {
package/server/git.js CHANGED
@@ -342,13 +342,14 @@ export async function removeWorktree(session, { discardChanges = false } = {}) {
342
342
  const local = (await gitExec(['-C', session.worktreePath, 'rev-parse', 'HEAD'])).trim();
343
343
  const upstream = (await gitExec(['-C', session.worktreePath, 'rev-parse', '@{u}'])).trim();
344
344
  fullyPushed = !!local && local === upstream;
345
- } catch {
346
- // No upstream, or one git cannot resolve locally — typically a branch
347
- // pushed to a raw URL (`git push -u https://…`), which records the URL
348
- // as branch.<name>.remote and creates no remote-tracking ref. Ask the
349
- // remote itself; anything short of a matching SHA stays not-pushed.
350
- fullyPushed = await matchesRemote(session);
351
- }
345
+ } catch {}
346
+ // No upstream git can resolve locally (a branch pushed to a raw URL,
347
+ // `git push -u https://…`, records the URL as branch.<name>.remote and
348
+ // creates no remote-tracking ref), or one that is stale: a push from
349
+ // inside the worktree after a rebase or a force-with-lease can leave the
350
+ // shared repo's refs/remotes/origin/<branch> on an old SHA. Ask the
351
+ // remote itself; anything short of a matching SHA stays not-pushed.
352
+ if (!fullyPushed) fullyPushed = await matchesRemote(session);
352
353
  }
353
354
  if (!reason && !fullyPushed) {
354
355
  const baseBranch = await resolveBaseBranch(session.repoPath);
package/server/jobs.js CHANGED
@@ -1086,6 +1086,20 @@ async function releaseOrphanedWorktree({ branchName, repoPath, worktreePath }, b
1086
1086
  return true;
1087
1087
  }
1088
1088
 
1089
+ // An "unpushed" orphan left by an older build (or a stale remote-tracking ref)
1090
+ // may be fully on the remote by now. Re-check each one at startup through the
1091
+ // same release path, so removeWorktree's rules decide: dirty stays, and only
1092
+ // an exact SHA match on the remote counts as pushed. A card still in progress
1093
+ // or in Review may want its agent re-adopted, so its orphan is left alone.
1094
+ export async function releasePushedOrphans(broadcast) {
1095
+ let released = 0;
1096
+ for (const entry of [...orphans.values()]) {
1097
+ if (entry.reason !== 'unpushed' || findJobForBranch(entry)) continue;
1098
+ if (await releaseOrphanedWorktree(entry, broadcast)) released++;
1099
+ }
1100
+ return released;
1101
+ }
1102
+
1089
1103
  export function updateSettings(fields, broadcast) {
1090
1104
  const settings = boardSettings();
1091
1105
  if (typeof fields.running === 'boolean') settings.running = fields.running;
package/server.js CHANGED
@@ -29,7 +29,7 @@ import { addRepo, createWorktree, removeWorktree, pruneWorktrees, scanForOrphane
29
29
  import { createSessionFromConfig } from './server/pty.js';
30
30
  import { setupWebSocket, broadcast, sessionPayload, broadcastOrphansList, verifyClient } from './server/ws.js';
31
31
  import { setupRoutes } from './server/http.js';
32
- import { startDispatcher, stopDispatcher, boardSettings } from './server/jobs.js';
32
+ import { startDispatcher, stopDispatcher, boardSettings, releasePushedOrphans } from './server/jobs.js';
33
33
  import { orphans, config } from './server/state.js';
34
34
  import { sweepMcpConfigs } from './server/agent-mcp.js';
35
35
  import { withDefaultPermission, envPermissionMode, PERMISSION_MODES, ENV_PERMISSION_MODE, sessionAgentFromCommand } from './lib/jobs.js';
@@ -238,6 +238,9 @@ async function startup() {
238
238
  mkdirSync(WORKTREE_DIR, { recursive: true });
239
239
  await pruneWorktrees();
240
240
  await scanForOrphanedWorktrees(broadcast);
241
+ // Not awaited: each check can ask the remote, and boot must not wait on the network.
242
+ releasePushedOrphans(broadcast).then(n => { if (n) console.log(` Released ${n} orphaned worktree(s) now on the remote`); })
243
+ .catch(err => console.error('Orphan re-check failed:', err.message));
241
244
  // The loop always runs; each tick is a no-op while settings.running is false.
242
245
  // Keeping one timer alive (instead of creating/destroying it on toggle) means
243
246
  // the Start button only has to flip a boolean, and a config restored with