@on-par/factory-cli 0.9.28-next.9 → 0.9.29-next.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.
Files changed (140) hide show
  1. package/dist/cli/ci-pending-draft-sweep.d.ts +45 -0
  2. package/dist/cli/ci-pending-draft-sweep.d.ts.map +1 -0
  3. package/dist/cli/ci-pending-draft-sweep.js +176 -0
  4. package/dist/cli/ci-pending-draft-sweep.js.map +1 -0
  5. package/dist/cli/config-override-option.d.ts +11 -0
  6. package/dist/cli/config-override-option.d.ts.map +1 -0
  7. package/dist/cli/config-override-option.js +37 -0
  8. package/dist/cli/config-override-option.js.map +1 -0
  9. package/dist/cli/doctor-config-sources.d.ts +23 -0
  10. package/dist/cli/doctor-config-sources.d.ts.map +1 -0
  11. package/dist/cli/doctor-config-sources.js +44 -0
  12. package/dist/cli/doctor-config-sources.js.map +1 -0
  13. package/dist/cli/doctor-verify.d.ts +5 -0
  14. package/dist/cli/doctor-verify.d.ts.map +1 -1
  15. package/dist/cli/doctor-verify.js +21 -4
  16. package/dist/cli/doctor-verify.js.map +1 -1
  17. package/dist/cli/doctor.d.ts.map +1 -1
  18. package/dist/cli/doctor.js +8 -3
  19. package/dist/cli/doctor.js.map +1 -1
  20. package/dist/cli/help-groups.d.ts.map +1 -1
  21. package/dist/cli/help-groups.js +1 -0
  22. package/dist/cli/help-groups.js.map +1 -1
  23. package/dist/cli/index.d.ts +49 -45
  24. package/dist/cli/index.d.ts.map +1 -1
  25. package/dist/cli/index.js +73 -16
  26. package/dist/cli/index.js.map +1 -1
  27. package/dist/cli/land-find-pr.d.ts +5 -0
  28. package/dist/cli/land-find-pr.d.ts.map +1 -0
  29. package/dist/cli/land-find-pr.js +27 -0
  30. package/dist/cli/land-find-pr.js.map +1 -0
  31. package/dist/cli/land-merge.d.ts.map +1 -1
  32. package/dist/cli/land-merge.js +5 -0
  33. package/dist/cli/land-merge.js.map +1 -1
  34. package/dist/cli/land-pr.d.ts +5 -1
  35. package/dist/cli/land-pr.d.ts.map +1 -1
  36. package/dist/cli/land-pr.js +5 -1
  37. package/dist/cli/land-pr.js.map +1 -1
  38. package/dist/cli/land.d.ts +11 -3
  39. package/dist/cli/land.d.ts.map +1 -1
  40. package/dist/cli/land.js +27 -34
  41. package/dist/cli/land.js.map +1 -1
  42. package/dist/cli/program-observe.js +1 -1
  43. package/dist/cli/program-observe.js.map +1 -1
  44. package/dist/cli/program-run-work.d.ts.map +1 -1
  45. package/dist/cli/program-run-work.js +14 -0
  46. package/dist/cli/program-run-work.js.map +1 -1
  47. package/dist/cli/program.d.ts.map +1 -1
  48. package/dist/cli/program.js +11 -1
  49. package/dist/cli/program.js.map +1 -1
  50. package/dist/cli/queue-backend-select.d.ts +15 -0
  51. package/dist/cli/queue-backend-select.d.ts.map +1 -0
  52. package/dist/cli/queue-backend-select.js +30 -0
  53. package/dist/cli/queue-backend-select.js.map +1 -0
  54. package/dist/cli/queue-preflight-prerequisite-stack.d.ts +11 -0
  55. package/dist/cli/queue-preflight-prerequisite-stack.d.ts.map +1 -0
  56. package/dist/cli/queue-preflight-prerequisite-stack.js +75 -0
  57. package/dist/cli/queue-preflight-prerequisite-stack.js.map +1 -0
  58. package/dist/cli/queue-preflight.d.ts +4 -0
  59. package/dist/cli/queue-preflight.d.ts.map +1 -1
  60. package/dist/cli/queue-preflight.js +16 -64
  61. package/dist/cli/queue-preflight.js.map +1 -1
  62. package/dist/cli/queue-prerequisite-state.d.ts +8 -0
  63. package/dist/cli/queue-prerequisite-state.d.ts.map +1 -0
  64. package/dist/cli/queue-prerequisite-state.js +66 -0
  65. package/dist/cli/queue-prerequisite-state.js.map +1 -0
  66. package/dist/cli/queue-startup.d.ts +42 -0
  67. package/dist/cli/queue-startup.d.ts.map +1 -1
  68. package/dist/cli/queue-startup.js +2 -0
  69. package/dist/cli/queue-startup.js.map +1 -1
  70. package/dist/cli/respond-command.d.ts +42 -0
  71. package/dist/cli/respond-command.d.ts.map +1 -0
  72. package/dist/cli/respond-command.js +76 -0
  73. package/dist/cli/respond-command.js.map +1 -0
  74. package/dist/cli/run-branch.d.ts.map +1 -1
  75. package/dist/cli/run-branch.js +2 -2
  76. package/dist/cli/run-branch.js.map +1 -1
  77. package/dist/cli/run-brief.d.ts +10 -0
  78. package/dist/cli/run-brief.d.ts.map +1 -1
  79. package/dist/cli/run-brief.js +41 -5
  80. package/dist/cli/run-brief.js.map +1 -1
  81. package/dist/cli/run-issue-merge.d.ts +54 -0
  82. package/dist/cli/run-issue-merge.d.ts.map +1 -0
  83. package/dist/cli/run-issue-merge.js +155 -0
  84. package/dist/cli/run-issue-merge.js.map +1 -0
  85. package/dist/cli/run-lane-deps.d.ts +6 -1
  86. package/dist/cli/run-lane-deps.d.ts.map +1 -1
  87. package/dist/cli/run-lane-discovery.d.ts +35 -0
  88. package/dist/cli/run-lane-discovery.d.ts.map +1 -0
  89. package/dist/cli/run-lane-discovery.js +93 -0
  90. package/dist/cli/run-lane-discovery.js.map +1 -0
  91. package/dist/cli/run-lane-restack.d.ts +6 -1
  92. package/dist/cli/run-lane-restack.d.ts.map +1 -1
  93. package/dist/cli/run-lane-restack.js +16 -0
  94. package/dist/cli/run-lane-restack.js.map +1 -1
  95. package/dist/cli/run-lane.d.ts.map +1 -1
  96. package/dist/cli/run-lane.js +40 -4
  97. package/dist/cli/run-lane.js.map +1 -1
  98. package/dist/cli/run-queue.d.ts +19 -0
  99. package/dist/cli/run-queue.d.ts.map +1 -0
  100. package/dist/cli/run-queue.js +66 -0
  101. package/dist/cli/run-queue.js.map +1 -0
  102. package/dist/cli/run-rework-poll.d.ts +15 -0
  103. package/dist/cli/run-rework-poll.d.ts.map +1 -0
  104. package/dist/cli/run-rework-poll.js +79 -0
  105. package/dist/cli/run-rework-poll.js.map +1 -0
  106. package/dist/cli/run.d.ts +3 -0
  107. package/dist/cli/run.d.ts.map +1 -1
  108. package/dist/cli/run.js +58 -102
  109. package/dist/cli/run.js.map +1 -1
  110. package/dist/cli/ship-options.d.ts +25 -1
  111. package/dist/cli/ship-options.d.ts.map +1 -1
  112. package/dist/cli/ship-options.js +39 -0
  113. package/dist/cli/ship-options.js.map +1 -1
  114. package/dist/cli/ship-pr-state.d.ts +58 -0
  115. package/dist/cli/ship-pr-state.d.ts.map +1 -0
  116. package/dist/cli/ship-pr-state.js +172 -0
  117. package/dist/cli/ship-pr-state.js.map +1 -0
  118. package/dist/cli/ship-review-rework.d.ts +6 -0
  119. package/dist/cli/ship-review-rework.d.ts.map +1 -1
  120. package/dist/cli/ship-review-rework.js +11 -2
  121. package/dist/cli/ship-review-rework.js.map +1 -1
  122. package/dist/cli/ship-steps.d.ts +5 -2
  123. package/dist/cli/ship-steps.d.ts.map +1 -1
  124. package/dist/cli/ship-steps.js +15 -2
  125. package/dist/cli/ship-steps.js.map +1 -1
  126. package/dist/cli/ship.d.ts +3 -0
  127. package/dist/cli/ship.d.ts.map +1 -1
  128. package/dist/cli/ship.js +26 -20
  129. package/dist/cli/ship.js.map +1 -1
  130. package/dist/cli/shutdown.d.ts +26 -0
  131. package/dist/cli/shutdown.d.ts.map +1 -0
  132. package/dist/cli/shutdown.js +82 -0
  133. package/dist/cli/shutdown.js.map +1 -0
  134. package/dist/cli/status.d.ts.map +1 -1
  135. package/dist/cli/status.js +57 -27
  136. package/dist/cli/status.js.map +1 -1
  137. package/dist/cli/supervise.d.ts.map +1 -1
  138. package/dist/cli/supervise.js +11 -6
  139. package/dist/cli/supervise.js.map +1 -1
  140. package/package.json +4 -4
