agentplane 0.3.22 → 0.3.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/assets/policy/incidents.md +1 -0
  2. package/dist/.build-manifest.json +83 -28
  3. package/dist/cli/run-cli/commands/init/orchestrate-v2.d.ts.map +1 -1
  4. package/dist/cli/run-cli/commands/init/orchestrate-v2.js +10 -2
  5. package/dist/cli/run-cli/commands/init/orchestrate.d.ts.map +1 -1
  6. package/dist/cli/run-cli/commands/init/orchestrate.js +10 -2
  7. package/dist/cli/run-cli/commands/init/recipes.d.ts.map +1 -1
  8. package/dist/cli/run-cli/commands/init/recipes.js +3 -1
  9. package/dist/cli.js +337 -337
  10. package/dist/commands/guard/impl/commit-refresh.d.ts +25 -0
  11. package/dist/commands/guard/impl/commit-refresh.d.ts.map +1 -0
  12. package/dist/commands/guard/impl/commit-refresh.js +116 -0
  13. package/dist/commands/guard/impl/commit-stage.d.ts +21 -0
  14. package/dist/commands/guard/impl/commit-stage.d.ts.map +1 -0
  15. package/dist/commands/guard/impl/commit-stage.js +43 -0
  16. package/dist/commands/guard/impl/commit.d.ts.map +1 -1
  17. package/dist/commands/guard/impl/commit.js +10 -150
  18. package/dist/commands/hooks/install.d.ts +4 -0
  19. package/dist/commands/hooks/install.d.ts.map +1 -1
  20. package/dist/commands/hooks/install.js +19 -0
  21. package/dist/commands/hooks/run.pre-push.d.ts.map +1 -1
  22. package/dist/commands/hooks/run.pre-push.js +5 -2
  23. package/dist/commands/recipes/impl/installed-recipes.d.ts +5 -1
  24. package/dist/commands/recipes/impl/installed-recipes.d.ts.map +1 -1
  25. package/dist/commands/recipes/impl/installed-recipes.js +38 -19
  26. package/dist/commands/release/apply.mutation.d.ts.map +1 -1
  27. package/dist/commands/release/apply.mutation.js +5 -4
  28. package/dist/commands/release/apply.pipeline/mutation.d.ts.map +1 -1
  29. package/dist/commands/release/apply.pipeline/mutation.js +6 -1
  30. package/dist/commands/release/apply.preflight.d.ts +4 -29
  31. package/dist/commands/release/apply.preflight.d.ts.map +1 -1
  32. package/dist/commands/release/apply.preflight.git.d.ts +7 -0
  33. package/dist/commands/release/apply.preflight.git.d.ts.map +1 -0
  34. package/dist/commands/release/apply.preflight.git.js +138 -0
  35. package/dist/commands/release/apply.preflight.js +4 -368
  36. package/dist/commands/release/apply.preflight.package.d.ts +7 -0
  37. package/dist/commands/release/apply.preflight.package.d.ts.map +1 -0
  38. package/dist/commands/release/apply.preflight.package.js +69 -0
  39. package/dist/commands/release/apply.preflight.plan.d.ts +16 -0
  40. package/dist/commands/release/apply.preflight.plan.d.ts.map +1 -0
  41. package/dist/commands/release/apply.preflight.plan.js +92 -0
  42. package/dist/commands/release/apply.preflight.publish.d.ts +4 -0
  43. package/dist/commands/release/apply.preflight.publish.d.ts.map +1 -0
  44. package/dist/commands/release/apply.preflight.publish.js +81 -0
  45. package/dist/commands/task/migrate-doc.d.ts.map +1 -1
  46. package/dist/commands/task/migrate-doc.js +25 -248
  47. package/dist/commands/task/migrate-doc.readme.d.ts +8 -0
  48. package/dist/commands/task/migrate-doc.readme.d.ts.map +1 -0
  49. package/dist/commands/task/migrate-doc.readme.js +225 -0
  50. package/dist/runtime/prompt-modules/index.d.ts +3 -0
  51. package/dist/runtime/prompt-modules/index.d.ts.map +1 -0
  52. package/dist/runtime/prompt-modules/index.js +1 -0
  53. package/dist/runtime/prompt-modules/model.d.ts +89 -0
  54. package/dist/runtime/prompt-modules/model.d.ts.map +1 -0
  55. package/dist/runtime/prompt-modules/model.js +1 -0
  56. package/dist/runtime/prompt-modules/mutations.d.ts +103 -0
  57. package/dist/runtime/prompt-modules/mutations.d.ts.map +1 -0
  58. package/dist/runtime/prompt-modules/mutations.js +1 -0
  59. package/dist/shared/runtime-env.d.ts +3 -0
  60. package/dist/shared/runtime-env.d.ts.map +1 -0
  61. package/dist/shared/runtime-env.js +73 -0
  62. package/package.json +3 -3
