@on-par/factory-cli 0.0.0-stage → 0.9.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/LICENSE +21 -0
- package/README.md +40 -2
- package/dist/cli/admission.d.ts +17 -0
- package/dist/cli/admission.d.ts.map +1 -0
- package/dist/cli/admission.js +37 -0
- package/dist/cli/admission.js.map +1 -0
- package/dist/cli/base-hold.d.ts +63 -0
- package/dist/cli/base-hold.d.ts.map +1 -0
- package/dist/cli/base-hold.js +122 -0
- package/dist/cli/base-hold.js.map +1 -0
- package/dist/cli/branch-prefix.d.ts +8 -0
- package/dist/cli/branch-prefix.d.ts.map +1 -0
- package/dist/cli/branch-prefix.js +16 -0
- package/dist/cli/branch-prefix.js.map +1 -0
- package/dist/cli/classifier-backtest.d.ts +50 -0
- package/dist/cli/classifier-backtest.d.ts.map +1 -0
- package/dist/cli/classifier-backtest.js +112 -0
- package/dist/cli/classifier-backtest.js.map +1 -0
- package/dist/cli/cost-json.d.ts +37 -0
- package/dist/cli/cost-json.d.ts.map +1 -0
- package/dist/cli/cost-json.js +48 -0
- package/dist/cli/cost-json.js.map +1 -0
- package/dist/cli/daemon.d.ts +162 -0
- package/dist/cli/daemon.d.ts.map +1 -0
- package/dist/cli/daemon.js +393 -0
- package/dist/cli/daemon.js.map +1 -0
- package/dist/cli/doctor.d.ts +127 -0
- package/dist/cli/doctor.d.ts.map +1 -0
- package/dist/cli/doctor.js +400 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cli/feedback.d.ts +74 -0
- package/dist/cli/feedback.d.ts.map +1 -0
- package/dist/cli/feedback.js +180 -0
- package/dist/cli/feedback.js.map +1 -0
- package/dist/cli/filing.d.ts +22 -0
- package/dist/cli/filing.d.ts.map +1 -0
- package/dist/cli/filing.js +53 -0
- package/dist/cli/filing.js.map +1 -0
- package/dist/cli/first-run.d.ts +9 -0
- package/dist/cli/first-run.d.ts.map +1 -0
- package/dist/cli/first-run.js +34 -0
- package/dist/cli/first-run.js.map +1 -0
- package/dist/cli/help-groups.d.ts +17 -0
- package/dist/cli/help-groups.d.ts.map +1 -0
- package/dist/cli/help-groups.js +59 -0
- package/dist/cli/help-groups.js.map +1 -0
- package/dist/cli/hosted-queue.d.ts +45 -0
- package/dist/cli/hosted-queue.d.ts.map +1 -0
- package/dist/cli/hosted-queue.js +74 -0
- package/dist/cli/hosted-queue.js.map +1 -0
- package/dist/cli/hosted-runner.d.ts +44 -0
- package/dist/cli/hosted-runner.d.ts.map +1 -0
- package/dist/cli/hosted-runner.js +68 -0
- package/dist/cli/hosted-runner.js.map +1 -0
- package/dist/cli/hosted.d.ts +38 -0
- package/dist/cli/hosted.d.ts.map +1 -0
- package/dist/cli/hosted.js +82 -0
- package/dist/cli/hosted.js.map +1 -0
- package/dist/cli/index.d.ts +674 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +4916 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init-files.d.ts +8 -0
- package/dist/cli/init-files.d.ts.map +1 -0
- package/dist/cli/init-files.js +45 -0
- package/dist/cli/init-files.js.map +1 -0
- package/dist/cli/logs.d.ts +27 -0
- package/dist/cli/logs.d.ts.map +1 -0
- package/dist/cli/logs.js +52 -0
- package/dist/cli/logs.js.map +1 -0
- package/dist/cli/merge-scope.d.ts +7 -0
- package/dist/cli/merge-scope.d.ts.map +1 -0
- package/dist/cli/merge-scope.js +14 -0
- package/dist/cli/merge-scope.js.map +1 -0
- package/dist/cli/octokit.d.ts +43 -0
- package/dist/cli/octokit.d.ts.map +1 -0
- package/dist/cli/octokit.js +87 -0
- package/dist/cli/octokit.js.map +1 -0
- package/dist/cli/queue-add-json.d.ts +25 -0
- package/dist/cli/queue-add-json.d.ts.map +1 -0
- package/dist/cli/queue-add-json.js +24 -0
- package/dist/cli/queue-add-json.js.map +1 -0
- package/dist/cli/queue-clear.d.ts +15 -0
- package/dist/cli/queue-clear.d.ts.map +1 -0
- package/dist/cli/queue-clear.js +58 -0
- package/dist/cli/queue-clear.js.map +1 -0
- package/dist/cli/queue-list.d.ts +24 -0
- package/dist/cli/queue-list.d.ts.map +1 -0
- package/dist/cli/queue-list.js +25 -0
- package/dist/cli/queue-list.js.map +1 -0
- package/dist/cli/ready-check.d.ts +98 -0
- package/dist/cli/ready-check.d.ts.map +1 -0
- package/dist/cli/ready-check.js +169 -0
- package/dist/cli/ready-check.js.map +1 -0
- package/dist/cli/reset.d.ts +40 -0
- package/dist/cli/reset.d.ts.map +1 -0
- package/dist/cli/reset.js +215 -0
- package/dist/cli/reset.js.map +1 -0
- package/dist/cli/run-children.d.ts +24 -0
- package/dist/cli/run-children.d.ts.map +1 -0
- package/dist/cli/run-children.js +73 -0
- package/dist/cli/run-children.js.map +1 -0
- package/dist/cli/run-flags.d.ts +14 -0
- package/dist/cli/run-flags.d.ts.map +1 -0
- package/dist/cli/run-flags.js +43 -0
- package/dist/cli/run-flags.js.map +1 -0
- package/dist/cli/runs-diffstat.d.ts +43 -0
- package/dist/cli/runs-diffstat.d.ts.map +1 -0
- package/dist/cli/runs-diffstat.js +91 -0
- package/dist/cli/runs-diffstat.js.map +1 -0
- package/dist/cli/runs.d.ts +36 -0
- package/dist/cli/runs.d.ts.map +1 -0
- package/dist/cli/runs.js +102 -0
- package/dist/cli/runs.js.map +1 -0
- package/dist/cli/self-update.d.ts +68 -0
- package/dist/cli/self-update.d.ts.map +1 -0
- package/dist/cli/self-update.js +167 -0
- package/dist/cli/self-update.js.map +1 -0
- package/dist/cli/staleness.d.ts +30 -0
- package/dist/cli/staleness.d.ts.map +1 -0
- package/dist/cli/staleness.js +132 -0
- package/dist/cli/staleness.js.map +1 -0
- package/dist/cli/state-root.d.ts +5 -0
- package/dist/cli/state-root.d.ts.map +1 -0
- package/dist/cli/state-root.js +12 -0
- package/dist/cli/state-root.js.map +1 -0
- package/dist/cli/status-json.d.ts +49 -0
- package/dist/cli/status-json.d.ts.map +1 -0
- package/dist/cli/status-json.js +23 -0
- package/dist/cli/status-json.js.map +1 -0
- package/dist/cli/stop-resume-json.d.ts +18 -0
- package/dist/cli/stop-resume-json.d.ts.map +1 -0
- package/dist/cli/stop-resume-json.js +10 -0
- package/dist/cli/stop-resume-json.js.map +1 -0
- package/dist/cli/stop-sentinel.d.ts +23 -0
- package/dist/cli/stop-sentinel.d.ts.map +1 -0
- package/dist/cli/stop-sentinel.js +61 -0
- package/dist/cli/stop-sentinel.js.map +1 -0
- package/dist/cli/sweep-heartbeat.d.ts +33 -0
- package/dist/cli/sweep-heartbeat.d.ts.map +1 -0
- package/dist/cli/sweep-heartbeat.js +65 -0
- package/dist/cli/sweep-heartbeat.js.map +1 -0
- package/dist/cli/unpark.d.ts +28 -0
- package/dist/cli/unpark.d.ts.map +1 -0
- package/dist/cli/unpark.js +68 -0
- package/dist/cli/unpark.js.map +1 -0
- package/dist/cli/update-state.d.ts +44 -0
- package/dist/cli/update-state.d.ts.map +1 -0
- package/dist/cli/update-state.js +154 -0
- package/dist/cli/update-state.js.map +1 -0
- package/dist/cli/usage-json.d.ts +20 -0
- package/dist/cli/usage-json.d.ts.map +1 -0
- package/dist/cli/usage-json.js +36 -0
- package/dist/cli/usage-json.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +6 -0
- package/dist/cli.js.map +1 -0
- package/dist/entry.d.ts +6 -0
- package/dist/entry.d.ts.map +1 -0
- package/dist/entry.js +13 -0
- package/dist/entry.js.map +1 -0
- package/package.json +56 -4
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
// packages/cli/src/cli/staleness.ts — refuse to run from a dist/ older than src/
|
|
2
|
+
import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
|
|
3
|
+
import { dirname, join, resolve, sep } from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
export function defaultStalenessDeps() {
|
|
6
|
+
return {
|
|
7
|
+
exists: (p) => existsSync(p),
|
|
8
|
+
readFile: (p) => readFileSync(p, 'utf-8'),
|
|
9
|
+
listFiles: (dir) => {
|
|
10
|
+
const entries = readdirSync(dir, { recursive: true, withFileTypes: true });
|
|
11
|
+
return entries.filter((e) => e.isFile()).map((e) => join(e.parentPath, e.name));
|
|
12
|
+
},
|
|
13
|
+
mtimeMs: (p) => statSync(p).mtimeMs,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
const RUNTIME_PACKAGES = ['config', 'core', 'tui', 'cli'];
|
|
17
|
+
export function findWorkspaceRoot(startDir, deps) {
|
|
18
|
+
let dir = resolve(startDir);
|
|
19
|
+
for (;;) {
|
|
20
|
+
const pkgJsonPath = join(dir, 'package.json');
|
|
21
|
+
if (deps.exists(pkgJsonPath)) {
|
|
22
|
+
try {
|
|
23
|
+
const parsed = JSON.parse(deps.readFile(pkgJsonPath));
|
|
24
|
+
if (parsed.workspaces !== undefined)
|
|
25
|
+
return dir;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
// malformed package.json — not a match, keep walking
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const parent = dirname(dir);
|
|
32
|
+
if (parent === dir)
|
|
33
|
+
return undefined;
|
|
34
|
+
dir = parent;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function isComparableSrcFile(path) {
|
|
38
|
+
return (path.endsWith('.ts') || path.endsWith('.tsx')) && !path.includes('.test.');
|
|
39
|
+
}
|
|
40
|
+
function newestMtime(files, deps) {
|
|
41
|
+
let newest = -Infinity;
|
|
42
|
+
for (const f of files) {
|
|
43
|
+
const mtime = deps.mtimeMs(f);
|
|
44
|
+
if (mtime > newest)
|
|
45
|
+
newest = mtime;
|
|
46
|
+
}
|
|
47
|
+
return newest;
|
|
48
|
+
}
|
|
49
|
+
export function checkDistFreshness(rootDir, deps) {
|
|
50
|
+
const results = [];
|
|
51
|
+
for (const pkg of RUNTIME_PACKAGES) {
|
|
52
|
+
const srcDir = join(rootDir, 'packages', pkg, 'src');
|
|
53
|
+
const distDir = join(rootDir, 'packages', pkg, 'dist');
|
|
54
|
+
if (!deps.exists(srcDir))
|
|
55
|
+
continue;
|
|
56
|
+
const srcFiles = deps.listFiles(srcDir).filter(isComparableSrcFile);
|
|
57
|
+
if (srcFiles.length === 0)
|
|
58
|
+
continue;
|
|
59
|
+
const newestSrc = newestMtime(srcFiles, deps);
|
|
60
|
+
if (!deps.exists(distDir)) {
|
|
61
|
+
results.push({ pkg, stale: true, reason: `${pkg}: dist/ missing` });
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
const distFiles = deps.listFiles(distDir);
|
|
65
|
+
if (distFiles.length === 0) {
|
|
66
|
+
results.push({ pkg, stale: true, reason: `${pkg}: dist/ empty` });
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
const newestDist = newestMtime(distFiles, deps);
|
|
70
|
+
if (newestSrc > newestDist) {
|
|
71
|
+
results.push({
|
|
72
|
+
pkg,
|
|
73
|
+
stale: true,
|
|
74
|
+
reason: `${pkg}: src is ${new Date(newestSrc).toISOString()} but dist is ${new Date(newestDist).toISOString()}`,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
results.push({ pkg, stale: false, reason: `${pkg}: dist newer than src` });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return results;
|
|
82
|
+
}
|
|
83
|
+
export function formatStaleDistMessage(stale, rootDir) {
|
|
84
|
+
const lines = ['factory: compiled dist is stale — refusing to run old code'];
|
|
85
|
+
for (const s of stale) {
|
|
86
|
+
lines.push(` - ${s.reason}`);
|
|
87
|
+
}
|
|
88
|
+
lines.push(`fix: run 'npm run build' in ${rootDir}`);
|
|
89
|
+
lines.push('override: FACTORY_ALLOW_STALE=1 (runs anyway, at your own risk)');
|
|
90
|
+
return lines.join('\n');
|
|
91
|
+
}
|
|
92
|
+
const BYPASS_COMMANDS = new Set(['doctor', '--help', '-h', '--version', '-V']);
|
|
93
|
+
export function runStalenessGuard(opts) {
|
|
94
|
+
const deps = opts.deps ?? defaultStalenessDeps();
|
|
95
|
+
const entryPath = fileURLToPath(opts.entryUrl);
|
|
96
|
+
if (!entryPath.split(sep).includes('dist'))
|
|
97
|
+
return null;
|
|
98
|
+
const root = findWorkspaceRoot(dirname(entryPath), deps);
|
|
99
|
+
if (root === undefined)
|
|
100
|
+
return null;
|
|
101
|
+
const stale = checkDistFreshness(root, deps).filter((p) => p.stale);
|
|
102
|
+
if (stale.length === 0)
|
|
103
|
+
return null;
|
|
104
|
+
const message = formatStaleDistMessage(stale, root);
|
|
105
|
+
if (opts.env.FACTORY_ALLOW_STALE === '1') {
|
|
106
|
+
opts.warn(`factory: FACTORY_ALLOW_STALE=1 — running stale dist:\n${message}`);
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
if (opts.argv[2] !== undefined && BYPASS_COMMANDS.has(opts.argv[2])) {
|
|
110
|
+
opts.warn(message);
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
opts.error(message);
|
|
114
|
+
return 2;
|
|
115
|
+
}
|
|
116
|
+
export function distFreshnessProbe(entryUrl, deps = defaultStalenessDeps()) {
|
|
117
|
+
const entryPath = fileURLToPath(entryUrl);
|
|
118
|
+
if (!entryPath.split(sep).includes('dist'))
|
|
119
|
+
return undefined;
|
|
120
|
+
const root = findWorkspaceRoot(dirname(entryPath), deps);
|
|
121
|
+
if (root === undefined)
|
|
122
|
+
return undefined;
|
|
123
|
+
return () => {
|
|
124
|
+
const results = checkDistFreshness(root, deps);
|
|
125
|
+
const stale = results.filter((r) => r.stale);
|
|
126
|
+
if (stale.length === 0) {
|
|
127
|
+
return { fresh: true, detail: 'dist newer than src' };
|
|
128
|
+
}
|
|
129
|
+
return { fresh: false, detail: stale.map((s) => s.reason).join('; ') };
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=staleness.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"staleness.js","sourceRoot":"","sources":["../../src/cli/staleness.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** The flag wins over the env var. A resolved root is written back to `env` as an absolute
|
|
2
|
+
* path so every child process (lanes, CHECK) skips the git lookup and any cwd difference.
|
|
3
|
+
* Invalid values throw. */
|
|
4
|
+
export declare function applyStateRootOption(flag: string | undefined, repoRoot: string, env?: NodeJS.ProcessEnv): string | undefined;
|
|
5
|
+
//# sourceMappingURL=state-root.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state-root.d.ts","sourceRoot":"","sources":["../../src/cli/state-root.ts"],"names":[],"mappings":"AAIA;;4BAE4B;AAC5B,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,QAAQ,EAAE,MAAM,EAChB,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,GAAG,SAAS,CAIpB"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// src/cli/state-root.ts — Applies the global `--state-root` flag / FACTORY_STATE_ROOT env (#2281).
|
|
2
|
+
import { resolveStateRoot, STATE_ROOT_ENV } from '@on-par/factory-core/internal';
|
|
3
|
+
/** The flag wins over the env var. A resolved root is written back to `env` as an absolute
|
|
4
|
+
* path so every child process (lanes, CHECK) skips the git lookup and any cwd difference.
|
|
5
|
+
* Invalid values throw. */
|
|
6
|
+
export function applyStateRootOption(flag, repoRoot, env = process.env) {
|
|
7
|
+
const resolved = resolveStateRoot(flag ?? env[STATE_ROOT_ENV], { repoRoot });
|
|
8
|
+
if (resolved !== undefined)
|
|
9
|
+
env[STATE_ROOT_ENV] = resolved;
|
|
10
|
+
return resolved;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=state-root.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state-root.js","sourceRoot":"","sources":["../../src/cli/state-root.ts"],"names":[],"mappings":"AAAA,mGAAmG;AAEnG,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAEjF;;4BAE4B;AAC5B,MAAM,UAAU,oBAAoB,CAClC,IAAwB,EACxB,QAAgB,EAChB,GAAG,GAAsB,OAAO,CAAC,GAAG;IAEpC,MAAM,QAAQ,GAAG,gBAAgB,CAAC,IAAI,IAAI,GAAG,CAAC,cAAc,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC7E,IAAI,QAAQ,KAAK,SAAS;QAAE,GAAG,CAAC,cAAc,CAAC,GAAG,QAAQ,CAAC;IAC3D,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { ActiveQueueClaim } from '@on-par/factory-core';
|
|
2
|
+
import type { StatusUpdateJson } from './update-state.js';
|
|
3
|
+
/** One open provider in `factory status --json` (#1101). */
|
|
4
|
+
export interface StatusBreakerProviderJson {
|
|
5
|
+
provider: string;
|
|
6
|
+
reason: string;
|
|
7
|
+
openedAt: string;
|
|
8
|
+
remainingSec: number;
|
|
9
|
+
}
|
|
10
|
+
/** Provider breaker state (state/breaker.json). `open` is true iff any provider is still open. */
|
|
11
|
+
export interface StatusBreakerJson {
|
|
12
|
+
open: boolean;
|
|
13
|
+
providers: StatusBreakerProviderJson[];
|
|
14
|
+
}
|
|
15
|
+
/** One fresh-heartbeat local queue claim. */
|
|
16
|
+
export interface StatusActiveRowJson {
|
|
17
|
+
lane: string;
|
|
18
|
+
issue: number;
|
|
19
|
+
phase: string;
|
|
20
|
+
ageSec: number;
|
|
21
|
+
}
|
|
22
|
+
/** `factory status --json` payload (#1101). No queue (#2268) or usage (#2270) section.
|
|
23
|
+
* Additive changes only; bump schemaVersion on a breaking change. */
|
|
24
|
+
export interface StatusJson {
|
|
25
|
+
schemaVersion: 1;
|
|
26
|
+
repo: string;
|
|
27
|
+
product: string | null;
|
|
28
|
+
stop: boolean;
|
|
29
|
+
breaker: StatusBreakerJson;
|
|
30
|
+
active: StatusActiveRowJson[];
|
|
31
|
+
/** factoryd self-update state (#2129, additive); null when no readable update-state.json exists. */
|
|
32
|
+
update: StatusUpdateJson | null;
|
|
33
|
+
}
|
|
34
|
+
/** Builds the `factory status --json` payload. An unparsable `lastActivityAt` reports `ageSec: 0`, never NaN. */
|
|
35
|
+
export declare function buildStatusJson(input: {
|
|
36
|
+
repo: string;
|
|
37
|
+
product: string | null;
|
|
38
|
+
stop: boolean;
|
|
39
|
+
breakers: ReadonlyArray<{
|
|
40
|
+
provider: string;
|
|
41
|
+
reason: string;
|
|
42
|
+
openedAt: string;
|
|
43
|
+
remainingMs: number;
|
|
44
|
+
}>;
|
|
45
|
+
active: ReadonlyArray<Pick<ActiveQueueClaim, 'lane' | 'issue' | 'phase' | 'lastActivityAt'>>;
|
|
46
|
+
update: StatusUpdateJson | null;
|
|
47
|
+
now: number;
|
|
48
|
+
}): StatusJson;
|
|
49
|
+
//# sourceMappingURL=status-json.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status-json.d.ts","sourceRoot":"","sources":["../../src/cli/status-json.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D,4DAA4D;AAC5D,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,kGAAkG;AAClG,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,yBAAyB,EAAE,CAAC;CACxC;AAED,6CAA6C;AAC7C,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;sEACsE;AACtE,MAAM,WAAW,UAAU;IACzB,aAAa,EAAE,CAAC,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,iBAAiB,CAAC;IAC3B,MAAM,EAAE,mBAAmB,EAAE,CAAC;IAC9B,oGAAoG;IACpG,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAAC;CACjC;AAED,iHAAiH;AACjH,wBAAgB,eAAe,CAAC,KAAK,EAAE;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,aAAa,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACrG,MAAM,EAAE,aAAa,CAAC,IAAI,CAAC,gBAAgB,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,gBAAgB,CAAC,CAAC,CAAC;IAC7F,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAChC,GAAG,EAAE,MAAM,CAAC;CACb,GAAG,UAAU,CAoBb"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** Builds the `factory status --json` payload. An unparsable `lastActivityAt` reports `ageSec: 0`, never NaN. */
|
|
2
|
+
export function buildStatusJson(input) {
|
|
3
|
+
const providers = input.breakers.map((b) => ({
|
|
4
|
+
provider: b.provider,
|
|
5
|
+
reason: b.reason,
|
|
6
|
+
openedAt: b.openedAt,
|
|
7
|
+
remainingSec: Math.ceil(b.remainingMs / 1000),
|
|
8
|
+
}));
|
|
9
|
+
const active = input.active.map((c) => {
|
|
10
|
+
const ageSec = Math.floor((input.now - Date.parse(c.lastActivityAt)) / 1000);
|
|
11
|
+
return { lane: c.lane, issue: c.issue, phase: c.phase, ageSec: Number.isFinite(ageSec) ? Math.max(0, ageSec) : 0 };
|
|
12
|
+
});
|
|
13
|
+
return {
|
|
14
|
+
schemaVersion: 1,
|
|
15
|
+
repo: input.repo,
|
|
16
|
+
product: input.product,
|
|
17
|
+
stop: input.stop,
|
|
18
|
+
breaker: { open: providers.length > 0, providers },
|
|
19
|
+
active,
|
|
20
|
+
update: input.update,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=status-json.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status-json.js","sourceRoot":"","sources":["../../src/cli/status-json.ts"],"names":[],"mappings":"AAsCA,iHAAiH;AACjH,MAAM,UAAU,eAAe,CAAC,KAQ/B;IACC,MAAM,SAAS,GAAG,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC3C,QAAQ,EAAE,CAAC,CAAC,QAAQ;QACpB,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,QAAQ,EAAE,CAAC,CAAC,QAAQ;QACpB,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,GAAG,IAAI,CAAC;KAC9C,CAAC,CAAC,CAAC;IACJ,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACpC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;QAC7E,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACrH,CAAC,CAAC,CAAC;IACH,OAAO;QACL,aAAa,EAAE,CAAC;QAChB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,SAAS,EAAE;QAClD,MAAM;QACN,MAAM,EAAE,KAAK,CAAC,MAAM;KACrB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** `factory stop|resume --json` payload (#2276). Additive changes only; bump schemaVersion on a breaking change. */
|
|
2
|
+
export interface StopResumeJson {
|
|
3
|
+
schemaVersion: 1;
|
|
4
|
+
ok: true;
|
|
5
|
+
action: 'stop' | 'resume';
|
|
6
|
+
repo: string;
|
|
7
|
+
stopFlag: {
|
|
8
|
+
before: boolean;
|
|
9
|
+
after: boolean;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export declare function buildStopResumeJson(input: {
|
|
13
|
+
action: 'stop' | 'resume';
|
|
14
|
+
repo: string;
|
|
15
|
+
before: boolean;
|
|
16
|
+
after: boolean;
|
|
17
|
+
}): StopResumeJson;
|
|
18
|
+
//# sourceMappingURL=stop-resume-json.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stop-resume-json.d.ts","sourceRoot":"","sources":["../../src/cli/stop-resume-json.ts"],"names":[],"mappings":"AAAA,oHAAoH;AACpH,MAAM,WAAW,cAAc;IAC7B,aAAa,EAAE,CAAC,CAAC;IACjB,EAAE,EAAE,IAAI,CAAC;IACT,MAAM,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE;QAAE,MAAM,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC;CAC/C;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE;IACzC,MAAM,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;CAChB,GAAG,cAAc,CAQjB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stop-resume-json.js","sourceRoot":"","sources":["../../src/cli/stop-resume-json.ts"],"names":[],"mappings":"AASA,MAAM,UAAU,mBAAmB,CAAC,KAKnC;IACC,OAAO;QACL,aAAa,EAAE,CAAC;QAChB,EAAE,EAAE,IAAI;QACR,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,QAAQ,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE;KACvD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { DoctorCheck } from './doctor.js';
|
|
2
|
+
export interface StopFileDeps {
|
|
3
|
+
pathExists: (p: string) => boolean;
|
|
4
|
+
statMtimeMs: (p: string) => number;
|
|
5
|
+
now: () => number;
|
|
6
|
+
}
|
|
7
|
+
export declare function defaultStopFileDeps(): StopFileDeps;
|
|
8
|
+
export type StopSentinelStatus = {
|
|
9
|
+
present: false;
|
|
10
|
+
} | {
|
|
11
|
+
present: true;
|
|
12
|
+
ageMs: number;
|
|
13
|
+
writtenAt: string;
|
|
14
|
+
};
|
|
15
|
+
export declare function readStopFileStatus(paths: {
|
|
16
|
+
stop: string;
|
|
17
|
+
}, deps?: Partial<StopFileDeps>): StopSentinelStatus;
|
|
18
|
+
/** Human-readable age like "3h 12m", "45s", or "820ms". */
|
|
19
|
+
export declare function formatStopFileAge(ms: number): string;
|
|
20
|
+
/** Message logged/printed by `factory run` when it skips a pass because STOP is present. */
|
|
21
|
+
export declare function stopSentinelRunSkipMessage(status: StopSentinelStatus): string;
|
|
22
|
+
export declare function stopSentinelCheck(status: StopSentinelStatus): DoctorCheck;
|
|
23
|
+
//# sourceMappingURL=stop-sentinel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stop-sentinel.d.ts","sourceRoot":"","sources":["../../src/cli/stop-sentinel.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;IACnC,WAAW,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IACnC,GAAG,EAAE,MAAM,MAAM,CAAC;CACnB;AAED,wBAAgB,mBAAmB,IAAI,YAAY,CAMlD;AAED,MAAM,MAAM,kBAAkB,GAAG;IAAE,OAAO,EAAE,KAAK,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1G,wBAAgB,kBAAkB,CAAC,KAAK,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,IAAI,GAAE,OAAO,CAAC,YAAY,CAAM,GAAG,kBAAkB,CAShH;AAED,2DAA2D;AAC3D,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAQpD;AAED,4FAA4F;AAC5F,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,CAO7E;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,kBAAkB,GAAG,WAAW,CAezE"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// packages/cli/src/cli/stop-sentinel.ts — `.factory/STOP` presence as pure
|
|
2
|
+
// state, shared by `factory run`'s skip-and-log path and `factory doctor`'s
|
|
3
|
+
// explicit status row. STOP is never written or deleted from this module.
|
|
4
|
+
import { existsSync, statSync } from 'node:fs';
|
|
5
|
+
export function defaultStopFileDeps() {
|
|
6
|
+
return {
|
|
7
|
+
pathExists: (p) => existsSync(p),
|
|
8
|
+
statMtimeMs: (p) => statSync(p).mtimeMs,
|
|
9
|
+
now: () => Date.now(),
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export function readStopFileStatus(paths, deps = {}) {
|
|
13
|
+
const { pathExists, statMtimeMs, now } = { ...defaultStopFileDeps(), ...deps };
|
|
14
|
+
if (!pathExists(paths.stop))
|
|
15
|
+
return { present: false };
|
|
16
|
+
try {
|
|
17
|
+
const mtimeMs = statMtimeMs(paths.stop);
|
|
18
|
+
return { present: true, ageMs: Math.max(0, now() - mtimeMs), writtenAt: new Date(mtimeMs).toISOString() };
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return { present: true, ageMs: 0, writtenAt: 'unknown' };
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/** Human-readable age like "3h 12m", "45s", or "820ms". */
|
|
25
|
+
export function formatStopFileAge(ms) {
|
|
26
|
+
if (ms < 1000)
|
|
27
|
+
return `${Math.max(0, Math.round(ms))}ms`;
|
|
28
|
+
const s = Math.floor(ms / 1000);
|
|
29
|
+
if (s < 60)
|
|
30
|
+
return `${s}s`;
|
|
31
|
+
const m = Math.floor(s / 60);
|
|
32
|
+
if (m < 60)
|
|
33
|
+
return `${m}m ${s % 60}s`;
|
|
34
|
+
const h = Math.floor(m / 60);
|
|
35
|
+
return `${h}h ${m % 60}m`;
|
|
36
|
+
}
|
|
37
|
+
/** Message logged/printed by `factory run` when it skips a pass because STOP is present. */
|
|
38
|
+
export function stopSentinelRunSkipMessage(status) {
|
|
39
|
+
if (!status.present)
|
|
40
|
+
return '';
|
|
41
|
+
return (`.factory/STOP present (age ${formatStopFileAge(status.ageMs)}, written ${status.writtenAt}) — ` +
|
|
42
|
+
`factory run is skipping this pass and claiming no new work. ` +
|
|
43
|
+
`Remove .factory/STOP (or run \`factory resume\`) to continue.`);
|
|
44
|
+
}
|
|
45
|
+
export function stopSentinelCheck(status) {
|
|
46
|
+
if (!status.present) {
|
|
47
|
+
return {
|
|
48
|
+
name: 'STOP sentinel',
|
|
49
|
+
ok: true,
|
|
50
|
+
detail: '.factory/STOP not present — factory run will claim work normally',
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
name: 'STOP sentinel',
|
|
55
|
+
ok: false,
|
|
56
|
+
optional: true,
|
|
57
|
+
detail: `.factory/STOP present (age ${formatStopFileAge(status.ageMs)}, written ${status.writtenAt}) — repo is intentionally paused`,
|
|
58
|
+
fix: 'rm .factory/STOP, or run `factory resume`, to let factory run claim work again',
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=stop-sentinel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stop-sentinel.js","sourceRoot":"","sources":["../../src/cli/stop-sentinel.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { DoctorCheck } from './doctor.js';
|
|
2
|
+
export interface SweepHeartbeatPolicy {
|
|
3
|
+
heartbeatFile?: string;
|
|
4
|
+
loopIntervalSeconds: number;
|
|
5
|
+
staleThresholdMultiplier: number;
|
|
6
|
+
}
|
|
7
|
+
export interface SweepHeartbeatDeps {
|
|
8
|
+
exists: (p: string) => boolean;
|
|
9
|
+
mtimeMs: (p: string) => number;
|
|
10
|
+
now: () => number;
|
|
11
|
+
}
|
|
12
|
+
export declare function defaultSweepHeartbeatDeps(): SweepHeartbeatDeps;
|
|
13
|
+
export declare function resolveSweepHeartbeatFile(policy: SweepHeartbeatPolicy, env: NodeJS.ProcessEnv): string | undefined;
|
|
14
|
+
export type SweepHeartbeatStatus = {
|
|
15
|
+
status: 'unconfigured';
|
|
16
|
+
} | {
|
|
17
|
+
status: 'missing';
|
|
18
|
+
file: string;
|
|
19
|
+
} | {
|
|
20
|
+
status: 'fresh';
|
|
21
|
+
file: string;
|
|
22
|
+
ageSeconds: number;
|
|
23
|
+
thresholdSeconds: number;
|
|
24
|
+
} | {
|
|
25
|
+
status: 'stale';
|
|
26
|
+
file: string;
|
|
27
|
+
ageSeconds: number;
|
|
28
|
+
thresholdSeconds: number;
|
|
29
|
+
};
|
|
30
|
+
export declare function checkSweepHeartbeat(policy: SweepHeartbeatPolicy, env: NodeJS.ProcessEnv, deps: SweepHeartbeatDeps): SweepHeartbeatStatus;
|
|
31
|
+
export declare function sweepHeartbeatCheck(status: SweepHeartbeatStatus): DoctorCheck | null;
|
|
32
|
+
export declare function formatSweepHeartbeatStatusLine(status: SweepHeartbeatStatus): string;
|
|
33
|
+
//# sourceMappingURL=sweep-heartbeat.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sweep-heartbeat.d.ts","sourceRoot":"","sources":["../../src/cli/sweep-heartbeat.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,MAAM,WAAW,oBAAoB;IACnC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,wBAAwB,EAAE,MAAM,CAAC;CAClC;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;IAC/B,OAAO,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IAC/B,GAAG,EAAE,MAAM,MAAM,CAAC;CACnB;AAED,wBAAgB,yBAAyB,IAAI,kBAAkB,CAM9D;AAED,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,oBAAoB,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,MAAM,GAAG,SAAS,CAElH;AAED,MAAM,MAAM,oBAAoB,GAC5B;IAAE,MAAM,EAAE,cAAc,CAAA;CAAE,GAC1B;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,gBAAgB,EAAE,MAAM,CAAA;CAAE,GAC/E;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,gBAAgB,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpF,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,oBAAoB,EAC5B,GAAG,EAAE,MAAM,CAAC,UAAU,EACtB,IAAI,EAAE,kBAAkB,GACvB,oBAAoB,CAWtB;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,oBAAoB,GAAG,WAAW,GAAG,IAAI,CA0BpF;AAED,wBAAgB,8BAA8B,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM,CAWnF"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// packages/cli/src/cli/sweep-heartbeat.ts — detect a dead auto-merge-sweep loop from its
|
|
2
|
+
// heartbeat file's mtime, so `factory doctor`/`status` catch it instead of it rotting silently.
|
|
3
|
+
import { existsSync, statSync } from 'node:fs';
|
|
4
|
+
export function defaultSweepHeartbeatDeps() {
|
|
5
|
+
return {
|
|
6
|
+
exists: (p) => existsSync(p),
|
|
7
|
+
mtimeMs: (p) => statSync(p).mtimeMs,
|
|
8
|
+
now: () => Date.now(),
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export function resolveSweepHeartbeatFile(policy, env) {
|
|
12
|
+
return policy.heartbeatFile || env.HEARTBEAT_FILE || undefined;
|
|
13
|
+
}
|
|
14
|
+
export function checkSweepHeartbeat(policy, env, deps) {
|
|
15
|
+
const file = resolveSweepHeartbeatFile(policy, env);
|
|
16
|
+
if (!file)
|
|
17
|
+
return { status: 'unconfigured' };
|
|
18
|
+
if (!deps.exists(file))
|
|
19
|
+
return { status: 'missing', file };
|
|
20
|
+
const ageSeconds = Math.max(0, Math.round((deps.now() - deps.mtimeMs(file)) / 1000));
|
|
21
|
+
const thresholdSeconds = Math.round(policy.loopIntervalSeconds * policy.staleThresholdMultiplier);
|
|
22
|
+
return ageSeconds > thresholdSeconds
|
|
23
|
+
? { status: 'stale', file, ageSeconds, thresholdSeconds }
|
|
24
|
+
: { status: 'fresh', file, ageSeconds, thresholdSeconds };
|
|
25
|
+
}
|
|
26
|
+
export function sweepHeartbeatCheck(status) {
|
|
27
|
+
const NAME = 'auto-merge sweep heartbeat';
|
|
28
|
+
switch (status.status) {
|
|
29
|
+
case 'unconfigured':
|
|
30
|
+
return null;
|
|
31
|
+
case 'missing':
|
|
32
|
+
return {
|
|
33
|
+
name: NAME,
|
|
34
|
+
ok: false,
|
|
35
|
+
detail: `${status.file} not found — the sweep has never written a heartbeat`,
|
|
36
|
+
fix: 'confirm the sweep loop is running and HEARTBEAT_FILE / sweep.heartbeatFile point at the right path',
|
|
37
|
+
};
|
|
38
|
+
case 'stale':
|
|
39
|
+
return {
|
|
40
|
+
name: NAME,
|
|
41
|
+
ok: false,
|
|
42
|
+
detail: `${status.file} last updated ${status.ageSeconds}s ago (> ${status.thresholdSeconds}s threshold) — the sweep looks dead`,
|
|
43
|
+
fix: 'check the sweep loop / launchd job (see docs/runbooks/sweep-heartbeat.md) and restart it',
|
|
44
|
+
};
|
|
45
|
+
case 'fresh':
|
|
46
|
+
return {
|
|
47
|
+
name: NAME,
|
|
48
|
+
ok: true,
|
|
49
|
+
detail: `${status.file} updated ${status.ageSeconds}s ago (threshold ${status.thresholdSeconds}s)`,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
export function formatSweepHeartbeatStatusLine(status) {
|
|
54
|
+
switch (status.status) {
|
|
55
|
+
case 'unconfigured':
|
|
56
|
+
return 'not configured (sweep.heartbeatFile / HEARTBEAT_FILE unset)';
|
|
57
|
+
case 'missing':
|
|
58
|
+
return `MISSING — ${status.file} not found`;
|
|
59
|
+
case 'stale':
|
|
60
|
+
return `STALE — ${status.file}, last updated ${status.ageSeconds}s ago (threshold ${status.thresholdSeconds}s)`;
|
|
61
|
+
case 'fresh':
|
|
62
|
+
return `OK — ${status.file}, last updated ${status.ageSeconds}s ago (threshold ${status.thresholdSeconds}s)`;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=sweep-heartbeat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sweep-heartbeat.js","sourceRoot":"","sources":["../../src/cli/sweep-heartbeat.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { QueueGitHubClient } from '@on-par/factory-core/internal';
|
|
2
|
+
export type UnparkErrorCode = 'not-parked' | 'lane-required' | 'unpark-failed';
|
|
3
|
+
export declare class UnparkError extends Error {
|
|
4
|
+
readonly code: UnparkErrorCode;
|
|
5
|
+
constructor(code: UnparkErrorCode, message: string);
|
|
6
|
+
}
|
|
7
|
+
/** `factory unpark --json` payload (#2277). Additive changes only; bump schemaVersion on a breaking change. */
|
|
8
|
+
export interface UnparkJson {
|
|
9
|
+
schemaVersion: 1;
|
|
10
|
+
ok: true;
|
|
11
|
+
action: 'unpark';
|
|
12
|
+
issue: number;
|
|
13
|
+
/** Slug actually routed to (the factory:lane:<slug> suffix). */
|
|
14
|
+
lane: string;
|
|
15
|
+
/** The one order position assigned. */
|
|
16
|
+
order: number;
|
|
17
|
+
labelsBefore: string[];
|
|
18
|
+
labelsAfter: string[];
|
|
19
|
+
}
|
|
20
|
+
export interface UnparkInput {
|
|
21
|
+
client: QueueGitHubClient;
|
|
22
|
+
owner: string;
|
|
23
|
+
repo: string;
|
|
24
|
+
issue: number;
|
|
25
|
+
lane?: string;
|
|
26
|
+
}
|
|
27
|
+
export declare function runUnpark(input: UnparkInput): Promise<UnparkJson>;
|
|
28
|
+
//# sourceMappingURL=unpark.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unpark.d.ts","sourceRoot":"","sources":["../../src/cli/unpark.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AASvE,MAAM,MAAM,eAAe,GAAG,YAAY,GAAG,eAAe,GAAG,eAAe,CAAC;AAE/E,qBAAa,WAAY,SAAQ,KAAK;IAElC,QAAQ,CAAC,IAAI,EAAE,eAAe;IADhC,YACW,IAAI,EAAE,eAAe,EAC9B,OAAO,EAAE,MAAM,EAIhB;CACF;AAED,+GAA+G;AAC/G,MAAM,WAAW,UAAU;IACzB,aAAa,EAAE,CAAC,CAAC;IACjB,EAAE,EAAE,IAAI,CAAC;IACT,MAAM,EAAE,QAAQ,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,gEAAgE;IAChE,IAAI,EAAE,MAAM,CAAC;IACb,uCAAuC;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,iBAAiB,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAMD,wBAAsB,SAAS,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAwDvE"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { createGithubQueue, LANE_LABEL_PREFIX, laneLabel, PARKED_LABEL, QUEUE_ORDER_LABEL_PREFIX, } from '@on-par/factory-core/internal';
|
|
2
|
+
export class UnparkError extends Error {
|
|
3
|
+
code;
|
|
4
|
+
constructor(code, message) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.code = code;
|
|
7
|
+
this.name = 'UnparkError';
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
function message(err) {
|
|
11
|
+
return err instanceof Error ? err.message : String(err);
|
|
12
|
+
}
|
|
13
|
+
export async function runUnpark(input) {
|
|
14
|
+
const { client, owner, repo, issue } = input;
|
|
15
|
+
const ref = { owner, repo, issue_number: issue };
|
|
16
|
+
try {
|
|
17
|
+
const labelsBefore = await client.getIssueLabels(ref);
|
|
18
|
+
if (!labelsBefore.includes(PARKED_LABEL)) {
|
|
19
|
+
throw new UnparkError('not-parked', `#${issue} is not labelled ${PARKED_LABEL}`);
|
|
20
|
+
}
|
|
21
|
+
const existing = labelsBefore
|
|
22
|
+
.filter((l) => l.startsWith(LANE_LABEL_PREFIX))
|
|
23
|
+
.map((l) => l.slice(LANE_LABEL_PREFIX.length))
|
|
24
|
+
.filter((s) => s !== '');
|
|
25
|
+
let lane;
|
|
26
|
+
if (input.lane !== undefined && input.lane.trim() !== '') {
|
|
27
|
+
lane = laneLabel(input.lane.trim()).slice(LANE_LABEL_PREFIX.length);
|
|
28
|
+
}
|
|
29
|
+
else if (existing.length === 1) {
|
|
30
|
+
lane = existing[0];
|
|
31
|
+
}
|
|
32
|
+
else if (existing.length === 0) {
|
|
33
|
+
throw new UnparkError('lane-required', `#${issue} has no ${LANE_LABEL_PREFIX}* label; pass --lane <lane>`);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
throw new UnparkError('lane-required', `#${issue} has several lane labels (${existing.join(', ')}); pass --lane <lane>`);
|
|
37
|
+
}
|
|
38
|
+
const keepLane = laneLabel(lane);
|
|
39
|
+
for (const name of labelsBefore) {
|
|
40
|
+
if (name.startsWith(QUEUE_ORDER_LABEL_PREFIX) || (name.startsWith(LANE_LABEL_PREFIX) && name !== keepLane)) {
|
|
41
|
+
await client.removeLabel({ ...ref, name });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const [r] = await createGithubQueue({ client, owner, repo }).enqueue(lane, [issue]);
|
|
45
|
+
if (r === undefined || r.outcome !== 'queued' || r.position === undefined) {
|
|
46
|
+
throw new UnparkError('unpark-failed', r?.detail ?? `enqueue returned ${r?.outcome}`);
|
|
47
|
+
}
|
|
48
|
+
// Remove the parked label last so a failed run can simply be repeated.
|
|
49
|
+
await client.removeLabel({ ...ref, name: PARKED_LABEL });
|
|
50
|
+
const labelsAfter = await client.getIssueLabels(ref);
|
|
51
|
+
return {
|
|
52
|
+
schemaVersion: 1,
|
|
53
|
+
ok: true,
|
|
54
|
+
action: 'unpark',
|
|
55
|
+
issue,
|
|
56
|
+
lane,
|
|
57
|
+
order: r.position,
|
|
58
|
+
labelsBefore: [...labelsBefore],
|
|
59
|
+
labelsAfter,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
if (err instanceof UnparkError)
|
|
64
|
+
throw err;
|
|
65
|
+
throw new UnparkError('unpark-failed', message(err));
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=unpark.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unpark.js","sourceRoot":"","sources":["../../src/cli/unpark.ts"],"names":[],"mappings":"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"}
|