package/dist/cli/index.js CHANGED
@@ -11,13 +11,15 @@ import { INVALID_BRANCH_PREFIX_MESSAGE, resolveBranchPrefixOption } from './bran
11
11
  import { startupSweeps, warnQueueDiagnostics } from './queue-startup.js';
12
12
  import { proposeTriageQueue } from './triage-open-prs.js';
13
13
  import { makeQueuePreflightOps, preflightQueuedIssue, } from './queue-preflight.js';
14
- import { acquirePortLease, aggregateCosts, appendKpiHistoryLine, applyRepoConfig, buildPhase, checkPhase, clearProxyState, computeHealthKpis, ConstitutionLoader, createDefaultWorkSourceRegistry, createLogger, createLaneProxy, defaultFindPortListeners, describeEffectiveConfig, detectPostMergeDefects, diagnoseModels, probeDeclaredHarnesses, estimateTrailingSpend, fetchDefectSources, fetchSubscriptionUsage, formatUsageReport, getConstitutionsDir, getFactoryPaths, GITHUB_ISSUE_SOURCE, hasUnresolvedPark, InvalidWorkRequestInputError, isCommandAvailable, isProxyRunning, kpiBranchPrefixes, kpisToHistoryRecord, laneBaseUrl, laneEnv, laneHostLabel, loadFactoryConfigForRepo, loadModelsConfig, loadRepoConfig, loadRoutesConfig, joinClassifierOutcomes, mergeClassifierOutcomes, parseClassifierOutcomes, summarizeClassifierOutcomes, formatClassifierReport, mergedPrRefs, ModelRegistry, ModelRouter, parkReasonFor, parseKpiHistory, parseQueue, planPhase, readEvents, readPortLeases, readQueue, readUsage, reapOrphanProcesses, reconstructKpiEvents, recordLeasePgid, releasePortLease, renderKpiReport, renderKpiTrend, resolveDefectWindowDays, parseSizeGateMode, parseMaxSlices, SIZE_GATE_MODES, resolveEffectiveModelPins, resolveEnvironmentProxy, resolveMergePolicy, resolveSkipCI, resolveTimeouts, resolveUsageCap, resolveWatchdogPolicy, runAutoIngest, shipPhase, formatCostTotal, validateQueue, watchUsage, writeLocalRunReport, issueNumberOf, workKeyFromIssue, writeProxyState, } from '@on-par/factory-core';
15
- import { acquirePidFile, createCheckResumeStore, DEFAULT_GARDEN_MAX_CLUSTERS, DEFAULT_GARDEN_SINCE, capGardenClusters, clusterGarden, dedupGardenClusters, filterGardenOnlyNew, filterGardenWindow, markGardenTrackingUnknown, parseGardenDuration, readHarvestEvents, renderGardenJson, renderGardenReport, laneWorktreePath, migrateRepoConfigToYaml, readRepoConfigFile, rewriteRepoConfigFile, REPO_CONFIG_YAML_HEADER, claudeConfigDirOverride, claudeKeychainService, cleanupWorktree, createDaemonLogSink, factoryBranchIssue, factoryBranchPrefixes, createFactorydServer, createRunRuntime, createShipExecutor, createGithubQueue, createLocalSmallDryRun, createOctokitFilingClient, createOctokitGreenPrClient, createOctokitQueueClient, daemonRuntimePaths, defaultRegistryPath, ensureDir, fetchHumanEventSourcesCached, FACTORY_RUNTIME_CONFIG_KEYS, findUnmergedGreenPrs, listStatelessLaneIssues, formatGcReport, gitFetch, listMicroVms, listOrphanContainers, logCost, logEvent, planQueueMigration, pollBlockedParks, readCosts, readGithubQueueSnapshot, reapCleanShipWorktree, reapLaneWorktree, reapOrphanContainers, reapOrphanMicroVm, releaseRuntimeFiles, releaseStaleClaims, resolveBranchPrefix, resolveEffectiveConfig, resolveExperimental, resolveLocalOnly, describeDraftPrPolicy, resolveDraftPrPolicy, resolvePrClassifierPolicy, resolveReviewFloorRules, runOvernightQueue, parseRemoteSlug, setupWorktree, shellEscape, listBuiltInCheckers, sweepWorktrees, watchChecks, withFileLock, withGitLock, writePortFile, buildTriagePrompt, parseTriageCandidates, laneSlug, formatStopMarker, readStopMarker, detectClaudePlan, findSlicePlanComment, listBlockedBy, aliasDeprecatedSizeGateMode, checkResumeBaseDrift, formatBaseMovedRefusal, } from '@on-par/factory-core/internal';
14
+ import { acquirePortLease, aggregateCosts, appendKpiHistoryLine, applyRepoConfig, buildPhase, checkPhase, clearProxyState, computeHealthKpis, ConstitutionLoader, createDefaultWorkSourceRegistry, createLogger, createLaneProxy, defaultFindPortListeners, describeEffectiveConfig, detectPostMergeDefects, diagnoseModels, probeDeclaredHarnesses, estimateTrailingSpend, fetchDefectSources, fetchSubscriptionUsage, formatUsageReport, getConstitutionsDir, getFactoryPaths, GITHUB_ISSUE_SOURCE, hasUnresolvedPark, InvalidWorkRequestInputError, isCommandAvailable, isProxyRunning, kpiBranchPrefixes, kpisToHistoryRecord, laneBaseUrl, laneEnv, laneHostLabel, loadFactoryConfigForRepo, loadModelsConfig, loadRepoConfig, loadRoutesConfig, joinClassifierOutcomes, mergeClassifierOutcomes, parseClassifierOutcomes, summarizeClassifierOutcomes, formatClassifierReport, mergedPrRefs, ModelRegistry, ModelRouter, parkReasonFor, parseKpiHistory, parseQueue, planPhase, readEvents, readPortLeases, readQueue, readUsage, reapOrphanProcesses, reconstructKpiEvents, recordLeasePgid, releasePortLease, renderKpiReport, renderKpiTrend, resolveDefectWindowDays, parseSizeGateMode, parseMaxSlices, SIZE_GATE_MODES, resolveEffectiveModelPins, resolveEnvironmentProxy, resolveMergePolicy, resolveSkipCI, resolveTimeouts, resolveUsageCap, resolveWatchdogPolicy, runAutoIngest, shipPhase, formatCostTotal, validateQueue, watchUsage, writeLocalRunReport, isNumericWorkKey, issueNumberOf, workKeyFromIssue, writeProxyState, } from '@on-par/factory-core';
15
+ import { acquirePidFile, createCheckResumeStore, DEFAULT_GARDEN_MAX_CLUSTERS, DEFAULT_GARDEN_SINCE, capGardenClusters, clusterGarden, dedupGardenClusters, filterGardenOnlyNew, filterGardenWindow, markGardenTrackingUnknown, parseGardenDuration, readHarvestEvents, renderGardenJson, renderGardenReport, laneWorktreePath, migrateRepoConfigToYaml, readRepoConfigFile, rewriteRepoConfigFile, REPO_CONFIG_YAML_HEADER, claudeConfigDirOverride, claudeKeychainService, cleanupWorktree, createDaemonLogSink, factoryBranchIssue, factoryBranchPrefixes, createFactorydServer, createRunRuntime, createShipExecutor, createGithubQueue, createLocalSmallDryRun, createOctokitFilingClient, createOctokitGreenPrClient, createOctokitQueueClient, daemonRuntimePaths, defaultRegistryPath, ensureDir, fetchHumanEventSourcesCached, FACTORY_RUNTIME_CONFIG_KEYS, findUnmergedGreenPrs, listStatelessLaneIssues, formatGcReport, gitFetch, listMicroVms, listOrphanContainers, logCost, logEvent, planQueueMigration, pollBlockedParks, readCosts, readGithubQueueSnapshot, reapCleanShipWorktree, reapLaneWorktree, reapOrphanContainers, reapOrphanMicroVm, releaseRuntimeFiles, releaseStaleClaims, resolveBranchPrefix, resolveEffectiveConfig, resolveExperimental, resolveLocalOnly, describeDraftPrPolicy, resolveDraftPrPolicy, resolvePrClassifierPolicy, resolveReviewFloorRules, runOvernightQueue, parseRemoteSlug, setupWorktree, checkInPlaceCheckout, setupInPlaceCheckout, shellEscape, listBuiltInCheckers, sweepWorktrees, watchChecks, withFileLock, withGitLock, writePortFile, buildTriagePrompt, parseTriageCandidates, laneSlug, formatStopMarker, readStopMarker, detectClaudePlan, findSlicePlanComment, listBlockedBy, aliasDeprecatedSizeGateMode, checkResumeBaseDrift, formatBaseMovedRefusal, } from '@on-par/factory-core/internal';
16
16
  import { CliExitError } from './errors.js';