@@ -1,30 +1,5 @@
1
- import type { PlanChange, ReleaseVersionPlan } from "./apply.types.js";
2
- export declare function fileExists(p: string): Promise<boolean>;
3
- export declare function readJsonFile<T>(p: string): Promise<T>;
4
- export declare function parseVersionPlan(raw: unknown): ReleaseVersionPlan;
5
- export declare function findLatestPlanDir(gitRoot: string): Promise<string>;
6
- export declare function readPackageVersion(pkgJsonPath: string): Promise<string>;
7
- export declare function readCoreDependencyVersion(pkgJsonPath: string): Promise<string>;
8
- export declare function readRecipesDependencyVersion(pkgJsonPath: string): Promise<string>;
9
- export declare function readAgentplaneDependencyVersion(pkgJsonPath: string): Promise<string>;
10
- export declare function readOptionalAgentplaneDependencyVersion(pkgJsonPath: string): Promise<string | null>;
11
- export declare function validateReleaseNotes(notesPath: string, minBullets: number): Promise<void>;
12
- type ReleaseCommandLabel = "release apply" | "release candidate";
13
- export declare function ensureCleanTrackedTree(gitRoot: string, commandLabel?: ReleaseCommandLabel): Promise<void>;
14
- export declare function ensureTagDoesNotExist(gitRoot: string, tag: string, commandLabel?: ReleaseCommandLabel): Promise<void>;
15
- export declare function ensureRemoteExists(gitRoot: string, remote: string, commandLabel?: ReleaseCommandLabel): Promise<void>;
16
- export declare function ensureRemoteTagDoesNotExist(gitRoot: string, remote: string, tag: string, commandLabel?: ReleaseCommandLabel): Promise<void>;
17
- export declare function ensureNpmVersionsAvailable(gitRoot: string, version: string, commandLabel?: ReleaseCommandLabel): Promise<void>;
18
- export declare function runReleasePrepublishGate(gitRoot: string, commandLabel?: ReleaseCommandLabel): Promise<void>;
19
- export declare function loadReleasePlan(opts: {
20
- gitRoot: string;
21
- planOverride?: string;
22
- }): Promise<{
23
- planDir: string;
24
- versionJsonPath: string;
25
- plan: ReleaseVersionPlan;
26
- changes: PlanChange[];
27
- minBullets: number;
28
- }>;
29
- export {};
1
+ export { fileExists, findLatestPlanDir, loadReleasePlan, parseVersionPlan, readJsonFile, } from "./apply.preflight.plan.js";
2
+ export { readAgentplaneDependencyVersion, readCoreDependencyVersion, readOptionalAgentplaneDependencyVersion, readPackageVersion, readRecipesDependencyVersion, validateReleaseNotes, } from "./apply.preflight.package.js";
3
+ export { ensureCleanTrackedTree, ensureRemoteExists, ensureRemoteTagDoesNotExist, ensureTagDoesNotExist, releasePushDescription, type ReleaseCommandLabel, } from "./apply.preflight.git.js";
4
+ export { ensureNpmVersionsAvailable, runReleasePrepublishGate } from "./apply.preflight.publish.js";
30
5
  //# sourceMappingURL=apply.preflight.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"apply.preflight.d.ts","sourceRoot":"","sources":["../../../src/commands/release/apply.preflight.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAEvE,wBAAsB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO5D;AAED,wBAAsB,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAE3D;AAaD,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,GAAG,kBAAkB,CAuBjE;AAED,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAiBxE;AAED,wBAAsB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAW7E;AAoBD,wBAAsB,yBAAyB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAEpF;AAED,wBAAsB,4BAA4B,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAEvF;AAED,wBAAsB,+BAA+B,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAE1F;AAED,wBAAsB,uCAAuC,CAC3D,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAOxB;AAED,wBAAsB,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAwB/F;AAED,KAAK,mBAAmB,GAAG,eAAe,GAAG,mBAAmB,CAAC;AAQjE,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,MAAM,EACf,YAAY,GAAE,mBAAqC,GAClD,OAAO,CAAC,IAAI,CAAC,CAgCf;AAED,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,YAAY,GAAE,mBAAqC,GAClD,OAAO,CAAC,IAAI,CAAC,CA6Bf;AAED,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,YAAY,GAAE,mBAAqC,GAClD,OAAO,CAAC,IAAI,CAAC,CA+Bf;AAED,wBAAsB,2BAA2B,CAC/C,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,YAAY,GAAE,mBAAqC,GAClD,OAAO,CAAC,IAAI,CAAC,CAyDf;AAED,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,YAAY,GAAE,mBAAqC,GAClD,OAAO,CAAC,IAAI,CAAC,CAmCf;AAgBD,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,MAAM,EACf,YAAY,GAAE,mBAAqC,GAClD,OAAO,CAAC,IAAI,CAAC,CAsCf;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC;IAC/F,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,IAAI,EAAE,kBAAkB,CAAC;IACzB,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC,CAwBD"}
