@on-par/factory-cli 0.0.0-stage → 0.9.0
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 +23 -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/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 +113 -0
- package/dist/cli/daemon.d.ts.map +1 -0
- package/dist/cli/daemon.js +282 -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 +50 -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 +656 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +4801 -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/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/status-json.d.ts +45 -0
- package/dist/cli/status-json.d.ts.map +1 -0
- package/dist/cli/status-json.js +22 -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/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 +48 -4
|
@@ -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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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { SubscriptionUsage } from '@on-par/factory-core';
|
|
2
|
+
/** Hours in the trailing usage window `factory usage` reports on. */
|
|
3
|
+
export declare const USAGE_WINDOW_HOURS: number;
|
|
4
|
+
export type UsageJsonSource = 'subscription' | 'heuristic' | 'unavailable';
|
|
5
|
+
/** `factory usage --json` payload (#2270). Absent readings are null, never 0 (ADR-0099).
|
|
6
|
+
* Additive changes only; bump schemaVersion on a breaking change. */
|
|
7
|
+
export interface UsageJson {
|
|
8
|
+
schemaVersion: 1;
|
|
9
|
+
source: UsageJsonSource;
|
|
10
|
+
/** Percent of the window used, 0-100 scale. */
|
|
11
|
+
utilizationPct: number | null;
|
|
12
|
+
resetsAt: string | null;
|
|
13
|
+
windowHours: number;
|
|
14
|
+
/** Trailing-window list-price estimate in USD. */
|
|
15
|
+
estimateUsd: number | null;
|
|
16
|
+
}
|
|
17
|
+
/** Builds the `factory usage --json` payload: the real subscription reading when present, else the
|
|
18
|
+
* list-price heuristic against `cap`, else an explicit `unavailable` record. Numbers are not rounded. */
|
|
19
|
+
export declare function buildUsageJson(subscription: SubscriptionUsage | null, estimateUsd: number | null, cap: number): UsageJson;
|
|
20
|
+
//# sourceMappingURL=usage-json.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage-json.d.ts","sourceRoot":"","sources":["../../src/cli/usage-json.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAG9D,qEAAqE;AACrE,eAAO,MAAM,kBAAkB,QAAiC,CAAC;AAEjE,MAAM,MAAM,eAAe,GAAG,cAAc,GAAG,WAAW,GAAG,aAAa,CAAC;AAE3E;sEACsE;AACtE,MAAM,WAAW,SAAS;IACxB,aAAa,EAAE,CAAC,CAAC;IACjB,MAAM,EAAE,eAAe,CAAC;IACxB,+CAA+C;IAC/C,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,kDAAkD;IAClD,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED;0GAC0G;AAC1G,wBAAgB,cAAc,CAC5B,YAAY,EAAE,iBAAiB,GAAG,IAAI,EACtC,WAAW,EAAE,MAAM,GAAG,IAAI,EAC1B,GAAG,EAAE,MAAM,GACV,SAAS,CA6BX"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { TRAILING_WINDOW_MS } from '@on-par/factory-core/internal';
|
|
2
|
+
/** Hours in the trailing usage window `factory usage` reports on. */
|
|
3
|
+
export const USAGE_WINDOW_HOURS = TRAILING_WINDOW_MS / 3_600_000;
|
|
4
|
+
/** Builds the `factory usage --json` payload: the real subscription reading when present, else the
|
|
5
|
+
* list-price heuristic against `cap`, else an explicit `unavailable` record. Numbers are not rounded. */
|
|
6
|
+
export function buildUsageJson(subscription, estimateUsd, cap) {
|
|
7
|
+
if (subscription !== null) {
|
|
8
|
+
return {
|
|
9
|
+
schemaVersion: 1,
|
|
10
|
+
source: 'subscription',
|
|
11
|
+
utilizationPct: subscription.fiveHourUtilization,
|
|
12
|
+
resetsAt: subscription.fiveHourResetsAt,
|
|
13
|
+
windowHours: USAGE_WINDOW_HOURS,
|
|
14
|
+
estimateUsd,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
if (estimateUsd !== null) {
|
|
18
|
+
return {
|
|
19
|
+
schemaVersion: 1,
|
|
20
|
+
source: 'heuristic',
|
|
21
|
+
utilizationPct: (estimateUsd / cap) * 100,
|
|
22
|
+
resetsAt: null,
|
|
23
|
+
windowHours: USAGE_WINDOW_HOURS,
|
|
24
|
+
estimateUsd,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
schemaVersion: 1,
|
|
29
|
+
source: 'unavailable',
|
|
30
|
+
utilizationPct: null,
|
|
31
|
+
resetsAt: null,
|
|
32
|
+
windowHours: USAGE_WINDOW_HOURS,
|
|
33
|
+
estimateUsd: null,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=usage-json.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage-json.js","sourceRoot":"","sources":["../../src/cli/usage-json.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAEnE,qEAAqE;AACrE,MAAM,CAAC,MAAM,kBAAkB,GAAG,kBAAkB,GAAG,SAAS,CAAC;AAiBjE;0GAC0G;AAC1G,MAAM,UAAU,cAAc,CAC5B,YAAsC,EACtC,WAA0B,EAC1B,GAAW;IAEX,IAAI,YAAY,KAAK,IAAI,EAAE,CAAC;QAC1B,OAAO;YACL,aAAa,EAAE,CAAC;YAChB,MAAM,EAAE,cAAc;YACtB,cAAc,EAAE,YAAY,CAAC,mBAAmB;YAChD,QAAQ,EAAE,YAAY,CAAC,gBAAgB;YACvC,WAAW,EAAE,kBAAkB;YAC/B,WAAW;SACZ,CAAC;IACJ,CAAC;IACD,IAAI,WAAW,KAAK,IAAI,EAAE,CAAC;QACzB,OAAO;YACL,aAAa,EAAE,CAAC;YAChB,MAAM,EAAE,WAAW;YACnB,cAAc,EAAE,CAAC,WAAW,GAAG,GAAG,CAAC,GAAG,GAAG;YACzC,QAAQ,EAAE,IAAI;YACd,WAAW,EAAE,kBAAkB;YAC/B,WAAW;SACZ,CAAC;IACJ,CAAC;IACD,OAAO;QACL,aAAa,EAAE,CAAC;QAChB,MAAM,EAAE,aAAa;QACrB,cAAc,EAAE,IAAI;QACpB,QAAQ,EAAE,IAAI;QACd,WAAW,EAAE,kBAAkB;QAC/B,WAAW,EAAE,IAAI;KAClB,CAAC;AACJ,CAAC"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,4CAA4C;AAE5C,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,KAAK,QAAQ,CAAC,IAAI,CAAC,CAAC"}
|
package/dist/entry.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entry.d.ts","sourceRoot":"","sources":["../src/entry.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,OAAO;IACtB,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAKD,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,GAAE,OAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAOhG"}
|
package/dist/entry.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// packages/cli/src/entry.ts — bin-entry runner: awaits main and exits 1 on rejection (#2031).
|
|
2
|
+
// References, not wrappers: Node's console methods are bound and process.exit ignores `this`.
|
|
3
|
+
const defaultIo = { error: console.error, exit: process.exit };
|
|
4
|
+
export async function runEntry(main, io = defaultIo) {
|
|
5
|
+
try {
|
|
6
|
+
await main();
|
|
7
|
+
}
|
|
8
|
+
catch (err) {
|
|
9
|
+
io.error(err.message);
|
|
10
|
+
io.exit(1);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=entry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entry.js","sourceRoot":"","sources":["../src/entry.ts"],"names":[],"mappings":"AAAA,8FAA8F;AAO9F,8FAA8F;AAC9F,MAAM,SAAS,GAAY,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC;AAExE,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,IAAyB,EAAE,EAAE,GAAY,SAAS;IAC/E,IAAI,CAAC;QACH,MAAM,IAAI,EAAE,CAAC;IACf,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,EAAE,CAAC,KAAK,CAAE,GAAa,CAAC,OAAO,CAAC,CAAC;QACjC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACb,CAAC;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,50 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@on-par/factory-cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.9.0",
|
|
4
|
+
"description": "CLI for the Software Factory — ships verified GitHub issues via boss-worker-checker orchestration.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/cli.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"factory": "dist/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"!dist/.tsbuildinfo"
|
|
13
|
+
],
|
|
14
|
+
"publishConfig": {
|
|
15
|
+
"access": "public"
|
|
16
|
+
},
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/on-par/software-factory.git",
|
|
20
|
+
"directory": "packages/cli"
|
|
21
|
+
},
|
|
22
|
+
"homepage": "https://github.com/on-par/software-factory#readme",
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/on-par/software-factory/issues"
|
|
25
|
+
},
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=24.0.0"
|
|
28
|
+
},
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "tsc -p tsconfig.build.json",
|
|
31
|
+
"dev": "tsx src/cli.ts",
|
|
32
|
+
"start": "node dist/cli.js",
|
|
33
|
+
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
34
|
+
"test": "vitest run",
|
|
35
|
+
"prepublishOnly": "npm run build",
|
|
36
|
+
"prepack": "node ../../scripts/pack-hygiene-cli.ts prepack"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@octokit/plugin-retry": "^8.1.1",
|
|
40
|
+
"@octokit/plugin-throttling": "^11.0.5",
|
|
41
|
+
"@octokit/rest": "^22.0.0",
|
|
42
|
+
"@on-par/factory-core": "0.9.0",
|
|
43
|
+
"@on-par/factory-tui": "0.9.0",
|
|
44
|
+
"commander": "^15.0.0"
|
|
45
|
+
},
|
|
46
|
+
"license": "MIT",
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@types/node": "^26.6.4"
|
|
49
|
+
}
|
|
50
|
+
}
|