17
- import { baseBranchConflict, baseBranchOrExit } from './ship-options.js';
17
+ import { baseBranchConflict, baseBranchOrExit, inPlaceConflict, resolveWorkspaceMode } from './ship-options.js';
18
18
  import { runIssueStack } from './stack-run.js';
19
19
  import { withRepoRunLock } from './repo-run-lock.js';
20
20
  export { CliExitError, withRepoRunLock };
21
+ import { resolveAwaitingCiCapMs } from '@on-par/factory-core/internal';
22
+ import { driveToMerge, exitForMerge, shouldDriveAfterShipFailure, validateMergeFlags } from './run-issue-merge.js';
21
23
  import { formatSteerabilityReport } from '@on-par/factory-core/internal';
22
24
  import { buildTierEvidence, formatTierEvidence, resolveTrustTier } from '@on-par/factory-core/internal';
23
25
  import { runTui } from '@on-par/factory-tui';
@@ -72,6 +74,8 @@ import { readRunFlagOverrides, recordDraftPrFlag } from './run-flags.js';
72
74
  import { runStalenessGuard } from './staleness.js';
73
75
  import { cmdBaselineClear } from './baseline.js';
74
76
  import { cmdBreakerReset } from './breaker.js';
77
+ import { cmdRespond } from './respond-command.js';
78
+ import { withShutdown } from './shutdown.js';
75
79
  import { runWorktreeKeep, runWorktreeRelease } from './worktree-keep.js';
