@wildorder/nightshift 0.5.0 → 0.6.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/dist/ci-init.d.ts +51 -0
- package/dist/ci-init.d.ts.map +1 -0
- package/dist/ci-init.js +274 -0
- package/dist/ci-init.js.map +1 -0
- package/dist/cli.js +99 -11
- package/dist/cli.js.map +1 -1
- package/dist/exit-codes.d.ts +44 -0
- package/dist/exit-codes.d.ts.map +1 -0
- package/dist/exit-codes.js +49 -0
- package/dist/exit-codes.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/program-branch.d.ts +65 -0
- package/dist/program-branch.d.ts.map +1 -0
- package/dist/program-branch.js +123 -0
- package/dist/program-branch.js.map +1 -0
- package/dist/publish.d.ts +105 -0
- package/dist/publish.d.ts.map +1 -0
- package/dist/publish.js +549 -0
- package/dist/publish.js.map +1 -0
- package/dist/report-path.d.ts +7 -0
- package/dist/report-path.d.ts.map +1 -0
- package/dist/report-path.js +10 -0
- package/dist/report-path.js.map +1 -0
- package/dist/run-program.d.ts +4 -0
- package/dist/run-program.d.ts.map +1 -1
- package/dist/run-program.js +49 -5
- package/dist/run-program.js.map +1 -1
- package/dist/run-publish.d.ts +41 -0
- package/dist/run-publish.d.ts.map +1 -0
- package/dist/run-publish.js +33 -0
- package/dist/run-publish.js.map +1 -0
- package/package.json +4 -3
- package/skills/plan-program/SKILL.md +14 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The process exit codes a `nightshift run` terminates with — the one place
|
|
3
|
+
* they are defined. A CI author and the generated GitHub Actions workflow
|
|
4
|
+
* (WS-05) both read these; there is exactly one source.
|
|
5
|
+
*
|
|
6
|
+
* 0 COMPLETE every workstream built; the handover is a clean PR.
|
|
7
|
+
* 2 PARTIAL the run terminated with a reviewable handover, but at
|
|
8
|
+
* least one workstream failed or was parked. A red job is
|
|
9
|
+
* the correct signal — the run report is worth reading.
|
|
10
|
+
* 3 COULD_NOT_START the run never began: a dependency cycle, a missing or
|
|
11
|
+
* invalid manifest, an unconfigured implementer, or a
|
|
12
|
+
* branch precondition refused before any agent spawned.
|
|
13
|
+
* There is no run report, because there was no run.
|
|
14
|
+
*
|
|
15
|
+
* 1 is deliberately NOT one of these three. It stays the generic "unexpected
|
|
16
|
+
* error" code that Node (uncaught throw) and Commander (usage error) already
|
|
17
|
+
* emit, so a tool crash or a mistyped command is never read as a run outcome.
|
|
18
|
+
*/
|
|
19
|
+
export const EXIT_CODES = {
|
|
20
|
+
COMPLETE: 0,
|
|
21
|
+
GENERIC: 1,
|
|
22
|
+
PARTIAL: 2,
|
|
23
|
+
COULD_NOT_START: 3,
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Thrown for every condition that stops a run before it starts. The CLI maps
|
|
27
|
+
* it to EXIT_CODES.COULD_NOT_START; anything else thrown out of a run is a
|
|
28
|
+
* genuine, unclassified error and stays EXIT_CODES.GENERIC. The message is the
|
|
29
|
+
* actionable guidance the operator reads — keep it a single readable sentence,
|
|
30
|
+
* exactly as the guards already write it.
|
|
31
|
+
*/
|
|
32
|
+
export class CouldNotStartError extends Error {
|
|
33
|
+
exitCode = EXIT_CODES.COULD_NOT_START;
|
|
34
|
+
constructor(message, options) {
|
|
35
|
+
super(message, options);
|
|
36
|
+
this.name = "CouldNotStartError";
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/** Complete → 0; partial → 2. The only mapping a returned run outcome needs. */
|
|
40
|
+
export function exitCodeForResult(result) {
|
|
41
|
+
return result.complete ? EXIT_CODES.COMPLETE : EXIT_CODES.PARTIAL;
|
|
42
|
+
}
|
|
43
|
+
/** A could-not-start throw → 3; every other throw → the generic 1. */
|
|
44
|
+
export function exitCodeForError(error) {
|
|
45
|
+
return error instanceof CouldNotStartError
|
|
46
|
+
? EXIT_CODES.COULD_NOT_START
|
|
47
|
+
: EXIT_CODES.GENERIC;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=exit-codes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exit-codes.js","sourceRoot":"","sources":["../src/exit-codes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,QAAQ,EAAE,CAAC;IACX,OAAO,EAAE,CAAC;IACV,OAAO,EAAE,CAAC;IACV,eAAe,EAAE,CAAC;CACV,CAAC;AAEX;;;;;;GAMG;AACH,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAClC,QAAQ,GAAG,UAAU,CAAC,eAAe,CAAC;IAC/C,YAAY,OAAe,EAAE,OAA6B;QACxD,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF;AAED,gFAAgF;AAChF,MAAM,UAAU,iBAAiB,CAAC,MAA6B;IAC7D,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC;AACpE,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,OAAO,KAAK,YAAY,kBAAkB;QACxC,CAAC,CAAC,UAAU,CAAC,eAAe;QAC5B,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC;AACzB,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -13,10 +13,15 @@ export * from "./decision-ledger.js";
|
|
|
13
13
|
export * from "./manifest.js";
|
|
14
14
|
export * from "./author.js";
|
|
15
15
|
export * from "./run-program.js";
|
|
16
|
+
export * from "./publish.js";
|
|
17
|
+
export * from "./run-publish.js";
|
|
18
|
+
export * from "./report-path.js";
|
|
16
19
|
export * from "./decide.js";
|
|
17
20
|
export * from "./init-project.js";
|
|
18
21
|
export * from "./install-skills.js";
|
|
19
22
|
export * from "./install-prefs.js";
|
|
20
23
|
export * from "./install-wizard.js";
|
|
21
24
|
export * from "./package-assets.js";
|
|
25
|
+
export * from "./exit-codes.js";
|
|
26
|
+
export * from "./ci-init.js";
|
|
22
27
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -13,10 +13,15 @@ export * from "./decision-ledger.js";
|
|
|
13
13
|
export * from "./manifest.js";
|
|
14
14
|
export * from "./author.js";
|
|
15
15
|
export * from "./run-program.js";
|
|
16
|
+
export * from "./publish.js";
|
|
17
|
+
export * from "./run-publish.js";
|
|
18
|
+
export * from "./report-path.js";
|
|
16
19
|
export * from "./decide.js";
|
|
17
20
|
export * from "./init-project.js";
|
|
18
21
|
export * from "./install-skills.js";
|
|
19
22
|
export * from "./install-prefs.js";
|
|
20
23
|
export * from "./install-wizard.js";
|
|
21
24
|
export * from "./package-assets.js";
|
|
25
|
+
export * from "./exit-codes.js";
|
|
26
|
+
export * from "./ci-init.js";
|
|
22
27
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The fixed prefix for every program branch. Not a config key — the charter
|
|
3
|
+
* keeps tuning knobs off the config surface, and a second source of truth
|
|
4
|
+
* next to this function is exactly what this module exists to prevent.
|
|
5
|
+
*/
|
|
6
|
+
export declare const PROGRAM_BRANCH_PREFIX = "program/";
|
|
7
|
+
/**
|
|
8
|
+
* The one place a program ID becomes a branch name. The runner's
|
|
9
|
+
* preconditions and the branch command both call this; nothing else derives
|
|
10
|
+
* a branch name anywhere in the codebase.
|
|
11
|
+
*/
|
|
12
|
+
export declare function programBranchName(programId: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* Git operations the branch command and the default-branch heuristic need,
|
|
15
|
+
* injectable so tests can force a specific state. The default implementation
|
|
16
|
+
* shells out to real git; tests otherwise drive real temporary repositories.
|
|
17
|
+
*/
|
|
18
|
+
export interface ProgramBranchGit {
|
|
19
|
+
isRepository(cwd: string): Promise<boolean>;
|
|
20
|
+
/** undefined when HEAD is detached. */
|
|
21
|
+
currentBranch(cwd: string): Promise<string | undefined>;
|
|
22
|
+
localBranchExists(cwd: string, branch: string): Promise<boolean>;
|
|
23
|
+
/** `origin/HEAD`'s target, with the leading `origin/` stripped; undefined when unset. */
|
|
24
|
+
originHeadBranch(cwd: string): Promise<string | undefined>;
|
|
25
|
+
/** `git config init.defaultBranch`; undefined when unset. */
|
|
26
|
+
configDefaultBranch(cwd: string): Promise<string | undefined>;
|
|
27
|
+
/** Switches to an existing local branch; never discards uncommitted work. */
|
|
28
|
+
switchTo(cwd: string, branch: string): Promise<void>;
|
|
29
|
+
/** Creates a branch from HEAD and switches to it; never discards uncommitted work. */
|
|
30
|
+
createAndSwitch(cwd: string, branch: string): Promise<void>;
|
|
31
|
+
}
|
|
32
|
+
export declare const defaultProgramBranchGit: ProgramBranchGit;
|
|
33
|
+
export interface CreateOrSwitchProgramBranchOptions {
|
|
34
|
+
cwd?: string;
|
|
35
|
+
git?: ProgramBranchGit;
|
|
36
|
+
}
|
|
37
|
+
export interface CreateOrSwitchProgramBranchResult {
|
|
38
|
+
action: "created" | "switched";
|
|
39
|
+
branch: string;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Creates a program's branch and switches to it, or switches to it when a
|
|
43
|
+
* prior run already made it, and reports which. Never discards uncommitted
|
|
44
|
+
* work: creating carries the working tree onto the new branch, and switching
|
|
45
|
+
* to an existing branch with conflicting local changes surfaces git's own
|
|
46
|
+
* refusal rather than overriding it.
|
|
47
|
+
*/
|
|
48
|
+
export declare function createOrSwitchProgramBranch(programId: string, options?: CreateOrSwitchProgramBranchOptions): Promise<CreateOrSwitchProgramBranchResult>;
|
|
49
|
+
/**
|
|
50
|
+
* Resolves the repository's default branch name, in order: `origin/HEAD`,
|
|
51
|
+
* then the first of `main`/`master` that exists locally, then
|
|
52
|
+
* `init.defaultBranch`, then `"main"`.
|
|
53
|
+
*
|
|
54
|
+
* This is a heuristic, not a guarantee. It is authoritative when
|
|
55
|
+
* `origin/HEAD` is set and correct for the common `main`/`master` local
|
|
56
|
+
* repositories, but it cannot identify a custom default (say `trunk`) with
|
|
57
|
+
* neither `origin/HEAD` nor a matching `init.defaultBranch` — it will return
|
|
58
|
+
* `main` in that case. This does not create a safety hole: the run
|
|
59
|
+
* preconditions in `run-program.ts` never rely on this alone. If this
|
|
60
|
+
* function misnames the default, the wrong-branch precondition still refuses
|
|
61
|
+
* a run on any branch that is not the one derived from the program ID; only
|
|
62
|
+
* the specificity of the refusal message degrades.
|
|
63
|
+
*/
|
|
64
|
+
export declare function detectDefaultBranch(cwd: string, git?: ProgramBranchGit): Promise<string>;
|
|
65
|
+
//# sourceMappingURL=program-branch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"program-branch.d.ts","sourceRoot":"","sources":["../src/program-branch.ts"],"names":[],"mappings":"AAKA;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,aAAa,CAAC;AAEhD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5C,uCAAuC;IACvC,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACxD,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACjE,yFAAyF;IACzF,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC3D,6DAA6D;IAC7D,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC9D,6EAA6E;IAC7E,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,sFAAsF;IACtF,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7D;AAED,eAAO,MAAM,uBAAuB,EAAE,gBAiErC,CAAC;AAEF,MAAM,WAAW,kCAAkC;IACjD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,gBAAgB,CAAC;CACxB;AAED,MAAM,WAAW,iCAAiC;IAChD,MAAM,EAAE,SAAS,GAAG,UAAU,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;GAMG;AACH,wBAAsB,2BAA2B,CAC/C,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,kCAAkC,GAC3C,OAAO,CAAC,iCAAiC,CAAC,CAuB5C;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,MAAM,EACX,GAAG,GAAE,gBAA0C,GAC9C,OAAO,CAAC,MAAM,CAAC,CASjB"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { promisify } from "node:util";
|
|
3
|
+
const execFileAsync = promisify(execFile);
|
|
4
|
+
/**
|
|
5
|
+
* The fixed prefix for every program branch. Not a config key — the charter
|
|
6
|
+
* keeps tuning knobs off the config surface, and a second source of truth
|
|
7
|
+
* next to this function is exactly what this module exists to prevent.
|
|
8
|
+
*/
|
|
9
|
+
export const PROGRAM_BRANCH_PREFIX = "program/";
|
|
10
|
+
/**
|
|
11
|
+
* The one place a program ID becomes a branch name. The runner's
|
|
12
|
+
* preconditions and the branch command both call this; nothing else derives
|
|
13
|
+
* a branch name anywhere in the codebase.
|
|
14
|
+
*/
|
|
15
|
+
export function programBranchName(programId) {
|
|
16
|
+
return `${PROGRAM_BRANCH_PREFIX}${programId}`;
|
|
17
|
+
}
|
|
18
|
+
export const defaultProgramBranchGit = {
|
|
19
|
+
async isRepository(cwd) {
|
|
20
|
+
try {
|
|
21
|
+
await execFileAsync("git", ["rev-parse", "--is-inside-work-tree"], { cwd });
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
async currentBranch(cwd) {
|
|
29
|
+
try {
|
|
30
|
+
const { stdout } = await execFileAsync("git", ["symbolic-ref", "--quiet", "--short", "HEAD"], { cwd });
|
|
31
|
+
return stdout.trim();
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
async localBranchExists(cwd, branch) {
|
|
38
|
+
try {
|
|
39
|
+
await execFileAsync("git", ["rev-parse", "--verify", "--quiet", `refs/heads/${branch}`], { cwd });
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
async originHeadBranch(cwd) {
|
|
47
|
+
try {
|
|
48
|
+
const { stdout } = await execFileAsync("git", ["symbolic-ref", "--quiet", "--short", "refs/remotes/origin/HEAD"], { cwd });
|
|
49
|
+
const ref = stdout.trim();
|
|
50
|
+
return ref.startsWith("origin/") ? ref.slice("origin/".length) : ref;
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
async configDefaultBranch(cwd) {
|
|
57
|
+
try {
|
|
58
|
+
const { stdout } = await execFileAsync("git", ["config", "--get", "init.defaultBranch"], { cwd });
|
|
59
|
+
const value = stdout.trim();
|
|
60
|
+
return value === "" ? undefined : value;
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
async switchTo(cwd, branch) {
|
|
67
|
+
await execFileAsync("git", ["switch", branch], { cwd });
|
|
68
|
+
},
|
|
69
|
+
async createAndSwitch(cwd, branch) {
|
|
70
|
+
await execFileAsync("git", ["switch", "-c", branch], { cwd });
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* Creates a program's branch and switches to it, or switches to it when a
|
|
75
|
+
* prior run already made it, and reports which. Never discards uncommitted
|
|
76
|
+
* work: creating carries the working tree onto the new branch, and switching
|
|
77
|
+
* to an existing branch with conflicting local changes surfaces git's own
|
|
78
|
+
* refusal rather than overriding it.
|
|
79
|
+
*/
|
|
80
|
+
export async function createOrSwitchProgramBranch(programId, options) {
|
|
81
|
+
const cwd = options?.cwd ?? process.cwd();
|
|
82
|
+
const git = options?.git ?? defaultProgramBranchGit;
|
|
83
|
+
const branch = programBranchName(programId);
|
|
84
|
+
if (!(await git.isRepository(cwd))) {
|
|
85
|
+
throw new Error(`${cwd} is not a git repository; run \`git init\` or plan from inside your repository.`);
|
|
86
|
+
}
|
|
87
|
+
const current = await git.currentBranch(cwd);
|
|
88
|
+
if (current === undefined) {
|
|
89
|
+
throw new Error("HEAD is detached; check out your default branch, then re-run.");
|
|
90
|
+
}
|
|
91
|
+
if (await git.localBranchExists(cwd, branch)) {
|
|
92
|
+
await git.switchTo(cwd, branch);
|
|
93
|
+
return { action: "switched", branch };
|
|
94
|
+
}
|
|
95
|
+
await git.createAndSwitch(cwd, branch);
|
|
96
|
+
return { action: "created", branch };
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Resolves the repository's default branch name, in order: `origin/HEAD`,
|
|
100
|
+
* then the first of `main`/`master` that exists locally, then
|
|
101
|
+
* `init.defaultBranch`, then `"main"`.
|
|
102
|
+
*
|
|
103
|
+
* This is a heuristic, not a guarantee. It is authoritative when
|
|
104
|
+
* `origin/HEAD` is set and correct for the common `main`/`master` local
|
|
105
|
+
* repositories, but it cannot identify a custom default (say `trunk`) with
|
|
106
|
+
* neither `origin/HEAD` nor a matching `init.defaultBranch` — it will return
|
|
107
|
+
* `main` in that case. This does not create a safety hole: the run
|
|
108
|
+
* preconditions in `run-program.ts` never rely on this alone. If this
|
|
109
|
+
* function misnames the default, the wrong-branch precondition still refuses
|
|
110
|
+
* a run on any branch that is not the one derived from the program ID; only
|
|
111
|
+
* the specificity of the refusal message degrades.
|
|
112
|
+
*/
|
|
113
|
+
export async function detectDefaultBranch(cwd, git = defaultProgramBranchGit) {
|
|
114
|
+
const originHead = await git.originHeadBranch(cwd);
|
|
115
|
+
if (originHead !== undefined)
|
|
116
|
+
return originHead;
|
|
117
|
+
for (const candidate of ["main", "master"]) {
|
|
118
|
+
if (await git.localBranchExists(cwd, candidate))
|
|
119
|
+
return candidate;
|
|
120
|
+
}
|
|
121
|
+
return (await git.configDefaultBranch(cwd)) ?? "main";
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=program-branch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"program-branch.js","sourceRoot":"","sources":["../src/program-branch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The handover from a finished run to a reviewable pull request: pushes the
|
|
3
|
+
* program branch, opens or updates exactly one draft PR through `gh`,
|
|
4
|
+
* renders the run report as its body (continuing oversized reports into
|
|
5
|
+
* comments), and upserts one comment per escalated decision. Idempotent —
|
|
6
|
+
* re-publishing edits the existing PR and its comments rather than
|
|
7
|
+
* duplicating them.
|
|
8
|
+
*
|
|
9
|
+
* `publish` is deliberately separate from `runProgram`: the runner owns
|
|
10
|
+
* commits and knows nothing about forges, and this command owns the forge
|
|
11
|
+
* and knows nothing about building. Authentication is entirely `gh`'s job —
|
|
12
|
+
* nightshift never reads, stores, or passes a token.
|
|
13
|
+
*/
|
|
14
|
+
export declare const GITHUB_PR_BODY_LIMIT = 65536;
|
|
15
|
+
export interface GhComment {
|
|
16
|
+
/** The forge's own comment id, opaque; used to edit or delete it. */
|
|
17
|
+
id: string;
|
|
18
|
+
body: string;
|
|
19
|
+
}
|
|
20
|
+
export interface GhPullRequest {
|
|
21
|
+
number: number;
|
|
22
|
+
url: string;
|
|
23
|
+
/** open | closed | merged — so publish can tell a live handover from history. */
|
|
24
|
+
state: "open" | "closed" | "merged";
|
|
25
|
+
/** Whether the PR is still a draft; asserted by the SC-06 test. */
|
|
26
|
+
isDraft: boolean;
|
|
27
|
+
}
|
|
28
|
+
export interface GhClient {
|
|
29
|
+
/**
|
|
30
|
+
* Preflight: succeeds when `gh` is installed and authenticated, and throws
|
|
31
|
+
* the actionable "not installed" / "not authenticated" errors otherwise.
|
|
32
|
+
* Called once at the very start of publish, before any push or PR work.
|
|
33
|
+
*/
|
|
34
|
+
checkAuth(cwd: string): Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* The open PR whose head is this branch, or undefined. Returns only an
|
|
37
|
+
* OPEN PR — a closed or merged PR for the branch is history, not the live
|
|
38
|
+
* handover. Never returns two: GitHub permits at most one open PR per
|
|
39
|
+
* head->base pair.
|
|
40
|
+
*/
|
|
41
|
+
findOpenPullRequest(cwd: string, headBranch: string): Promise<GhPullRequest | undefined>;
|
|
42
|
+
/** Opens a draft PR; returns its number, url, state, and draft flag. */
|
|
43
|
+
createDraftPullRequest(cwd: string, input: {
|
|
44
|
+
headBranch: string;
|
|
45
|
+
baseBranch: string;
|
|
46
|
+
title: string;
|
|
47
|
+
body: string;
|
|
48
|
+
}): Promise<GhPullRequest>;
|
|
49
|
+
/** Rewrites the body of an existing PR; does not change its draft/ready state. */
|
|
50
|
+
updatePullRequestBody(cwd: string, number: number, body: string): Promise<void>;
|
|
51
|
+
listComments(cwd: string, number: number): Promise<GhComment[]>;
|
|
52
|
+
createComment(cwd: string, number: number, body: string): Promise<void>;
|
|
53
|
+
updateComment(cwd: string, commentId: string, body: string): Promise<void>;
|
|
54
|
+
/** Removes a now-stale nightshift-authored comment. */
|
|
55
|
+
deleteComment(cwd: string, commentId: string): Promise<void>;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Git operations `publish` needs beyond `program-branch.ts`'s derivation —
|
|
59
|
+
* kept local to this module, mirroring `ProgramBranchGit`, so the runner's
|
|
60
|
+
* `GitOps` stays about building, not remotes.
|
|
61
|
+
*/
|
|
62
|
+
export interface PublishGit {
|
|
63
|
+
/** The branch HEAD points at, for the provenance check; `git rev-parse --abbrev-ref HEAD`. */
|
|
64
|
+
currentBranch(cwd: string): Promise<string>;
|
|
65
|
+
/** Is the branch ahead of base? `git rev-list --count <base>..<branch>`. */
|
|
66
|
+
commitsAhead(cwd: string, base: string, branch: string): Promise<number>;
|
|
67
|
+
push(cwd: string, remote: string, branch: string): Promise<void>;
|
|
68
|
+
}
|
|
69
|
+
export declare const defaultPublishGit: PublishGit;
|
|
70
|
+
export declare const defaultGhClient: GhClient;
|
|
71
|
+
export interface PublishOptions {
|
|
72
|
+
cwd: string;
|
|
73
|
+
programId: string;
|
|
74
|
+
/** Injected GitHub boundary; default spawns `gh`. */
|
|
75
|
+
gh?: GhClient;
|
|
76
|
+
/** Injected git boundary; default execFile-backed. */
|
|
77
|
+
git?: PublishGit;
|
|
78
|
+
log?: (line: string) => void;
|
|
79
|
+
}
|
|
80
|
+
export interface PublishResult {
|
|
81
|
+
prNumber: number;
|
|
82
|
+
prUrl: string;
|
|
83
|
+
action: "created" | "updated";
|
|
84
|
+
/** Escalation comments upserted this publish. */
|
|
85
|
+
escalationComments: number;
|
|
86
|
+
/** Report-continuation comments upserted this publish (0 when the report fits). */
|
|
87
|
+
continuationComments: number;
|
|
88
|
+
}
|
|
89
|
+
interface ReportChunk {
|
|
90
|
+
/** A verbatim, contiguous slice of the report — never rewritten or decorated. */
|
|
91
|
+
payload: string;
|
|
92
|
+
/** True when this chunk's payload ends mid-section (the degenerate fallback). */
|
|
93
|
+
cutMidSection: boolean;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Splits the run report into chunks whose payloads are verbatim, contiguous
|
|
97
|
+
* slices of the report — concatenating every payload in order reproduces the
|
|
98
|
+
* report byte-for-byte. A report that fits under the limit is a single
|
|
99
|
+
* chunk; an oversized report is packed on section boundaries, falling back
|
|
100
|
+
* to paragraph/character boundaries only for a section too large on its own.
|
|
101
|
+
*/
|
|
102
|
+
export declare function splitReportIntoChunks(report: string): ReportChunk[];
|
|
103
|
+
export declare function publish(options: PublishOptions): Promise<PublishResult>;
|
|
104
|
+
export {};
|
|
105
|
+
//# sourceMappingURL=publish.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../src/publish.ts"],"names":[],"mappings":"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"}
|