@on-par/factory-cli 0.9.8-next.9 → 0.9.8
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/dist/cli/agent-job.d.ts +29 -0
- package/dist/cli/agent-job.d.ts.map +1 -0
- package/dist/cli/agent-job.js +63 -0
- package/dist/cli/agent-job.js.map +1 -0
- package/dist/cli/doctor-harness.d.ts +11 -0
- package/dist/cli/doctor-harness.d.ts.map +1 -1
- package/dist/cli/doctor-harness.js +43 -1
- package/dist/cli/doctor-harness.js.map +1 -1
- package/dist/cli/doctor-opencode-probe.d.ts +22 -0
- package/dist/cli/doctor-opencode-probe.d.ts.map +1 -0
- package/dist/cli/doctor-opencode-probe.js +110 -0
- package/dist/cli/doctor-opencode-probe.js.map +1 -0
- package/dist/cli/doctor.d.ts +30 -8
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +114 -44
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/first-run.d.ts +3 -1
- package/dist/cli/first-run.d.ts.map +1 -1
- package/dist/cli/first-run.js +5 -2
- package/dist/cli/first-run.js.map +1 -1
- package/dist/cli/github-stub.js +1 -1
- package/dist/cli/github-stub.js.map +1 -1
- package/dist/cli/harness-check.d.ts +27 -0
- package/dist/cli/harness-check.d.ts.map +1 -0
- package/dist/cli/harness-check.js +58 -0
- package/dist/cli/harness-check.js.map +1 -0
- package/dist/cli/help-groups.d.ts.map +1 -1
- package/dist/cli/help-groups.js +2 -1
- package/dist/cli/help-groups.js.map +1 -1
- package/dist/cli/host-slot.d.ts +4 -0
- package/dist/cli/host-slot.d.ts.map +1 -0
- package/dist/cli/host-slot.js +8 -0
- package/dist/cli/host-slot.js.map +1 -0
- package/dist/cli/index.d.ts +21 -18
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +66 -61
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/program-advanced.d.ts.map +1 -1
- package/dist/cli/program-advanced.js +19 -0
- package/dist/cli/program-advanced.js.map +1 -1
- package/dist/cli/program-run-work.js +2 -2
- package/dist/cli/program-run-work.js.map +1 -1
- package/dist/cli/program-setup.d.ts.map +1 -1
- package/dist/cli/program-setup.js +10 -1
- package/dist/cli/program-setup.js.map +1 -1
- package/dist/cli/queue-add-json.d.ts +3 -1
- package/dist/cli/queue-add-json.d.ts.map +1 -1
- package/dist/cli/queue-add-json.js +1 -0
- package/dist/cli/queue-add-json.js.map +1 -1
- package/dist/cli/queue-output.d.ts +9 -0
- package/dist/cli/queue-output.d.ts.map +1 -0
- package/dist/cli/queue-output.js +38 -0
- package/dist/cli/queue-output.js.map +1 -0
- package/dist/cli/queue-startup.d.ts +8 -0
- package/dist/cli/queue-startup.d.ts.map +1 -0
- package/dist/cli/queue-startup.js +27 -0
- package/dist/cli/queue-startup.js.map +1 -0
- package/dist/cli/run-lane.d.ts +11 -1
- package/dist/cli/run-lane.d.ts.map +1 -1
- package/dist/cli/run-lane.js +27 -2
- package/dist/cli/run-lane.js.map +1 -1
- package/dist/cli/run.d.ts +1 -0
- package/dist/cli/run.d.ts.map +1 -1
- package/dist/cli/run.js +17 -2
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/self-update-apply.d.ts.map +1 -1
- package/dist/cli/self-update-apply.js +24 -2
- package/dist/cli/self-update-apply.js.map +1 -1
- package/dist/cli/self-update.d.ts +4 -0
- package/dist/cli/self-update.d.ts.map +1 -1
- package/dist/cli/self-update.js +1 -1
- package/dist/cli/self-update.js.map +1 -1
- package/dist/cli/ship.d.ts.map +1 -1
- package/dist/cli/ship.js +21 -10
- package/dist/cli/ship.js.map +1 -1
- package/dist/cli/status-host-slots.d.ts +4 -0
- package/dist/cli/status-host-slots.d.ts.map +1 -0
- package/dist/cli/status-host-slots.js +17 -0
- package/dist/cli/status-host-slots.js.map +1 -0
- package/dist/cli/status.d.ts +5 -0
- package/dist/cli/status.d.ts.map +1 -1
- package/dist/cli/status.js +16 -5
- package/dist/cli/status.js.map +1 -1
- package/dist/cli/stop-sentinel.d.ts +4 -0
- package/dist/cli/stop-sentinel.d.ts.map +1 -1
- package/dist/cli/stop-sentinel.js +11 -0
- package/dist/cli/stop-sentinel.js.map +1 -1
- package/dist/cli/supervise.d.ts +5 -0
- package/dist/cli/supervise.d.ts.map +1 -1
- package/dist/cli/supervise.js +1 -0
- package/dist/cli/supervise.js.map +1 -1
- package/dist/cli/triage-open-prs.d.ts +10 -0
- package/dist/cli/triage-open-prs.d.ts.map +1 -0
- package/dist/cli/triage-open-prs.js +38 -0
- package/dist/cli/triage-open-prs.js.map +1 -0
- package/dist/cli/update-state.d.ts +2 -0
- package/dist/cli/update-state.d.ts.map +1 -1
- package/dist/cli/update-state.js +14 -0
- package/dist/cli/update-state.js.map +1 -1
- package/dist/cli/worktree-reap.d.ts +31 -0
- package/dist/cli/worktree-reap.d.ts.map +1 -0
- package/dist/cli/worktree-reap.js +72 -0
- package/dist/cli/worktree-reap.js.map +1 -0
- package/package.json +3 -3
package/dist/cli/index.js
CHANGED
|
@@ -7,12 +7,16 @@ import { arch, hostname as osHostname, release, platform, userInfo } from 'node:
|
|
|
7
7
|
import { basename, dirname, isAbsolute, join, relative, resolve } from 'node:path';
|
|
8
8
|
import { promisify, styleText } from 'node:util';
|
|
9
9
|
import { INVALID_BRANCH_PREFIX_MESSAGE, resolveBranchPrefixOption } from './branch-prefix.js';
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
10
|
+
import { sweepLaneClaims, warnQueueDiagnostics } from './queue-startup.js';
|
|
11
|
+
import { proposeTriageQueue } from './triage-open-prs.js';
|
|
12
|
+
import { acquirePortLease, aggregateCosts, appendKpiHistoryLine, applyRepoConfig, buildPhase, checkPhase, clearProxyState, computeHealthKpis, ConstitutionLoader, createDefaultWorkSourceRegistry, createLogger, createLaneProxy, defaultFindPortListeners, describeEffectiveConfig, detectPostMergeDefects, diagnoseModels, probeDeclaredHarnesses, estimateTrailingSpend, fetchDefectSources, fetchHumanEventSources, fetchSubscriptionUsage, formatUsageReport, getConstitutionsDir, getFactoryPaths, GITHUB_ISSUE_SOURCE, hasUnresolvedPark, InvalidArtifactsDirError, InvalidWorkRequestInputError, InvalidWorkspaceError, isCommandAvailable, isProxyRunning, kpiBranchPrefixes, kpisToHistoryRecord, laneBaseUrl, laneEnv, laneHostLabel, loadFactoryConfigForRepo, loadModelsConfig, loadRepoConfig, loadRoutesConfig, LOCAL_BRIEF_SOURCE, 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, resolveArtifactsDir, resolveLocalOnlyPolicy, resolveMergePolicy, resolveSkipCI, resolveTimeouts, resolveUsageCap, resolveWatchdogPolicy, runAutoIngest, shipPhase, formatCostTotal, validateQueue, watchUsage, writeLocalRunReport, writeProxyState, } from '@on-par/factory-core';
|
|
13
|
+
import { acquirePidFile, createCheckResumeStore, findSlicePlanComment, upsertSlicePlanComment, withSliceState, DEFAULT_GARDEN_MAX_CLUSTERS, DEFAULT_GARDEN_SINCE, capGardenClusters, clusterGarden, dedupGardenClusters, filterGardenOnlyNew, filterGardenWindow, markGardenTrackingUnknown, parseGardenDuration, readHarvestEvents, renderGardenJson, renderGardenReport, laneWorktreePath, migrateRepoConfigToYaml, REPO_CONFIG_YAML_HEADER, claudeConfigDirOverride, claudeKeychainService, cleanupWorktree, createDaemonLogSink, factoryBranchIssue, factoryBranchPrefixes, createFactorydServer, createRunRuntime, createShipExecutor, createGithubQueue, createLocalSmallDryRun, createOctokitFilingClient, createOctokitGreenPrClient, createOctokitQueueClient, daemonRuntimePaths, defaultRegistryPath, ensureDir, FACTORY_RUNTIME_CONFIG_KEYS, findUnmergedGreenPrs, formatGcReport, gitFetch, listMicroVms, listOrphanContainers, logCost, logEvent, planQueueMigration, pollBlockedParks, readCosts, readGithubQueueSnapshot, reapCleanShipWorktree, reapLaneWorktree, reapOrphanContainers, reapOrphanMicroVm, releaseRuntimeFiles, releaseStaleClaims, resolveBranchPrefix, resolveEffectiveConfig, resolveExperimental, resolveLocalOnly, resolvePrClassifierPolicy, resolveReviewFloorRules, RunLockHeldError, runOvernightQueue, parseRemoteSlug, setupWorktree, shellEscape, listBuiltInCheckers, sweepWorktrees, watchChecks, withFileLock, withGitLock, withRunLock, writePortFile, buildTriagePrompt, parseTriageCandidates, recordLocalAuthFailure, } from '@on-par/factory-core/internal';
|
|
12
14
|
import { runTui } from '@on-par/factory-tui';
|
|
13
15
|
import { admissionStateReaderFor, runQueueReconcile } from './admission.js';
|
|
14
16
|
import { cmdClassifierBacktest, ClassifierBacktestInputError, } from './classifier-backtest.js';
|
|
17
|
+
import { runHarnessCheckCommand } from './harness-check.js';
|
|
15
18
|
import { findOpenPRForIssue, landIssue } from './land.js';
|
|
19
|
+
import { STOP_SET_MESSAGE } from './stop-sentinel.js';
|
|
16
20
|
import { AwaitingReviewError, CiFailedError, CiUnverifiedError, getPullRequestLandState, LandConflictError, LandFailureError, MergeGatedError, } from './land-pr.js';
|
|
17
21
|
import { setLandRuntime } from './land-runtime.js';
|
|
18
22
|
import { cmdRun } from './run.js';
|
|
@@ -24,6 +28,7 @@ import { runQueueClear } from './queue-clear.js';
|
|
|
24
28
|
import { buildProgram } from './program.js';
|
|
25
29
|
import { buildCostJson } from './cost-json.js';
|
|
26
30
|
import { buildQueueAddJson } from './queue-add-json.js';
|
|
31
|
+
import { renderQueueAddLines, renderUnparkLines } from './queue-output.js';
|
|
27
32
|
import { buildQueueListJson } from './queue-list.js';
|
|
28
33
|
import { appendUnparkEvent, runUnpark, UnparkError } from './unpark.js';
|
|
29
34
|
import { buildRunsJson, parseRunsLimit } from './runs.js';
|
|
@@ -50,6 +55,7 @@ import { DeepCheckError, createDeepModelRunner, runIssueCheck } from './ready-ch
|
|
|
50
55
|
import { childRunSucceeded, formatChildRunSummary, runChildrenInOrder } from './run-children.js';
|
|
51
56
|
import { readRunFlagOverrides } from './run-flags.js';
|
|
52
57
|
import { runStalenessGuard } from './staleness.js';
|
|
58
|
+
import { gcWorktreeSandbox, reapParkedLane, reapPrlessShip } from './worktree-reap.js';
|
|
53
59
|
const DEFAULT_CONFIG_LOADERS = {
|
|
54
60
|
loadModelsConfig,
|
|
55
61
|
loadRoutesConfig,
|
|
@@ -96,6 +102,7 @@ const DEFAULT_INTERNAL_OPS = {
|
|
|
96
102
|
createLocalSmallDryRun,
|
|
97
103
|
readCosts,
|
|
98
104
|
sweepWorktrees,
|
|
105
|
+
reapCleanShipWorktree,
|
|
99
106
|
releaseStaleClaims,
|
|
100
107
|
pollBlockedParks,
|
|
101
108
|
findUnmergedGreenPrs,
|
|
@@ -114,6 +121,7 @@ function resolveInternalOps(overrides, base = internalOps) {
|
|
|
114
121
|
createLocalSmallDryRun: overrides.createLocalSmallDryRun ?? base.createLocalSmallDryRun,
|
|
115
122
|
readCosts: overrides.readCosts ?? base.readCosts,
|
|
116
123
|
sweepWorktrees: overrides.sweepWorktrees ?? base.sweepWorktrees,
|
|
124
|
+
reapCleanShipWorktree: overrides.reapCleanShipWorktree ?? base.reapCleanShipWorktree,
|
|
117
125
|
releaseStaleClaims: overrides.releaseStaleClaims ?? base.releaseStaleClaims,
|
|
118
126
|
pollBlockedParks: overrides.pollBlockedParks ?? base.pollBlockedParks,
|
|
119
127
|
findUnmergedGreenPrs: overrides.findUnmergedGreenPrs ?? base.findUnmergedGreenPrs,
|
|
@@ -414,7 +422,7 @@ async function cmdInit(opts = {}) {
|
|
|
414
422
|
// Doctor-style validation (policy=auto, N models reachable) — informational, never fails init.
|
|
415
423
|
const modelsConfig = applyRepoConfig(configLoaders.loadModelsConfig(), configLoaders.loadRepoConfig(repoRoot));
|
|
416
424
|
const registry = new coreOps.ModelRegistry(modelsConfig);
|
|
417
|
-
const diagnoses = coreOps.diagnoseModels(registry, modelDoctorProbes(
|
|
425
|
+
const diagnoses = coreOps.diagnoseModels(registry, modelDoctorProbes(), resolveExperimental(), resolveLocalOnly());
|
|
418
426
|
console.log(formatInitReachability(diagnoses));
|
|
419
427
|
if (!hasReachableWorker(diagnoses)) {
|
|
420
428
|
console.log(styleText('yellow', 'No worker model reachable yet — see `factory doctor` and `factory models --doctor`.'));
|
|
@@ -815,8 +823,8 @@ export function formatDoctorReport(diagnoses, repoDefined = new Set()) {
|
|
|
815
823
|
export function hasReachableWorker(diagnoses) {
|
|
816
824
|
return diagnoses.some((d) => d.reachable && (d.tiers.includes('worker') || d.tiers.includes('worker_fallback')));
|
|
817
825
|
}
|
|
818
|
-
function ollamaModelSet(
|
|
819
|
-
if (
|
|
826
|
+
function ollamaModelSet() {
|
|
827
|
+
if (!coreOps.isCommandAvailable('ollama'))
|
|
820
828
|
return undefined;
|
|
821
829
|
try {
|
|
822
830
|
const out = shellOps.execSync('ollama list', { timeout: 10_000 });
|
|
@@ -831,15 +839,21 @@ function ollamaModelSet(requireOnPath = false) {
|
|
|
831
839
|
}
|
|
832
840
|
}
|
|
833
841
|
/** Probes shared by every doctor-style reachability check (init, models --doctor, overnight
|
|
834
|
-
* preflight), so their counts agree.
|
|
835
|
-
* reaches the shell (#2507). */
|
|
836
|
-
export function modelDoctorProbes(
|
|
837
|
-
const ollamaModels = ollamaModelSet(
|
|
842
|
+
* preflight), so their counts agree. The probes never invoke `ollama` unless it is on PATH, so a
|
|
843
|
+
* missing binary never reaches the shell (#2507, #2724). */
|
|
844
|
+
export function modelDoctorProbes() {
|
|
845
|
+
const ollamaModels = ollamaModelSet();
|
|
838
846
|
return {
|
|
839
847
|
commandAvailable: coreOps.isCommandAvailable,
|
|
840
848
|
ollamaModelPresent: ollamaModels ? (model) => ollamaModels.has(model) : undefined,
|
|
841
849
|
};
|
|
842
850
|
}
|
|
851
|
+
async function cmdHarnessCheck(id, opts) {
|
|
852
|
+
const r = await runHarnessCheckCommand(id, opts, { repoRoot: await getRepoRoot(), ...configLoaders });
|
|
853
|
+
if (r.exitCode !== 0)
|
|
854
|
+
throw new CliExitError(r.output, r.exitCode);
|
|
855
|
+
console.log(r.output);
|
|
856
|
+
}
|
|
843
857
|
async function cmdModels(opts = {}) {
|
|
844
858
|
const repoRoot = await getRepoRoot();
|
|
845
859
|
const repoConfig = configLoaders.loadRepoConfig(repoRoot);
|
|
@@ -1190,16 +1204,17 @@ export function resolveUsageKnobs(env = process.env, repoConfig = null, override
|
|
|
1190
1204
|
};
|
|
1191
1205
|
}
|
|
1192
1206
|
/** Human-readable name for whatever decided the usage-watch gate, used in the `factory run`
|
|
1193
|
-
* and `factory supervise` logs so an explicit operator override is always attributable (#1404).
|
|
1194
|
-
|
|
1207
|
+
* and `factory supervise` logs so an explicit operator override is always attributable (#1404). `repoConfigLabel` names the
|
|
1208
|
+
* repo config file that was loaded (#2570). */
|
|
1209
|
+
export function usageWatchSourceLabel(source, watch, repoConfigLabel = 'the repo config') {
|
|
1195
1210
|
switch (source) {
|
|
1196
1211
|
case 'flag':
|
|
1197
1212
|
return watch ? 'flag: --usage-watch' : 'flag: --no-usage-watch';
|
|
1198
1213
|
case 'repo':
|
|
1199
|
-
return
|
|
1214
|
+
return `${repoConfigLabel}: budget.watchdog.watch`;
|
|
1200
1215
|
case 'env':
|
|
1201
1216
|
return 'env: FACTORY_USAGE_WATCH';
|
|
1202
|
-
default:
|
|
1217
|
+
case 'default':
|
|
1203
1218
|
return 'default';
|
|
1204
1219
|
}
|
|
1205
1220
|
}
|
|
@@ -1240,11 +1255,6 @@ export async function cmdUsage(deps = {}, opts = {}) {
|
|
|
1240
1255
|
console.log(heuristicLine);
|
|
1241
1256
|
}
|
|
1242
1257
|
}
|
|
1243
|
-
function warnQueueDiagnostics(diagnostics) {
|
|
1244
|
-
for (const d of diagnostics) {
|
|
1245
|
-
console.error(styleText('yellow', `factory: queue ${d.message} — skipped`));
|
|
1246
|
-
}
|
|
1247
|
-
}
|
|
1248
1258
|
/** GitHub is polled far less often than local files: a queue changes on the order of minutes. */
|
|
1249
1259
|
const TUI_GITHUB_QUEUE_POLL_MS = 30_000;
|
|
1250
1260
|
/** The Queue tab's backlog source for `factory tui` (#1362). Mirrors `factory run`: GitHub Issues
|
|
@@ -1304,7 +1314,7 @@ async function cmdTui(opts = {}, runTuiImpl = runTui) {
|
|
|
1304
1314
|
const effectiveConfigLines = describeEffectiveConfig({
|
|
1305
1315
|
router,
|
|
1306
1316
|
repo: repoConfig,
|
|
1307
|
-
repoConfigPath:
|
|
1317
|
+
repoConfigPath: repoConfigFileFor(repoRoot, paths.config).relPath,
|
|
1308
1318
|
mergePolicy: resolveMergePolicy(configLoaders.loadFactoryConfigForRepo(paths.config), process.env, {
|
|
1309
1319
|
auto: readRunFlagOverrides(paths.runFlags).autoMerge,
|
|
1310
1320
|
}),
|
|
@@ -1451,6 +1461,7 @@ export function resolveEnvironmentAcquirer(opts) {
|
|
|
1451
1461
|
};
|
|
1452
1462
|
};
|
|
1453
1463
|
}
|
|
1464
|
+
const sweepStaleLaneClaims = (paths, ghRepo) => sweepLaneClaims(paths, ghRepo, () => (hasGitHubToken() ? getOctokit() : undefined));
|
|
1454
1465
|
/** The autoGcOnRun-gated worktree sweep every pipeline entry point runs before shipping
|
|
1455
1466
|
* (`factory run`, and since #1756 the one-shot `factory ship` / `factory run-issue`). Never
|
|
1456
1467
|
* throws — a GC failure is a warn, never a reason to abort the command. */
|
|
@@ -1479,14 +1490,15 @@ async function runAutoWorktreeGc(repoRoot, paths, ghRepo, eventScope) {
|
|
|
1479
1490
|
* lane holds the land lock so a sweep can never race a merge. Logs worktree-gc only when it
|
|
1480
1491
|
* removed something. Never throws. */
|
|
1481
1492
|
export async function sweepBetweenLaneIssues(issue, lane, repoRoot, ghRepo, paths, deps = {}) {
|
|
1482
|
-
const { loadConfig = configLoaders.loadFactoryConfigForRepo, sweep = internalOps.sweepWorktrees, emitEvent = logEvent, octokit = getOctokit, } = deps;
|
|
1493
|
+
const { loadConfig = configLoaders.loadFactoryConfigForRepo, sweep = internalOps.sweepWorktrees, emitEvent = logEvent, octokit = getOctokit, protectedIssues = () => new Set(), } = deps;
|
|
1483
1494
|
try {
|
|
1484
1495
|
const cfg = loadConfig(paths.config);
|
|
1485
1496
|
if (!cfg.worktree.autoGcOnRun)
|
|
1486
1497
|
return 'disabled';
|
|
1487
1498
|
const gcLog = (type, msg) => emitEvent(paths.events, type, issue, msg, { lane });
|
|
1488
1499
|
const sandbox = gcWorktreeSandbox(cfg.sandbox, repoRoot);
|
|
1489
|
-
const
|
|
1500
|
+
const gcOpts = { repoRoot, ttlDays: cfg.worktree.gcTtlDays, repo: ghRepo, branchPrefix: resolveBranchPrefix() };
|
|
1501
|
+
const report = await withGitLock(repoRoot, () => withFileLock(paths.mergeLock, () => withFileLock(paths.gitLock, () => sweep({ ...gcOpts, protectedIssues: protectedIssues() }, { log: gcLog, octokit: octokit(), sandbox })), { timeoutMs: 0 }));
|
|
1490
1502
|
if (report.removed.length > 0) {
|
|
1491
1503
|
emitEvent(paths.events, 'worktree-gc', issue, `removed ${report.removed.length} stale worktree(s), kept ${report.kept}`, { lane });
|
|
1492
1504
|
console.log(internalOps.formatGcReport(report));
|
|
@@ -1538,6 +1550,9 @@ async function cmdShip(issueNum, opts) {
|
|
|
1538
1550
|
catch (err) {
|
|
1539
1551
|
if (err instanceof IssueSkippedError)
|
|
1540
1552
|
return;
|
|
1553
|
+
if (ghRepo && !(err instanceof InvalidWorkRequestInputError) && !(err instanceof LaneEnvironmentPauseError)) {
|
|
1554
|
+
await reapPrlessShipWorktree(issueNum, repoRoot, ghRepo, paths, branchPrefix);
|
|
1555
|
+
}
|
|
1541
1556
|
// #2492: a pull request number is a usage error, not a failed ship.
|
|
1542
1557
|
if (err instanceof InvalidWorkRequestInputError)
|
|
1543
1558
|
throw new CliExitError(`factory: ${err.message}`, 2);
|
|
@@ -1853,30 +1868,23 @@ export async function withRepoRunLock(paths, command, fn, deps = {}) {
|
|
|
1853
1868
|
throw err;
|
|
1854
1869
|
}
|
|
1855
1870
|
}
|
|
1856
|
-
/** The repo's current docker-sandbox descriptor for worktree-gc sweeps, or undefined for
|
|
1857
|
-
* every other runtime/config state (including a fixture config with no `sandbox` key). */
|
|
1858
|
-
function gcWorktreeSandbox(sandboxCfg, repoRoot) {
|
|
1859
|
-
if (!sandboxCfg)
|
|
1860
|
-
return undefined;
|
|
1861
|
-
const policy = resolveSandboxPolicy(sandboxCfg, { worktree: repoRoot, repoRoot });
|
|
1862
|
-
return worktreeSandboxFor(policy?.runtime);
|
|
1863
|
-
}
|
|
1864
|
-
/** Eagerly reaps a parked lane's own worktree inside `factory run` (#1007). All the safety
|
|
1865
|
-
* gates live in reapLaneWorktree; this wrapper resolves the lane's conventional worktree
|
|
1866
|
-
* path and holds the same git+file lock pairing as every other worktree mutation site. A
|
|
1867
|
-
* reap failure is logged as a warn and never surfaces — parking must always succeed. */
|
|
1868
1871
|
export async function reapParkedLaneWorktree(issue, repoRoot, ghRepo, paths, prefixOverride) {
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1872
|
+
await reapParkedLane({ configLoaders, worktreePathFor }, reapLaneWorktree, [
|
|
1873
|
+
issue,
|
|
1874
|
+
repoRoot,
|
|
1875
|
+
ghRepo,
|
|
1876
|
+
paths,
|
|
1877
|
+
prefixOverride,
|
|
1878
|
+
]);
|
|
1879
|
+
}
|
|
1880
|
+
export async function reapPrlessShipWorktree(issue, repoRoot, ghRepo, paths, prefixOverride) {
|
|
1881
|
+
await reapPrlessShip({ configLoaders, worktreePathFor }, internalOps.reapCleanShipWorktree, [
|
|
1882
|
+
issue,
|
|
1883
|
+
repoRoot,
|
|
1884
|
+
ghRepo,
|
|
1885
|
+
paths,
|
|
1886
|
+
prefixOverride,
|
|
1887
|
+
]);
|
|
1880
1888
|
}
|
|
1881
1889
|
export async function cmdWorktreeGc(opts) {
|
|
1882
1890
|
const repoRoot = await getRepoRoot();
|
|
@@ -2016,7 +2024,7 @@ async function cmdTriage(opts) {
|
|
|
2016
2024
|
onLog: (msg) => logEvent(paths.events, 'triage', '-', msg),
|
|
2017
2025
|
});
|
|
2018
2026
|
model = result.model;
|
|
2019
|
-
const queue =
|
|
2027
|
+
const queue = await proposeTriageQueue(result.output, ghRepo, paths.events, shellOps.exec);
|
|
2020
2028
|
if (queue) {
|
|
2021
2029
|
const header = triageQueueHeader(model, product);
|
|
2022
2030
|
writeFileSync(paths.queueProposed, header + queue);
|
|
@@ -2176,7 +2184,8 @@ export async function cmdUnpark(issueArg, opts = {}) {
|
|
|
2176
2184
|
console.log(JSON.stringify(result));
|
|
2177
2185
|
return;
|
|
2178
2186
|
}
|
|
2179
|
-
|
|
2187
|
+
for (const line of renderUnparkLines(result))
|
|
2188
|
+
console.log(line);
|
|
2180
2189
|
}
|
|
2181
2190
|
export async function cmdQueueAdd(lane, issueArgs, opts = {}) {
|
|
2182
2191
|
// Validate + dedupe BEFORE any GitHub call. parseIssueArg throws CliExitError(2) on bad input.
|
|
@@ -2215,17 +2224,8 @@ export async function cmdQueueAdd(lane, issueArgs, opts = {}) {
|
|
|
2215
2224
|
}
|
|
2216
2225
|
return;
|
|
2217
2226
|
}
|
|
2218
|
-
for (const
|
|
2219
|
-
|
|
2220
|
-
console.log(styleText('green', `#${r.issue} queued → lane ${lane}, position ${r.position}`));
|
|
2221
|
-
}
|
|
2222
|
-
else if (r.outcome === 'already-queued') {
|
|
2223
|
-
console.log(`#${r.issue} already queued — skipped`);
|
|
2224
|
-
}
|
|
2225
|
-
else {
|
|
2226
|
-
console.error(styleText('red', `#${r.issue} failed — ${r.detail}`));
|
|
2227
|
-
}
|
|
2228
|
-
}
|
|
2227
|
+
for (const line of renderQueueAddLines(lane, results))
|
|
2228
|
+
(line.stream === 'err' ? console.error : console.log)(line.text);
|
|
2229
2229
|
const failed = results.filter((r) => r.outcome === 'failed');
|
|
2230
2230
|
if (failed.length > 0) {
|
|
2231
2231
|
throw new CliExitError(`factory: ${failed.length} issue(s) failed to queue`, 1);
|
|
@@ -2235,6 +2235,7 @@ export async function cmdQueueReconcile(opts = {}) {
|
|
|
2235
2235
|
const repoRoot = await getRepoRoot();
|
|
2236
2236
|
const paths = getFactoryPaths(repoRoot);
|
|
2237
2237
|
const [owner, repo] = (await getGitHubRepo()).split('/');
|
|
2238
|
+
await sweepStaleLaneClaims(paths, `${owner}/${repo}`);
|
|
2238
2239
|
const client = createOctokitQueueClient(getOctokit());
|
|
2239
2240
|
const { report, conflicts } = await runQueueReconcile({
|
|
2240
2241
|
readSnapshot: () => readGithubQueueSnapshot({ client, owner, repo }),
|
|
@@ -2849,7 +2850,7 @@ export async function cmdResumeApproved(opts = {}) {
|
|
|
2849
2850
|
}
|
|
2850
2851
|
const USAGE_UNAVAILABLE_LINE = '[factory] supervise: usage signal unavailable — proceeding without resume gate (set FACTORY_USAGE_ESTIMATOR=1 to gate on the heuristic)';
|
|
2851
2852
|
export async function superviseLoop(deps) {
|
|
2852
|
-
const { cap, resumeAt, pollMs, watch = true, watchSource = 'default', resumeAtSource = 'default', pollSource = 'default', estimator = false, stopFile, eventsFile, now, runQueue, readUsageFn = () => readUsage({ cap, estimator }), pathExists = existsSync, clearStop = (path) => rmSync(path, { force: true }), sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)), emitEvent = logEvent, writeLine = (line) => console.log(line), ingest, } = deps;
|
|
2853
|
+
const { cap, resumeAt, pollMs, watch = true, watchSource = 'default', repoConfigLabel, resumeAtSource = 'default', pollSource = 'default', estimator = false, stopFile, eventsFile, now, runQueue, readUsageFn = () => readUsage({ cap, estimator }), pathExists = existsSync, clearStop = (path) => rmSync(path, { force: true }), sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)), emitEvent = logEvent, writeLine = (line) => console.log(line), ingest, } = deps;
|
|
2853
2854
|
let cycle = 0;
|
|
2854
2855
|
if (resumeAtSource === 'flag') {
|
|
2855
2856
|
const detail = 'usage watchdog threshold set by flag: --usage-threshold';
|
|
@@ -2866,11 +2867,11 @@ export async function superviseLoop(deps) {
|
|
|
2866
2867
|
let pct = 0;
|
|
2867
2868
|
let source = 'unavailable';
|
|
2868
2869
|
if (!watch) {
|
|
2869
|
-
writeLine(`[factory] supervise: usage watchdog disabled (${usageWatchSourceLabel(watchSource, watch)}) — skipping resume gate`);
|
|
2870
|
+
writeLine(`[factory] supervise: usage watchdog disabled (${usageWatchSourceLabel(watchSource, watch, repoConfigLabel)}) — skipping resume gate`);
|
|
2870
2871
|
}
|
|
2871
2872
|
else {
|
|
2872
2873
|
if (watchSource === 'flag') {
|
|
2873
|
-
writeLine(`[factory] supervise: usage watchdog enabled (${usageWatchSourceLabel(watchSource, watch)}) — enforcing resume gate`);
|
|
2874
|
+
writeLine(`[factory] supervise: usage watchdog enabled (${usageWatchSourceLabel(watchSource, watch, repoConfigLabel)}) — enforcing resume gate`);
|
|
2874
2875
|
}
|
|
2875
2876
|
let reading = await readUsageFn();
|
|
2876
2877
|
if (reading === null) {
|
|
@@ -3009,7 +3010,7 @@ export async function cmdStop(opts = {}) {
|
|
|
3009
3010
|
console.log(JSON.stringify(buildStopResumeJson({ action: 'stop', repo: json.repo, before, after })));
|
|
3010
3011
|
return;
|
|
3011
3012
|
}
|
|
3012
|
-
console.log(
|
|
3013
|
+
console.log(STOP_SET_MESSAGE);
|
|
3013
3014
|
}
|
|
3014
3015
|
export async function cmdResume(issue, opts = {}) {
|
|
3015
3016
|
if (issue === undefined && opts.from !== undefined) {
|
|
@@ -3095,6 +3096,7 @@ function runSupervise(opts) {
|
|
|
3095
3096
|
createIngestHook,
|
|
3096
3097
|
cmdRun: (o) => runRun(o),
|
|
3097
3098
|
CliExitError,
|
|
3099
|
+
repoConfigFileFor,
|
|
3098
3100
|
});
|
|
3099
3101
|
}
|
|
3100
3102
|
/** `factory status` (#2798): the handler lives in ./status.ts; this binds its runtime. */
|
|
@@ -3111,6 +3113,7 @@ function runStatus(opts = {}) {
|
|
|
3111
3113
|
warnQueueDiagnostics,
|
|
3112
3114
|
errorDetail,
|
|
3113
3115
|
CliExitError,
|
|
3116
|
+
repoConfigFileFor,
|
|
3114
3117
|
});
|
|
3115
3118
|
}
|
|
3116
3119
|
/** `factory run` (#2800): the handler lives in ./run.ts; this binds its runtime. */
|
|
@@ -3126,6 +3129,7 @@ function runRun(opts = {}) {
|
|
|
3126
3129
|
branchPrefixOrExit,
|
|
3127
3130
|
withRepoRunLock,
|
|
3128
3131
|
runAutoWorktreeGc,
|
|
3132
|
+
sweepStaleLaneClaims,
|
|
3129
3133
|
planRunLanes,
|
|
3130
3134
|
preflightQueuedIssue,
|
|
3131
3135
|
createQueuePreflightOps,
|
|
@@ -3165,6 +3169,7 @@ export const PROGRAM_HANDLERS = {
|
|
|
3165
3169
|
cmdMigrate,
|
|
3166
3170
|
cmdConstitution,
|
|
3167
3171
|
cmdModels,
|
|
3172
|
+
cmdHarnessCheck,
|
|
3168
3173
|
cmdDoctor: runDoctor,
|
|
3169
3174
|
cmdCost,
|
|
3170
3175
|
cmdUsage,
|