76
80
  import { gcWorktreeSandbox, reapParkedLane, reapPrlessShip } from './worktree-reap.js';
77
81
  const DEFAULT_CONFIG_LOADERS = {
@@ -104,7 +108,14 @@ function resolveConfigLoaders(overrides, base = configLoaders) {
104
108
  resolveEffectiveModelPins: overrides.resolveEffectiveModelPins ?? base.resolveEffectiveModelPins,
105
109
  };
106
110
  }
107
- const DEFAULT_GIT_OPS = { setupWorktree, cleanupWorktree, gitFetch, checkResumeBaseDrift };
111
+ const DEFAULT_GIT_OPS = {
112
+ setupWorktree,
113
+ cleanupWorktree,
114
+ gitFetch,
115
+ checkResumeBaseDrift,
116
+ checkInPlaceCheckout,
117
+ setupInPlaceCheckout,
118
+ };
108
119
  /** Git worktree/fetch ops for the current main() or cmdLand invocation; DEFAULT_GIT_OPS outside them. */
109
120
  let gitOps = DEFAULT_GIT_OPS;
110
121
  /** Per-field `??` so an explicit `undefined` override falls back instead of replacing the default. */
@@ -114,6 +125,8 @@ function resolveGitOps(overrides, base = gitOps) {
114
125
  cleanupWorktree: overrides.cleanupWorktree ?? base.cleanupWorktree,
115
126
  gitFetch: overrides.gitFetch ?? base.gitFetch,
116
127
  checkResumeBaseDrift: overrides.checkResumeBaseDrift ?? base.checkResumeBaseDrift,
128
+ checkInPlaceCheckout: overrides.checkInPlaceCheckout ?? base.checkInPlaceCheckout,
129
+ setupInPlaceCheckout: overrides.setupInPlaceCheckout ?? base.setupInPlaceCheckout,
117
130
  };