1
+ {"version":3,"file":"apply.preflight.d.ts","sourceRoot":"","sources":["../../../src/commands/release/apply.preflight.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,YAAY,GACb,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,+BAA+B,EAC/B,yBAAyB,EACzB,uCAAuC,EACvC,kBAAkB,EAClB,4BAA4B,EAC5B,oBAAoB,GACrB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,sBAAsB,EACtB,kBAAkB,EAClB,2BAA2B,EAC3B,qBAAqB,EACrB,sBAAsB,EACtB,KAAK,mBAAmB,GACzB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,0BAA0B,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC"}
@@ -0,0 +1,7 @@
1
+ export type ReleaseCommandLabel = "release apply" | "release candidate";
2
+ export declare function releasePushDescription(commandLabel: ReleaseCommandLabel): string;
3
+ export declare function ensureCleanTrackedTree(gitRoot: string, commandLabel?: ReleaseCommandLabel): Promise<void>;
4
+ export declare function ensureTagDoesNotExist(gitRoot: string, tag: string, commandLabel?: ReleaseCommandLabel): Promise<void>;
5
+ export declare function ensureRemoteExists(gitRoot: string, remote: string, commandLabel?: ReleaseCommandLabel): Promise<void>;
6
+ export declare function ensureRemoteTagDoesNotExist(gitRoot: string, remote: string, tag: string, commandLabel?: ReleaseCommandLabel): Promise<void>;
7
+ //# sourceMappingURL=apply.preflight.git.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apply.preflight.git.d.ts","sourceRoot":"","sources":["../../../src/commands/release/apply.preflight.git.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,mBAAmB,GAAG,eAAe,GAAG,mBAAmB,CAAC;AAExE,wBAAgB,sBAAsB,CAAC,YAAY,EAAE,mBAAmB,GAAG,MAAM,CAIhF;AAED,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,MAAM,EACf,YAAY,GAAE,mBAAqC,GAClD,OAAO,CAAC,IAAI,CAAC,CAgCf;AAED,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,YAAY,GAAE,mBAAqC,GAClD,OAAO,CAAC,IAAI,CAAC,CA6Bf;AAED,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,YAAY,GAAE,mBAAqC,GAClD,OAAO,CAAC,IAAI,CAAC,CA+Bf;AAED,wBAAsB,2BAA2B,CAC/C,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,YAAY,GAAE,mBAAqC,GAClD,OAAO,CAAC,IAAI,CAAC,CAyDf"}
@@ -0,0 +1,138 @@
1
+ import { exitCodeForError } from "../../cli/exit-codes.js";
2
+ import { withDiagnosticContext } from "../shared/diagnostics.js";
3
+ import { CliError } from "../../shared/errors.js";
4
+ import { execFileAsync } from "@agentplaneorg/core/process";
5
+ import { gitEnv } from "@agentplaneorg/core/git";
6
+ export function releasePushDescription(commandLabel) {
7
+ return commandLabel === "release candidate"
8
+ ? "preparing or pushing the release candidate branch"
9
+ : "pushing the release tag";
10
+ }
11
+ export async function ensureCleanTrackedTree(gitRoot, commandLabel = "release apply") {
12
+ const { stdout } = await execFileAsync("git", ["status", "--short", "--untracked-files=no"], {
13
+ cwd: gitRoot,
14
+ env: gitEnv(),
15
+ maxBuffer: 10 * 1024 * 1024,
16
+ });
17
+ const dirty = String(stdout ?? "")
18
+ .split(/\r?\n/u)
19
+ .map((line) => line.trimEnd())
20
+ .filter((line) => line.length > 0);
21
+ if (dirty.length === 0)
22
+ return;
23
+ throw new CliError({
24
+ exitCode: exitCodeForError("E_GIT"),
25
+ code: "E_GIT",
26
+ message: `${commandLabel} requires a clean tracked working tree.\n` +
27
+ `Found tracked changes:\n${dirty.map((line) => ` ${line}`).join("\n")}`,
28
+ context: withDiagnosticContext({ command: commandLabel }, {
29
+ state: `${commandLabel} cannot start from a dirty tracked tree`,
30
+ likelyCause: "the release flow needs to create one deterministic version-bump commit and tag, but tracked edits already exist in the workspace",
31
+ nextAction: {
32
+ command: "git status --short --untracked-files=no",
33
+ reason: `inspect or clear tracked changes before rerunning \`agentplane ${commandLabel}\``,
34
+ reasonCode: "release_dirty_tree",
35
+ },
36
+ }),
37
+ });
38
+ }
39
+ export async function ensureTagDoesNotExist(gitRoot, tag, commandLabel = "release apply") {
40
+ try {
41
+ await execFileAsync("git", ["rev-parse", "-q", "--verify", `refs/tags/${tag}`], {
42
+ cwd: gitRoot,
43
+ env: gitEnv(),
44
+ });
45
+ throw new CliError({
46
+ exitCode: exitCodeForError("E_GIT"),
47
+ code: "E_GIT",
48
+ message: `Tag already exists: ${tag}`,
49
+ context: withDiagnosticContext({ command: commandLabel }, {
50
+ state: "the target release tag already exists locally",
51
+ likelyCause: "the release version was already applied earlier, or a previous release attempt created the tag before failing later in the flow",
52
+ nextAction: {
53
+ command: `git show --stat --oneline ${tag}`,
54
+ reason: "inspect the existing tag before deciding whether to reuse it or plan a new version",
55
+ reasonCode: "release_tag_exists",
56
+ },
57
+ }),
58
+ });
59
+ }
60
+ catch (err) {
61
+ const code = err?.code;
62
+ if (code !== 1)
63
+ throw err;
64
+ }
65
+ }
66
+ export async function ensureRemoteExists(gitRoot, remote, commandLabel = "release apply") {
67
+ try {
68
+ await execFileAsync("git", ["remote", "get-url", remote], {
69
+ cwd: gitRoot,
70
+ env: gitEnv(),
71
+ });
72
+ }
73
+ catch (err) {
74
+ const details = String(err?.stderr ??
75
+ err?.message ??
76
+ "").trim();
77
+ throw new CliError({
78
+ exitCode: exitCodeForError("E_GIT"),
79
+ code: "E_GIT",
80
+ message: `Git remote is not configured: ${remote}` + (details ? `\n\n${details}` : ""),
81
+ context: withDiagnosticContext({ command: commandLabel }, {
82
+ state: "the configured release remote does not exist locally",
83
+ likelyCause: "release apply was asked to push, but the selected git remote is missing or misconfigured in this checkout",
84
+ nextAction: {
85
+ command: "git remote -v",
86
+ reason: `inspect configured remotes before rerunning ${commandLabel} with --push`,
87
+ reasonCode: "release_remote_missing",
88
+ },
89
+ }),
90
+ });
91
+ }
92
+ }
93
+ export async function ensureRemoteTagDoesNotExist(gitRoot, remote, tag, commandLabel = "release apply") {
94
+ let stdout = "";
95
+ try {
96
+ const out = await execFileAsync("git", ["ls-remote", "--tags", remote, `refs/tags/${tag}`], {
97
+ cwd: gitRoot,
98
+ env: gitEnv(),
99
+ });
100
+ stdout = String(out.stdout ?? "").trim();
101
+ }
102
+ catch (err) {
103
+ const details = String(err?.stderr ??
104
+ err?.message ??
105
+ "").trim();
106
+ throw new CliError({
107
+ exitCode: exitCodeForError("E_GIT"),
108
+ code: "E_GIT",
109
+ message: `Failed to inspect remote tag state for ${remote}/${tag}.` +
110
+ (details ? `\n\n${details}` : ""),
111
+ context: withDiagnosticContext({ command: commandLabel }, {
112
+ state: `${commandLabel} could not verify the remote tag state`,
113
+ likelyCause: "the remote is configured, but git could not query it for the target release tag before the release started",
114
+ nextAction: {
115
+ command: `git ls-remote --tags ${remote} refs/tags/${tag}`,
116
+ reason: "inspect remote tag visibility before retrying the release push path",
117
+ reasonCode: "release_remote_tag_check_failed",
118
+ },
119
+ }),
120
+ });
121
+ }
122
+ if (!stdout)
123
+ return;
124
+ throw new CliError({
125
+ exitCode: exitCodeForError("E_GIT"),
126
+ code: "E_GIT",
127
+ message: `Remote tag already exists: ${remote}/${tag}`,
128
+ context: withDiagnosticContext({ command: commandLabel }, {
129
+ state: "the target release tag already exists on the remote",
130
+ likelyCause: "a previous release or partial push already published this tag upstream, so pushing the same version again would drift the local release state",
131
+ nextAction: {
132
+ command: `git ls-remote --tags ${remote} refs/tags/${tag}`,
133
+ reason: "inspect the existing remote tag before deciding whether to recover or bump to a new version",
134
+ reasonCode: "release_remote_tag_exists",
135
+ },
136
+ }),
137
+ });
138
+ }
@@ -1,368 +1,4 @@
1
- import { readFile, readdir } from "node:fs/promises";
2
- import path from "node:path";
3
- import { exitCodeForError } from "../../cli/exit-codes.js";
4
- import { withDiagnosticContext } from "../shared/diagnostics.js";
5
- import { CliError } from "../../shared/errors.js";
6
- import { execFileAsync } from "@agentplaneorg/core/process";
7
- import { gitEnv } from "@agentplaneorg/core/git";
8
- export async function fileExists(p) {
9
- try {
10
- await readFile(p, "utf8");
11
- return true;
12
- }
13
- catch {
14
- return false;
15
- }
16
- }
17
- export async function readJsonFile(p) {
18
- return JSON.parse(await readFile(p, "utf8"));
19
- }
20
- function assertNonEmptyString(value, label) {
21
- if (typeof value !== "string" || !value.trim()) {
22
- throw new CliError({
23
- exitCode: exitCodeForError("E_VALIDATION"),
24
- code: "E_VALIDATION",
25
- message: `Invalid ${label} (expected non-empty string).`,
26
- });
27
- }
28
- return value.trim();
29
- }
30
- export function parseVersionPlan(raw) {
31
- if (!raw || typeof raw !== "object") {
32
- throw new CliError({
33
- exitCode: exitCodeForError("E_VALIDATION"),
34
- code: "E_VALIDATION",
35
- message: "Invalid version.json (expected object).",
36
- });
37
- }
38
- const obj = raw;
39
- const bumpRaw = assertNonEmptyString(obj.bump, "bump");
40
- if (bumpRaw !== "patch" && bumpRaw !== "minor" && bumpRaw !== "major") {
41
- throw new CliError({
42
- exitCode: exitCodeForError("E_VALIDATION"),
43
- code: "E_VALIDATION",
44
- message: `Invalid bump in version.json: ${bumpRaw}`,
45
- });
46
- }
47
- const prevTagVal = obj.prevTag;
48
- const prevTag = prevTagVal === null ? null : typeof prevTagVal === "string" ? prevTagVal : null;
49
- const prevVersion = assertNonEmptyString(obj.prevVersion, "prevVersion");
50
- const nextTag = assertNonEmptyString(obj.nextTag, "nextTag");
51
- const nextVersion = assertNonEmptyString(obj.nextVersion, "nextVersion");
52
- return { prevTag, prevVersion, nextTag, nextVersion, bump: bumpRaw };
53
- }
54
- export async function findLatestPlanDir(gitRoot) {
55
- const base = path.join(gitRoot, ".agentplane", ".release", "plan");
56
- const runNames = await readdir(base);
57
- const runs = runNames
58
- .map((s) => s.trim())
59
- .filter(Boolean)
60
- .toSorted();
61
- const latest = runs.at(-1);
62
- if (!latest) {
63
- throw new CliError({
64
- exitCode: exitCodeForError("E_IO"),
65
- code: "E_IO",
66
- message: "No release plan runs found under .agentplane/.release/plan/. Run `agentplane release plan` first.",
67
- });
68
- }
69
- return path.join(base, latest);
70
- }
71
- export async function readPackageVersion(pkgJsonPath) {
72
- const raw = JSON.parse(await readFile(pkgJsonPath, "utf8"));
73
- const version = typeof raw.version === "string" ? raw.version.trim() : "";
74
- if (!version) {
75
- throw new CliError({
76
- exitCode: exitCodeForError("E_VALIDATION"),
77
- code: "E_VALIDATION",
78
- message: `Missing package.json version: ${pkgJsonPath}`,
79
- });
80
- }
81
- return version;
82
- }
83
- async function readDependencyVersion(pkgJsonPath, dependencyName) {
84
- const raw = JSON.parse(await readFile(pkgJsonPath, "utf8"));
85
- const value = raw.dependencies?.[dependencyName];
86
- const version = typeof value === "string" ? value.trim() : "";
87
- if (!version) {
88
- throw new CliError({
89
- exitCode: exitCodeForError("E_VALIDATION"),
90
- code: "E_VALIDATION",
91
- message: `Missing dependency ${dependencyName} in ${pkgJsonPath}. ` +
92
- `Release parity requires packages/agentplane to pin ${dependencyName} to the same version.`,
93
- });
94
- }
95
- return version;
96
- }
97
- export async function readCoreDependencyVersion(pkgJsonPath) {
98
- return await readDependencyVersion(pkgJsonPath, "@agentplaneorg/core");
99
- }
100
- export async function readRecipesDependencyVersion(pkgJsonPath) {
101
- return await readDependencyVersion(pkgJsonPath, "@agentplaneorg/recipes");
102
- }
103
- export async function readAgentplaneDependencyVersion(pkgJsonPath) {
104
- return await readDependencyVersion(pkgJsonPath, "agentplane");
105
- }
106
- export async function readOptionalAgentplaneDependencyVersion(pkgJsonPath) {
107
- const raw = JSON.parse(await readFile(pkgJsonPath, "utf8"));
108
- const value = raw.dependencies?.agentplane;
109
- const version = typeof value === "string" ? value.trim() : "";
110
- return version || null;
111
- }
112
- export async function validateReleaseNotes(notesPath, minBullets) {
113
- const content = await readFile(notesPath, "utf8");
114
- if (!/release\s+notes/i.test(content)) {
115
- throw new CliError({
116
- exitCode: exitCodeForError("E_VALIDATION"),
117
- code: "E_VALIDATION",
118
- message: `Release notes must include a "Release Notes" heading in ${notesPath}.`,
119
- });
120
- }
121
- const bulletCount = content.split(/\r?\n/u).filter((line) => /^\s*[-*]\s+\S+/u.test(line)).length;
122
- if (bulletCount < minBullets) {
123
- throw new CliError({
124
- exitCode: exitCodeForError("E_VALIDATION"),
125
- code: "E_VALIDATION",
126
- message: `Release notes must include at least ${minBullets} bullet points in ${notesPath}.`,
127
- });
128
- }
129
- if (/[\u0400-\u04FF]/u.test(content)) {
130
- throw new CliError({
131
- exitCode: exitCodeForError("E_VALIDATION"),
132
- code: "E_VALIDATION",
133
- message: `Release notes must be written in English (no Cyrillic) in ${notesPath}.`,
134
- });
135
- }
136
- }
137
- function releasePushDescription(commandLabel) {
138
- return commandLabel === "release candidate"
139
- ? "preparing or pushing the release candidate branch"
140
- : "pushing the release tag";
141
- }
142
- export async function ensureCleanTrackedTree(gitRoot, commandLabel = "release apply") {
143
- const { stdout } = await execFileAsync("git", ["status", "--short", "--untracked-files=no"], {
144
- cwd: gitRoot,
145
- env: gitEnv(),
146
- maxBuffer: 10 * 1024 * 1024,
147
- });
148
- const dirty = String(stdout ?? "")
149
- .split(/\r?\n/u)
150
- .map((line) => line.trimEnd())
151
- .filter((line) => line.length > 0);
152
- if (dirty.length === 0)
153
- return;
154
- throw new CliError({
155
- exitCode: exitCodeForError("E_GIT"),
156
- code: "E_GIT",
157
- message: `${commandLabel} requires a clean tracked working tree.\n` +
158
- `Found tracked changes:\n${dirty.map((line) => ` ${line}`).join("\n")}`,
159
- context: withDiagnosticContext({ command: commandLabel }, {
160
- state: `${commandLabel} cannot start from a dirty tracked tree`,
161
- likelyCause: "the release flow needs to create one deterministic version-bump commit and tag, but tracked edits already exist in the workspace",
162
- nextAction: {
163
- command: "git status --short --untracked-files=no",
164
- reason: `inspect or clear tracked changes before rerunning \`agentplane ${commandLabel}\``,
165
- reasonCode: "release_dirty_tree",
166
- },
167
- }),
168
- });
169
- }
170
- export async function ensureTagDoesNotExist(gitRoot, tag, commandLabel = "release apply") {
171
- try {
172
- await execFileAsync("git", ["rev-parse", "-q", "--verify", `refs/tags/${tag}`], {
173
- cwd: gitRoot,
174
- env: gitEnv(),
175
- });
176
- throw new CliError({
177
- exitCode: exitCodeForError("E_GIT"),
178
- code: "E_GIT",
179
- message: `Tag already exists: ${tag}`,
180
- context: withDiagnosticContext({ command: commandLabel }, {
181
- state: "the target release tag already exists locally",
182
- likelyCause: "the release version was already applied earlier, or a previous release attempt created the tag before failing later in the flow",
183
- nextAction: {
184
- command: `git show --stat --oneline ${tag}`,
185
- reason: "inspect the existing tag before deciding whether to reuse it or plan a new version",
186
- reasonCode: "release_tag_exists",
187
- },
188
- }),
189
- });
190
- }
191
- catch (err) {
192
- const code = err?.code;
193
- if (code !== 1)
194
- throw err;
195
- }
196
- }
197
- export async function ensureRemoteExists(gitRoot, remote, commandLabel = "release apply") {
198
- try {
199
- await execFileAsync("git", ["remote", "get-url", remote], {
200
- cwd: gitRoot,
201
- env: gitEnv(),
202
- });
203
- }
204
- catch (err) {
205
- const details = String(err?.stderr ??
206
- err?.message ??
207
- "").trim();
208
- throw new CliError({
209
- exitCode: exitCodeForError("E_GIT"),
210
- code: "E_GIT",
211
- message: `Git remote is not configured: ${remote}` + (details ? `\n\n${details}` : ""),
212
- context: withDiagnosticContext({ command: commandLabel }, {
213
- state: "the configured release remote does not exist locally",
214
- likelyCause: "release apply was asked to push, but the selected git remote is missing or misconfigured in this checkout",
215
- nextAction: {
216
- command: "git remote -v",
217
- reason: `inspect configured remotes before rerunning ${commandLabel} with --push`,
218
- reasonCode: "release_remote_missing",
219
- },
220
- }),
221
- });
222
- }
223
- }
224
- export async function ensureRemoteTagDoesNotExist(gitRoot, remote, tag, commandLabel = "release apply") {
225
- let stdout = "";
226
- try {
227
- const out = await execFileAsync("git", ["ls-remote", "--tags", remote, `refs/tags/${tag}`], {
228
- cwd: gitRoot,
229
- env: gitEnv(),
230
- });
231
- stdout = String(out.stdout ?? "").trim();
232
- }
233
- catch (err) {
234
- const details = String(err?.stderr ??
235
- err?.message ??
236
- "").trim();
237
- throw new CliError({
238
- exitCode: exitCodeForError("E_GIT"),
239
- code: "E_GIT",
240
- message: `Failed to inspect remote tag state for ${remote}/${tag}.` +
241
- (details ? `\n\n${details}` : ""),
242
- context: withDiagnosticContext({ command: commandLabel }, {
243
- state: `${commandLabel} could not verify the remote tag state`,
244
- likelyCause: "the remote is configured, but git could not query it for the target release tag before the release started",
245
- nextAction: {
246
- command: `git ls-remote --tags ${remote} refs/tags/${tag}`,
247
- reason: "inspect remote tag visibility before retrying the release push path",
248
- reasonCode: "release_remote_tag_check_failed",
249
- },
250
- }),
251
- });
252
- }
253
- if (!stdout)
254
- return;
255
- throw new CliError({
256
- exitCode: exitCodeForError("E_GIT"),
257
- code: "E_GIT",
258
- message: `Remote tag already exists: ${remote}/${tag}`,
259
- context: withDiagnosticContext({ command: commandLabel }, {
260
- state: "the target release tag already exists on the remote",
261
- likelyCause: "a previous release or partial push already published this tag upstream, so pushing the same version again would drift the local release state",
262
- nextAction: {
263
- command: `git ls-remote --tags ${remote} refs/tags/${tag}`,
264
- reason: "inspect the existing remote tag before deciding whether to recover or bump to a new version",
265
- reasonCode: "release_remote_tag_exists",
266
- },
267
- }),
268
- });
269
- }
270
- export async function ensureNpmVersionsAvailable(gitRoot, version, commandLabel = "release apply") {
271
- const scriptPath = path.join(gitRoot, "scripts", "check-npm-version-availability.mjs");
272
- try {
273
- await execFileAsync("node", [scriptPath, "--version", version], {
274
- cwd: gitRoot,
275
- env: process.env,
276
- maxBuffer: 10 * 1024 * 1024,
277
- });
278
- }
279
- catch (err) {
280
- const details = String(err?.stderr ?? "").trim();
281
- throw new CliError({
282
- exitCode: exitCodeForError("E_VALIDATION"),
283
- code: "E_VALIDATION",
284
- message: `Pre-publish npm check failed for version ${version}. ` +
285
- "Ensure this version is not already published for @agentplaneorg/core and agentplane." +
286
- (details ? `\n\n${details}` : ""),
287
- context: withDiagnosticContext({ command: commandLabel }, {
288
- state: "the target npm version is not publishable",
289
- likelyCause: "that version is already burned in npm history for one of the published packages, even if it is no longer the current dist-tag",
290
- nextAction: {
291
- command: `node scripts/check-npm-version-availability.mjs --version ${version}`,
292
- reason: "inspect which package already consumed the target version before choosing a new release number",
293
- reasonCode: "release_npm_version_burned",
294
- },
295
- }),
296
- });
297
- }
298
- }
299
- async function runReleasePrepublishPhase(gitRoot, phase) {
300
- await execFileAsync("bun", ["run", `release:prepublish:${phase}`], {
301
- cwd: gitRoot,
302
- env: {
303
- ...process.env,
304
- GIT_AUTHOR_NAME: process.env.GIT_AUTHOR_NAME ?? "agentplane-release",
305
- GIT_AUTHOR_EMAIL: process.env.GIT_AUTHOR_EMAIL ?? "agentplane-release@example.com",
306
- GIT_COMMITTER_NAME: process.env.GIT_COMMITTER_NAME ?? "agentplane-release",
307
- GIT_COMMITTER_EMAIL: process.env.GIT_COMMITTER_EMAIL ?? "agentplane-release@example.com",
308
- },
309
- maxBuffer: 200 * 1024 * 1024,
310
- });
311
- }
312
- export async function runReleasePrepublishGate(gitRoot, commandLabel = "release apply") {
313
- for (const phase of ["fast", "heavy"]) {
314
- try {
315
- await runReleasePrepublishPhase(gitRoot, phase);
316
- }
317
- catch (err) {
318
- const details = String(err?.stderr ??
319
- err?.stdout ??
320
- err?.message ??
321
- "").trim();
322
- throw new CliError({
323
- exitCode: exitCodeForError("E_VALIDATION"),
324
- code: "E_VALIDATION",
325
- message: `Release prepublish ${phase} phase failed. \`agentplane ${commandLabel} --push\` requires a successful local \`bun run release:prepublish:${phase}\` run before ${releasePushDescription(commandLabel)}.` +
326
- (details ? `\n\n${details}` : ""),
327
- context: withDiagnosticContext({ command: commandLabel }, {
328
- state: `release prepublish ${phase} validation failed before ${releasePushDescription(commandLabel)}`,
329
- likelyCause: phase === "fast"
330
- ? "a lightweight publish-readiness check rejected the current release payload before the expensive validation route started"
331
- : "the expensive release validation route rejected the current repository state after the fast publish-readiness checks passed",
332
- nextAction: {
333
- command: `bun run release:prepublish:${phase}`,
334
- reason: phase === "fast"
335
- ? `rerun the fast prepublish phase to fix the exact payload or packaging problem before retrying ${commandLabel}`
336
- : `rerun the heavy prepublish phase to inspect and fix the expensive validation failure before retrying ${commandLabel}`,
337
- reasonCode: `release_prepublish_${phase}_failed`,
338
- },
339
- }),
340
- });
341
- }
342
- }
343
- }
344
- export async function loadReleasePlan(opts) {
345
- const planDir = opts.planOverride
346
- ? path.resolve(opts.gitRoot, opts.planOverride)
347
- : await findLatestPlanDir(opts.gitRoot);
348
- const versionJsonPath = path.join(planDir, "version.json");
349
- if (!(await fileExists(versionJsonPath))) {
350
- throw new CliError({
351
- exitCode: exitCodeForError("E_IO"),
352
- code: "E_IO",
353
- message: `Missing version.json in plan dir: ${path.relative(opts.gitRoot, versionJsonPath)}`,
354
- });
355
- }
356
- const plan = parseVersionPlan(await readJsonFile(versionJsonPath));
357
- const changesJsonPath = path.join(planDir, "changes.json");
358
- const changes = (await fileExists(changesJsonPath))
359
- ? await readJsonFile(changesJsonPath)
360
- : [];
361
- return {
362
- planDir,
363
- versionJsonPath,
364
- plan,
365
- changes,
366
- minBullets: Math.max(1, Array.isArray(changes) ? changes.length : 0),
367
- };
368
- }
1
+ export { fileExists, findLatestPlanDir, loadReleasePlan, parseVersionPlan, readJsonFile, } from "./apply.preflight.plan.js";
2
+ export { readAgentplaneDependencyVersion, readCoreDependencyVersion, readOptionalAgentplaneDependencyVersion, readPackageVersion, readRecipesDependencyVersion, validateReleaseNotes, } from "./apply.preflight.package.js";
3
+ export { ensureCleanTrackedTree, ensureRemoteExists, ensureRemoteTagDoesNotExist, ensureTagDoesNotExist, releasePushDescription, } from "./apply.preflight.git.js";
4
+ export { ensureNpmVersionsAvailable, runReleasePrepublishGate } from "./apply.preflight.publish.js";
@@ -0,0 +1,7 @@
1
+ export declare function readPackageVersion(pkgJsonPath: string): Promise<string>;
2
+ export declare function readCoreDependencyVersion(pkgJsonPath: string): Promise<string>;
3
+ export declare function readRecipesDependencyVersion(pkgJsonPath: string): Promise<string>;
4
+ export declare function readAgentplaneDependencyVersion(pkgJsonPath: string): Promise<string>;
5
+ export declare function readOptionalAgentplaneDependencyVersion(pkgJsonPath: string): Promise<string | null>;
6
+ export declare function validateReleaseNotes(notesPath: string, minBullets: number): Promise<void>;
7
+ //# sourceMappingURL=apply.preflight.package.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apply.preflight.package.d.ts","sourceRoot":"","sources":["../../../src/commands/release/apply.preflight.package.ts"],"names":[],"mappings":"AAKA,wBAAsB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAW7E;AAoBD,wBAAsB,yBAAyB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAEpF;AAED,wBAAsB,4BAA4B,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAEvF;AAED,wBAAsB,+BAA+B,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAE1F;AAED,wBAAsB,uCAAuC,CAC3D,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAOxB;AAED,wBAAsB,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAwB/F"}
@@ -0,0 +1,69 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { exitCodeForError } from "../../cli/exit-codes.js";
3
+ import { CliError } from "../../shared/errors.js";
4
+ export async function readPackageVersion(pkgJsonPath) {
5
+ const raw = JSON.parse(await readFile(pkgJsonPath, "utf8"));
6
+ const version = typeof raw.version === "string" ? raw.version.trim() : "";
7
+ if (!version) {
8
+ throw new CliError({
9
+ exitCode: exitCodeForError("E_VALIDATION"),
10
+ code: "E_VALIDATION",
11
+ message: `Missing package.json version: ${pkgJsonPath}`,
12
+ });
13
+ }
14
+ return version;
15
+ }
16
+ async function readDependencyVersion(pkgJsonPath, dependencyName) {
17
+ const raw = JSON.parse(await readFile(pkgJsonPath, "utf8"));
18
+ const value = raw.dependencies?.[dependencyName];
19
+ const version = typeof value === "string" ? value.trim() : "";
20
+ if (!version) {
21
+ throw new CliError({
22
+ exitCode: exitCodeForError("E_VALIDATION"),
23
+ code: "E_VALIDATION",
24
+ message: `Missing dependency ${dependencyName} in ${pkgJsonPath}. ` +
25
+ `Release parity requires packages/agentplane to pin ${dependencyName} to the same version.`,
26
+ });
27
+ }
28
+ return version;
29
+ }
30
+ export async function readCoreDependencyVersion(pkgJsonPath) {
31
+ return await readDependencyVersion(pkgJsonPath, "@agentplaneorg/core");
32
+ }
33
+ export async function readRecipesDependencyVersion(pkgJsonPath) {
34
+ return await readDependencyVersion(pkgJsonPath, "@agentplaneorg/recipes");
35
+ }
36
+ export async function readAgentplaneDependencyVersion(pkgJsonPath) {
37
+ return await readDependencyVersion(pkgJsonPath, "agentplane");
38
+ }
39
+ export async function readOptionalAgentplaneDependencyVersion(pkgJsonPath) {
40
+ const raw = JSON.parse(await readFile(pkgJsonPath, "utf8"));
41
+ const value = raw.dependencies?.agentplane;
42
+ const version = typeof value === "string" ? value.trim() : "";
43
+ return version || null;
44
+ }
45
+ export async function validateReleaseNotes(notesPath, minBullets) {
46
+ const content = await readFile(notesPath, "utf8");
47
+ if (!/release\s+notes/i.test(content)) {
48
+ throw new CliError({
49
+ exitCode: exitCodeForError("E_VALIDATION"),
50
+ code: "E_VALIDATION",
51
+ message: `Release notes must include a "Release Notes" heading in ${notesPath}.`,
52
+ });
53
+ }
54
+ const bulletCount = content.split(/\r?\n/u).filter((line) => /^\s*[-*]\s+\S+/u.test(line)).length;
55
+ if (bulletCount < minBullets) {
56
+ throw new CliError({
57
+ exitCode: exitCodeForError("E_VALIDATION"),
58
+ code: "E_VALIDATION",
59
+ message: `Release notes must include at least ${minBullets} bullet points in ${notesPath}.`,
60
+ });
61
+ }
62
+ if (/[\u0400-\u04FF]/u.test(content)) {
63
+ throw new CliError({
64
+ exitCode: exitCodeForError("E_VALIDATION"),
65
+ code: "E_VALIDATION",
66
+ message: `Release notes must be written in English (no Cyrillic) in ${notesPath}.`,
67
+ });
68
+ }
69
+ }