118
131
  }
119
132
  const DEFAULT_INTERNAL_OPS = {
@@ -222,7 +235,7 @@ function resolvePhaseOps(overrides, base = phaseOps) {
222
235
  export const PREREQUISITES_TEXT = `First step: run \`factory doctor\` to check your setup and see what to fix.
223
236
 
224
237
  Prerequisites:
225
- - Claude Code CLI installed and authenticated (Claude subscription): https://claude.com/claude-code
238
+ - A supported coding agent CLI installed and authenticated: Claude Code, Codex, OpenCode or Pi (\`factory doctor\` shows which are ready)
226
239
  - GitHub CLI authenticated: gh auth login
227
240
  - GITHUB_TOKEN or GH_TOKEN set (falls back to \`gh auth token\`)
228
241
  Run inside a git repository with a GitHub remote.
@@ -1527,7 +1540,7 @@ export function resolveEnvironmentAcquirer(opts) {
1527
1540
  };
1528
1541
  };
1529
1542
  }
1530
- const { sweepStaleLaneClaims, sweepOrphanDrafts, reapExpiredClaims } = startupSweeps(() => hasGitHubToken() ? getOctokit() : undefined);
1543
+ const { sweepStaleLaneClaims, sweepOrphanDrafts, sweepCiPendingDrafts, reapExpiredClaims } = startupSweeps(() => hasGitHubToken() ? getOctokit() : undefined);
1531
1544
  /** The autoGcOnRun-gated worktree sweep every pipeline entry point runs before shipping
1532
1545
  * (`factory run`, and since #1756 the one-shot `factory ship` / `factory run-issue`). Never
1533
1546
  * throws — a GC failure is a warn, never a reason to abort the command. */
@@ -1643,7 +1656,8 @@ async function cmdRunIssue(issueNum, opts) {
1643
1656
  if (!existsSync(paths.root)) {
1644
1657
  throw new CliExitError(`factory: ${notInitializedMessage()}`, 2);
1645
1658
  }
1646
- const { runChildren: _removed, sizeGate: rawSizeGate, maxSlices: rawMaxSlices, stack, ...shipOpts } = opts;
1659
+ const { runChildren: _removed, sizeGate: rawSizeGate, maxSlices: rawMaxSlices, stack, merge, mergeTimeout, admin, inPlace: _inPlaceFlag, ...shipOpts } = opts;
1660
+ const mergeTimeoutMs = validateMergeFlags({ merge, mergeTimeout, admin, pr: opts.pr, stack: stack || rawSizeGate === 'stack' }, 'issue');
1647
1661
  const branchPrefix = branchPrefixOrExit(opts.branchPrefix, paths.config);
1648
1662
  const parsedSizeGate = sizeGateOrExit(rawSizeGate);
1649
1663
  if (stack && parsedSizeGate !== undefined && parsedSizeGate !== 'stack') {
@@ -1662,8 +1676,20 @@ async function cmdRunIssue(issueNum, opts) {
1662
1676
  if (opts.pr === false && sizeGate !== undefined && sizeGate !== 'off') {
1663
1677
  throw new CliExitError('factory: --no-pr runs with the size gate off — drop --size-gate or drop --no-pr', 2);
1664
1678
  }
1679
+ const inPlace = resolveWorkspaceMode(opts.inPlace, process.env) === 'in-place';
1680
+ if (inPlace) {
1681
+ const inPlaceMsg = inPlaceConflict({ baseBranch, sizeGate });
1682
+ if (inPlaceMsg)
1683
+ throw new CliExitError(inPlaceMsg, 2);
1684
+ }
1665
1685
  await withRepoRunLock(paths, 'factory run-issue', async () => {
1666
1686
  recordDraftPrFlag(paths.runFlags, opts.draftPr);
1687
+ if (inPlace) {
1688
+ // Refuse before the issue lookup and PLAN, under the run lock (#3904).
1689
+ const problem = await gitOps.checkInPlaceCheckout(repoRoot);
1690
+ if (problem)
1691
+ throw new CliExitError(`factory: ${problem.message}`, 2);
1692
+ }
1667
1693
  const ghRepo = await getGitHubRepo();
1668
1694
  // Pre-flight: resolve the issue through the canonical work-request seam
1669
1695
  // BEFORE any worktree or PR exists — a bad issue exits here.
@@ -1682,7 +1708,9 @@ async function cmdRunIssue(issueNum, opts) {
1682
1708
  throw new CliExitError(`factory: could not resolve issue #${issueNum} in ${ghRepo} (${errorDetail(err)}) — no worktree or PR was created`, 2);
1683
1709
  }
1684
1710
  console.log(styleText('cyan', `one-shot: resolved ${work.id} — running the pipeline (queue untouched)`));
1685
- await runAutoWorktreeGc(repoRoot, paths, ghRepo, issueNum);
1711
+ // A one-job in-place container has no other lanes to collect.
1712
+ if (!inPlace)
1713
+ await runAutoWorktreeGc(repoRoot, paths, ghRepo, issueNum);
1686
1714
  const priorEvents = readEvents(paths.events, { includeSegments: true });
1687
1715
  if (hasUnresolvedPark(priorEvents, String(issueNum))) {
1688
1716
  logEvent(paths.events, 'human-restarted', issueNum, 'manual retry of a previously parked/failed run', {
@@ -1718,7 +1746,29 @@ async function cmdRunIssue(issueNum, opts) {
1718
1746
  });
1719
1747
  return;
1720
1748
  }
1721
- await shipIssue(issueNum, { ...shipOpts, branchPrefix, sizeGate, explicitStack, maxSlices }, { repoRoot, ghRepo, workRequest: work });
1749
+ let outcome;
1750
+ const drive = async () => exitForMerge(await driveToMerge({
1751
+ issue: issueNum,
1752
+ outcome,
1753
+ repoRoot,
1754
+ ghRepo,
1755
+ paths,
1756
+ timeoutMs: mergeTimeoutMs ?? resolveAwaitingCiCapMs(configLoaders.loadFactoryConfigForRepo(paths.config)),
1757
+ ...(admin ? { admin } : {}),
1758
+ }), `issue #${issueNum}`);
1759
+ try {
1760
+ await shipIssue(issueNum, { ...shipOpts, branchPrefix, sizeGate, explicitStack, maxSlices, inPlace }, { repoRoot, ghRepo, workRequest: work, onOutcome: (o) => (outcome = o) });
1761
+ }
1762
+ catch (err) {
1763
+ if (merge &&
1764
+ shouldDriveAfterShipFailure(outcome) &&
1765
+ !(err instanceof CliExitError) &&
1766
+ !(err instanceof IssueSkippedError))
1767
+ await drive();
1768
+ throw err;
1769
+ }
1770
+ if (merge)
1771
+ await drive();
1722
1772
  }
1723
1773
  catch (err) {
1724
1774
  if (err instanceof CliExitError)
@@ -2527,10 +2577,15 @@ export function createIngestHook(repoRoot, paths, ingestCfg, deps = {}) {
2527
2577
  };
2528
2578
  }
2529
2579
  /** The lane loop is numeric and GitHub-only in v1 (ADR-0168 §1); this is its single meeting point with the WorkKey seam. */
2530
- export function laneQueueDeps(queue, lane) {
2580
+ export function laneQueueDeps(queue, lane, onUnshippable) {
2531
2581
  return {
2532
2582
  claimNext: async () => {
2533
2583
  const claim = await queue.claimNext(lane);
2584
+ if (claim !== null && !isNumericWorkKey(claim.key)) {
2585
+ await queue.release(claim.key, 'queued');
2586
+ onUnshippable?.(claim.key);
2587
+ return null;
2588
+ }
2534
2589
  return claim === null ? null : { issue: issueNumberOf(claim.key), decision: claim.decision };
2535
2590
  },
2536
2591
  releaseIssue: (issue, outcome) => queue.release(workKeyFromIssue(issue), outcome),
@@ -2566,7 +2621,7 @@ export async function planRunLanes(input) {
2566
2621
  const backend = input.queue();
2567
2622
  const lanes = await backend.lanes();
2568
2623
  return {
2569
- lanes: lanes.map((lane) => ({ lane, issues: [], deps: laneQueueDeps(backend, lane) })),
2624
+ lanes: lanes.map((lane) => ({ lane, issues: [], deps: laneQueueDeps(backend, lane, input.onUnshippable) })),
2570
2625
  diagnostics: [],
2571
2626
  };
2572
2627
  }
@@ -2997,6 +3052,7 @@ function runRun(opts = {}) {
2997
3052
  runAutoWorktreeGc,
2998
3053
  sweepStaleLaneClaims,
2999
3054
  sweepOrphanDrafts,
3055
+ sweepCiPendingDrafts,
3000
3056
  reapExpiredClaims,
3001
3057
  planRunLanes,
3002
3058
  preflightQueuedIssue,
@@ -3065,14 +3121,14 @@ export const PROGRAM_HANDLERS = {
3065
3121
  cmdQueueClear,
3066
3122
  cmdCheck,
3067
3123
  cmdDraft,
3068
- cmdShip,
3069
- cmdRunIssue,
3070
- cmdRunBrief,
3124
+ cmdShip: withShutdown(cmdShip),
3125
+ cmdRunIssue: withShutdown(cmdRunIssue),
3126
+ cmdRunBrief: withShutdown(cmdRunBrief),
3071
3127
  cmdLocalSmallDryRun,
3072
3128
  cmdLocalSmallOvernight,
3073
3129
  cmdLand,
3074
3130
  cmdResumeApproved,
3075
- cmdRun: runRun,
3131
+ cmdRun: withShutdown(runRun),
3076
3132
  cmdProxy,
3077
3133
  cmdFactoryd,
3078
3134
  cmdDaemonStart,
@@ -3085,8 +3141,9 @@ export const PROGRAM_HANDLERS = {
3085
3141
  cmdWorktreeRelease,
3086
3142
  cmdBaselineClear,
3087
3143
  cmdBreakerReset,
3144
+ cmdRespond,
3088
3145
  cmdReset,
3089
- cmdSupervise: runSupervise,
3146
+ cmdSupervise: withShutdown(runSupervise),
3090
3147
  cmdStop,
3091
3148
  cmdResume,
3092
3149
  cmdSteer: runSteerCommand,