agentplane 0.3.23 → 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.
- package/dist/.build-manifest.json +47 -12
- package/dist/cli.js +309 -309
- package/dist/commands/guard/impl/commit-refresh.d.ts +25 -0
- package/dist/commands/guard/impl/commit-refresh.d.ts.map +1 -0
- package/dist/commands/guard/impl/commit-refresh.js +116 -0
- package/dist/commands/guard/impl/commit-stage.d.ts +21 -0
- package/dist/commands/guard/impl/commit-stage.d.ts.map +1 -0
- package/dist/commands/guard/impl/commit-stage.js +43 -0
- package/dist/commands/guard/impl/commit.d.ts.map +1 -1
- package/dist/commands/guard/impl/commit.js +10 -150
- package/dist/commands/release/apply.preflight.d.ts +4 -29
- package/dist/commands/release/apply.preflight.d.ts.map +1 -1
- package/dist/commands/release/apply.preflight.git.d.ts +7 -0
- package/dist/commands/release/apply.preflight.git.d.ts.map +1 -0
- package/dist/commands/release/apply.preflight.git.js +138 -0
- package/dist/commands/release/apply.preflight.js +4 -369
- package/dist/commands/release/apply.preflight.package.d.ts +7 -0
- package/dist/commands/release/apply.preflight.package.d.ts.map +1 -0
- package/dist/commands/release/apply.preflight.package.js +69 -0
- package/dist/commands/release/apply.preflight.plan.d.ts +16 -0
- package/dist/commands/release/apply.preflight.plan.d.ts.map +1 -0
- package/dist/commands/release/apply.preflight.plan.js +92 -0
- package/dist/commands/release/apply.preflight.publish.d.ts +4 -0
- package/dist/commands/release/apply.preflight.publish.d.ts.map +1 -0
- package/dist/commands/release/apply.preflight.publish.js +81 -0
- package/dist/commands/task/migrate-doc.d.ts.map +1 -1
- package/dist/commands/task/migrate-doc.js +25 -248
- package/dist/commands/task/migrate-doc.readme.d.ts +8 -0
- package/dist/commands/task/migrate-doc.readme.d.ts.map +1 -0
- package/dist/commands/task/migrate-doc.readme.js +225 -0
- package/package.json +3 -3
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type CommandContext } from "../../shared/task-backend.js";
|
|
2
|
+
type CommitRef = {
|
|
3
|
+
hash: string;
|
|
4
|
+
subject: string;
|
|
5
|
+
} | null;
|
|
6
|
+
export declare function resetRebuildableTaskIndexCache(ctx: CommandContext): Promise<void>;
|
|
7
|
+
export declare function formatCommitRef(commit: CommitRef): string;
|
|
8
|
+
export declare function commitRefreshedTaskArtifacts(opts: {
|
|
9
|
+
ctx: CommandContext;
|
|
10
|
+
cwd: string;
|
|
11
|
+
rootOverride?: string;
|
|
12
|
+
taskId: string;
|
|
13
|
+
sourceMessage: string;
|
|
14
|
+
quiet: boolean;
|
|
15
|
+
}): Promise<CommitRef>;
|
|
16
|
+
export declare function refreshBranchPrArtifactsForCloseCommit(opts: {
|
|
17
|
+
ctx: CommandContext;
|
|
18
|
+
cwd: string;
|
|
19
|
+
rootOverride?: string;
|
|
20
|
+
taskId: string;
|
|
21
|
+
quiet: boolean;
|
|
22
|
+
refreshTaskArtifacts: boolean;
|
|
23
|
+
}): Promise<void>;
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=commit-refresh.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commit-refresh.d.ts","sourceRoot":"","sources":["../../../../src/commands/guard/impl/commit-refresh.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAKnE,KAAK,SAAS,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC;AAE1D,wBAAsB,8BAA8B,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CA2BvF;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CAGzD;AAED,wBAAsB,4BAA4B,CAAC,IAAI,EAAE;IACvD,GAAG,EAAE,cAAc,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,OAAO,CAAC;CAChB,GAAG,OAAO,CAAC,SAAS,CAAC,CAgErB;AAED,wBAAsB,sCAAsC,CAAC,IAAI,EAAE;IACjE,GAAG,EAAE,cAAc,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,oBAAoB,EAAE,OAAO,CAAC;CAC/B,GAAG,OAAO,CAAC,IAAI,CAAC,CAWhB"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { mkdir, rm, writeFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { buildTaskArtifactRefreshCommitSubject } from "@agentplaneorg/core/commit";
|
|
4
|
+
import { gitEnv } from "@agentplaneorg/core/git";
|
|
5
|
+
import { execFileAsync } from "@agentplaneorg/core/process";
|
|
6
|
+
import { resolveTaskIndexPath } from "../../../backends/task-index.js";
|
|
7
|
+
import { refreshBranchPrArtifactsAfterTaskCommit } from "../../shared/post-commit-pr-artifacts.js";
|
|
8
|
+
import { isTaskLocalAdvancePath } from "../../shared/task-local-freshness.js";
|
|
9
|
+
import { stageAllowlist } from "./allow.js";
|
|
10
|
+
import { buildGitCommitEnv, resolveCanonicalGitIdentity } from "./env.js";
|
|
11
|
+
import { guardCommitCheck } from "./policy.js";
|
|
12
|
+
export async function resetRebuildableTaskIndexCache(ctx) {
|
|
13
|
+
const gitRoot = path.resolve(ctx.resolvedProject.gitRoot);
|
|
14
|
+
const workflowDirAbs = path.resolve(gitRoot, ctx.config.paths.workflow_dir);
|
|
15
|
+
const cachePath = path.resolve(resolveTaskIndexPath(workflowDirAbs));
|
|
16
|
+
const relativeCachePath = path.relative(gitRoot, cachePath);
|
|
17
|
+
if (!relativeCachePath || relativeCachePath.startsWith(".."))
|
|
18
|
+
return;
|
|
19
|
+
try {
|
|
20
|
+
await execFileAsync("git", ["ls-files", "--error-unmatch", "--", relativeCachePath], {
|
|
21
|
+
cwd: gitRoot,
|
|
22
|
+
env: gitEnv(),
|
|
23
|
+
});
|
|
24
|
+
const gitPath = relativeCachePath.split(path.sep).join("/");
|
|
25
|
+
const cacheBlob = await execFileAsync("git", ["show", `HEAD:${gitPath}`], {
|
|
26
|
+
cwd: gitRoot,
|
|
27
|
+
env: gitEnv(),
|
|
28
|
+
});
|
|
29
|
+
await mkdir(path.dirname(cachePath), { recursive: true });
|
|
30
|
+
await writeFile(cachePath, cacheBlob.stdout, "utf8");
|
|
31
|
+
await execFileAsync("git", ["restore", "--staged", "--", relativeCachePath], {
|
|
32
|
+
cwd: gitRoot,
|
|
33
|
+
env: gitEnv(),
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
await rm(cachePath, { force: true });
|
|
38
|
+
}
|
|
39
|
+
ctx.git.invalidateStatus();
|
|
40
|
+
}
|
|
41
|
+
export function formatCommitRef(commit) {
|
|
42
|
+
if (!commit)
|
|
43
|
+
return "";
|
|
44
|
+
return `${commit.hash?.slice(0, 12) ?? ""} ${commit.subject ?? ""}`.trim();
|
|
45
|
+
}
|
|
46
|
+
export async function commitRefreshedTaskArtifacts(opts) {
|
|
47
|
+
const changedPaths = await opts.ctx.git.statusChangedPaths();
|
|
48
|
+
const taskArtifactPaths = changedPaths.filter((relPath) => isTaskLocalAdvancePath({
|
|
49
|
+
workflowDir: opts.ctx.config.paths.workflow_dir,
|
|
50
|
+
taskId: opts.taskId,
|
|
51
|
+
tasksPath: opts.ctx.config.paths.tasks_path,
|
|
52
|
+
relPath,
|
|
53
|
+
}));
|
|
54
|
+
if (taskArtifactPaths.length === 0)
|
|
55
|
+
return null;
|
|
56
|
+
await stageAllowlist({
|
|
57
|
+
ctx: opts.ctx,
|
|
58
|
+
allow: [],
|
|
59
|
+
allowTasks: true,
|
|
60
|
+
allowPolicy: false,
|
|
61
|
+
allowConfig: false,
|
|
62
|
+
allowHooks: false,
|
|
63
|
+
allowCI: false,
|
|
64
|
+
tasksPath: opts.ctx.config.paths.tasks_path,
|
|
65
|
+
workflowDir: opts.ctx.config.paths.workflow_dir,
|
|
66
|
+
taskId: opts.taskId,
|
|
67
|
+
allowTaskOnly: true,
|
|
68
|
+
emptyAllowMessage: "PR artifact refresh produced no task-local files to stage for the follow-up commit.",
|
|
69
|
+
noMatchMessage: "PR artifact refresh produced changes outside the active task artifact scope; inspect the working tree before retrying the commit flow.",
|
|
70
|
+
});
|
|
71
|
+
const message = buildTaskArtifactRefreshCommitSubject({
|
|
72
|
+
taskId: opts.taskId,
|
|
73
|
+
baseSubject: opts.sourceMessage,
|
|
74
|
+
});
|
|
75
|
+
await guardCommitCheck({
|
|
76
|
+
ctx: opts.ctx,
|
|
77
|
+
cwd: opts.cwd,
|
|
78
|
+
rootOverride: opts.rootOverride,
|
|
79
|
+
baseBranchOverride: null,
|
|
80
|
+
taskId: opts.taskId,
|
|
81
|
+
message,
|
|
82
|
+
allow: [],
|
|
83
|
+
allowBase: false,
|
|
84
|
+
allowTasks: true,
|
|
85
|
+
allowPolicy: false,
|
|
86
|
+
allowConfig: false,
|
|
87
|
+
allowHooks: false,
|
|
88
|
+
allowCI: false,
|
|
89
|
+
requireClean: true,
|
|
90
|
+
quiet: opts.quiet,
|
|
91
|
+
});
|
|
92
|
+
const env = buildGitCommitEnv({
|
|
93
|
+
taskId: opts.taskId,
|
|
94
|
+
allowTasks: true,
|
|
95
|
+
allowBase: false,
|
|
96
|
+
allowPolicy: false,
|
|
97
|
+
allowConfig: false,
|
|
98
|
+
allowHooks: false,
|
|
99
|
+
allowCI: false,
|
|
100
|
+
gitIdentity: await resolveCanonicalGitIdentity(),
|
|
101
|
+
});
|
|
102
|
+
await opts.ctx.git.commit({ message, env });
|
|
103
|
+
return await opts.ctx.git.headHashSubject();
|
|
104
|
+
}
|
|
105
|
+
export async function refreshBranchPrArtifactsForCloseCommit(opts) {
|
|
106
|
+
if (opts.refreshTaskArtifacts) {
|
|
107
|
+
await refreshBranchPrArtifactsAfterTaskCommit({
|
|
108
|
+
ctx: opts.ctx,
|
|
109
|
+
cwd: opts.cwd,
|
|
110
|
+
rootOverride: opts.rootOverride,
|
|
111
|
+
taskId: opts.taskId,
|
|
112
|
+
quiet: opts.quiet,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
opts.ctx.git.invalidateStatus();
|
|
116
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type CommandContext } from "../../shared/task-backend.js";
|
|
2
|
+
export declare function hasExplicitCommitScope(opts: {
|
|
3
|
+
allow: string[];
|
|
4
|
+
allowTasks: boolean;
|
|
5
|
+
allowPolicy: boolean;
|
|
6
|
+
allowConfig: boolean;
|
|
7
|
+
allowHooks: boolean;
|
|
8
|
+
allowCI: boolean;
|
|
9
|
+
}): boolean;
|
|
10
|
+
export declare function stageActiveTaskArtifactsFromAllowTasks(opts: {
|
|
11
|
+
ctx: CommandContext;
|
|
12
|
+
taskId: string;
|
|
13
|
+
allowTasks: boolean;
|
|
14
|
+
}): Promise<string[]>;
|
|
15
|
+
export declare function stageCloseCommitPaths(opts: {
|
|
16
|
+
ctx: CommandContext;
|
|
17
|
+
readmeRel: string;
|
|
18
|
+
taskId: string;
|
|
19
|
+
allowPolicy: boolean;
|
|
20
|
+
}): Promise<void>;
|
|
21
|
+
//# sourceMappingURL=commit-stage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commit-stage.d.ts","sourceRoot":"","sources":["../../../../src/commands/guard/impl/commit-stage.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAEnE,wBAAgB,sBAAsB,CAAC,IAAI,EAAE;IAC3C,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;CAClB,GAAG,OAAO,CASV;AAED,wBAAsB,sCAAsC,CAAC,IAAI,EAAE;IACjE,GAAG,EAAE,cAAc,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,OAAO,CAAC;CACrB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAiBpB;AAED,wBAAsB,qBAAqB,CAAC,IAAI,EAAE;IAChD,GAAG,EAAE,cAAc,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,OAAO,CAAC;CACtB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBhB"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { protectedPathKindForFile } from "../../../shared/protected-paths.js";
|
|
2
|
+
import { isTaskLocalAdvancePath } from "../../shared/task-local-freshness.js";
|
|
3
|
+
export function hasExplicitCommitScope(opts) {
|
|
4
|
+
return (opts.allow.some((prefix) => prefix.trim().length > 0) ||
|
|
5
|
+
opts.allowTasks ||
|
|
6
|
+
opts.allowPolicy ||
|
|
7
|
+
opts.allowConfig ||
|
|
8
|
+
opts.allowHooks ||
|
|
9
|
+
opts.allowCI);
|
|
10
|
+
}
|
|
11
|
+
export async function stageActiveTaskArtifactsFromAllowTasks(opts) {
|
|
12
|
+
if (!opts.allowTasks)
|
|
13
|
+
return [];
|
|
14
|
+
const changedPaths = await opts.ctx.git.statusChangedPaths();
|
|
15
|
+
const taskArtifactPaths = changedPaths.filter((relPath) => isTaskLocalAdvancePath({
|
|
16
|
+
workflowDir: opts.ctx.config.paths.workflow_dir,
|
|
17
|
+
taskId: opts.taskId,
|
|
18
|
+
tasksPath: opts.ctx.config.paths.tasks_path,
|
|
19
|
+
relPath,
|
|
20
|
+
}));
|
|
21
|
+
if (taskArtifactPaths.length === 0)
|
|
22
|
+
return [];
|
|
23
|
+
const unique = [...new Set(taskArtifactPaths)].toSorted((a, b) => a.localeCompare(b));
|
|
24
|
+
await opts.ctx.git.stage(unique);
|
|
25
|
+
return unique;
|
|
26
|
+
}
|
|
27
|
+
export async function stageCloseCommitPaths(opts) {
|
|
28
|
+
const stagePaths = new Set([opts.readmeRel]);
|
|
29
|
+
if (opts.allowPolicy) {
|
|
30
|
+
const changedPaths = await opts.ctx.git.statusChangedPaths();
|
|
31
|
+
for (const relPath of changedPaths) {
|
|
32
|
+
if (protectedPathKindForFile({
|
|
33
|
+
filePath: relPath,
|
|
34
|
+
tasksPath: opts.ctx.config.paths.tasks_path,
|
|
35
|
+
workflowDir: opts.ctx.config.paths.workflow_dir,
|
|
36
|
+
taskId: opts.taskId,
|
|
37
|
+
}) === "policy") {
|
|
38
|
+
stagePaths.add(relPath);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
await opts.ctx.git.stage([...stagePaths].toSorted((a, b) => a.localeCompare(b)));
|
|
43
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commit.d.ts","sourceRoot":"","sources":["../../../../src/commands/guard/impl/commit.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"commit.d.ts","sourceRoot":"","sources":["../../../../src/commands/guard/impl/commit.ts"],"names":[],"mappings":"AAKA,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,8BAA8B,CAAC;AAsBtC,wBAAsB,SAAS,CAAC,IAAI,EAAE;IACpC,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,OAAO,CAAC;IACf,kBAAkB,EAAE,OAAO,CAAC;IAC5B,cAAc,EAAE,OAAO,CAAC;IACxB,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,yBAAyB,CAAC,EAAE,OAAO,CAAC;CACrC,GAAG,OAAO,CAAC,MAAM,CAAC,CAwIlB"}
|
|
@@ -1,14 +1,8 @@
|
|
|
1
|
-
import { mkdir, rm, writeFile } from "node:fs/promises";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { buildTaskArtifactRefreshCommitSubject } from "@agentplaneorg/core/commit";
|
|
4
|
-
import { resolveTaskIndexPath } from "../../../backends/task-index.js";
|
|
5
1
|
import { mapCoreError } from "../../../cli/error-map.js";
|
|
6
2
|
import { infoMessage, successMessage } from "../../../cli/output.js";
|
|
7
3
|
import { withDiagnosticContext } from "../../shared/diagnostics.js";
|
|
8
4
|
import { CliError } from "../../../shared/errors.js";
|
|
9
|
-
import { protectedPathKindForFile } from "../../../shared/protected-paths.js";
|
|
10
5
|
import { refreshBranchPrArtifactsAfterTaskCommit } from "../../shared/post-commit-pr-artifacts.js";
|
|
11
|
-
import { isTaskLocalAdvancePath } from "../../shared/task-local-freshness.js";
|
|
12
6
|
import { loadCommandContext, loadTaskFromContext, } from "../../shared/task-backend.js";
|
|
13
7
|
import { execFileAsync } from "@agentplaneorg/core/process";
|
|
14
8
|
import { gitEnv } from "@agentplaneorg/core/git";
|
|
@@ -18,141 +12,9 @@ import { resolveIgnoredDirectCloseDirtyPaths } from "./close-dirt.js";
|
|
|
18
12
|
import { buildCloseCommitMessage, taskReadmePathForTask } from "./close-message.js";
|
|
19
13
|
import { asCommitFailure } from "./commit-diagnostics.js";
|
|
20
14
|
import { buildGitCommitEnv, resolveCanonicalGitIdentity } from "./env.js";
|
|
15
|
+
import { commitRefreshedTaskArtifacts, formatCommitRef, refreshBranchPrArtifactsForCloseCommit, resetRebuildableTaskIndexCache, } from "./commit-refresh.js";
|
|
16
|
+
import { hasExplicitCommitScope, stageActiveTaskArtifactsFromAllowTasks, stageCloseCommitPaths, } from "./commit-stage.js";
|
|
21
17
|
import { guardCommitCheck } from "./policy.js";
|
|
22
|
-
async function resetRebuildableTaskIndexCache(ctx) {
|
|
23
|
-
const gitRoot = path.resolve(ctx.resolvedProject.gitRoot);
|
|
24
|
-
const workflowDirAbs = path.resolve(gitRoot, ctx.config.paths.workflow_dir);
|
|
25
|
-
const cachePath = path.resolve(resolveTaskIndexPath(workflowDirAbs));
|
|
26
|
-
const relativeCachePath = path.relative(gitRoot, cachePath);
|
|
27
|
-
if (!relativeCachePath || relativeCachePath.startsWith(".."))
|
|
28
|
-
return;
|
|
29
|
-
try {
|
|
30
|
-
await execFileAsync("git", ["ls-files", "--error-unmatch", "--", relativeCachePath], {
|
|
31
|
-
cwd: gitRoot,
|
|
32
|
-
env: gitEnv(),
|
|
33
|
-
});
|
|
34
|
-
const gitPath = relativeCachePath.split(path.sep).join("/");
|
|
35
|
-
const cacheBlob = await execFileAsync("git", ["show", `HEAD:${gitPath}`], {
|
|
36
|
-
cwd: gitRoot,
|
|
37
|
-
env: gitEnv(),
|
|
38
|
-
});
|
|
39
|
-
await mkdir(path.dirname(cachePath), { recursive: true });
|
|
40
|
-
await writeFile(cachePath, cacheBlob.stdout, "utf8");
|
|
41
|
-
await execFileAsync("git", ["restore", "--staged", "--", relativeCachePath], {
|
|
42
|
-
cwd: gitRoot,
|
|
43
|
-
env: gitEnv(),
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
catch {
|
|
47
|
-
await rm(cachePath, { force: true });
|
|
48
|
-
}
|
|
49
|
-
ctx.git.invalidateStatus();
|
|
50
|
-
}
|
|
51
|
-
async function stageCloseCommitPaths(opts) {
|
|
52
|
-
const stagePaths = new Set([opts.readmeRel]);
|
|
53
|
-
if (opts.allowPolicy) {
|
|
54
|
-
const changedPaths = await opts.ctx.git.statusChangedPaths();
|
|
55
|
-
for (const relPath of changedPaths) {
|
|
56
|
-
if (protectedPathKindForFile({
|
|
57
|
-
filePath: relPath,
|
|
58
|
-
tasksPath: opts.ctx.config.paths.tasks_path,
|
|
59
|
-
workflowDir: opts.ctx.config.paths.workflow_dir,
|
|
60
|
-
taskId: opts.taskId,
|
|
61
|
-
}) === "policy") {
|
|
62
|
-
stagePaths.add(relPath);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
await opts.ctx.git.stage([...stagePaths].toSorted((a, b) => a.localeCompare(b)));
|
|
67
|
-
}
|
|
68
|
-
async function commitRefreshedTaskArtifacts(opts) {
|
|
69
|
-
const changedPaths = await opts.ctx.git.statusChangedPaths();
|
|
70
|
-
const taskArtifactPaths = changedPaths.filter((relPath) => isTaskLocalAdvancePath({
|
|
71
|
-
workflowDir: opts.ctx.config.paths.workflow_dir,
|
|
72
|
-
taskId: opts.taskId,
|
|
73
|
-
tasksPath: opts.ctx.config.paths.tasks_path,
|
|
74
|
-
relPath,
|
|
75
|
-
}));
|
|
76
|
-
if (taskArtifactPaths.length === 0)
|
|
77
|
-
return null;
|
|
78
|
-
await stageAllowlist({
|
|
79
|
-
ctx: opts.ctx,
|
|
80
|
-
allow: [],
|
|
81
|
-
allowTasks: true,
|
|
82
|
-
allowPolicy: false,
|
|
83
|
-
allowConfig: false,
|
|
84
|
-
allowHooks: false,
|
|
85
|
-
allowCI: false,
|
|
86
|
-
tasksPath: opts.ctx.config.paths.tasks_path,
|
|
87
|
-
workflowDir: opts.ctx.config.paths.workflow_dir,
|
|
88
|
-
taskId: opts.taskId,
|
|
89
|
-
allowTaskOnly: true,
|
|
90
|
-
emptyAllowMessage: "PR artifact refresh produced no task-local files to stage for the follow-up commit.",
|
|
91
|
-
noMatchMessage: "PR artifact refresh produced changes outside the active task artifact scope; inspect the working tree before retrying the commit flow.",
|
|
92
|
-
});
|
|
93
|
-
const message = buildTaskArtifactRefreshCommitSubject({
|
|
94
|
-
taskId: opts.taskId,
|
|
95
|
-
baseSubject: opts.sourceMessage,
|
|
96
|
-
});
|
|
97
|
-
await guardCommitCheck({
|
|
98
|
-
ctx: opts.ctx,
|
|
99
|
-
cwd: opts.cwd,
|
|
100
|
-
rootOverride: opts.rootOverride,
|
|
101
|
-
baseBranchOverride: null,
|
|
102
|
-
taskId: opts.taskId,
|
|
103
|
-
message,
|
|
104
|
-
allow: [],
|
|
105
|
-
allowBase: false,
|
|
106
|
-
allowTasks: true,
|
|
107
|
-
allowPolicy: false,
|
|
108
|
-
allowConfig: false,
|
|
109
|
-
allowHooks: false,
|
|
110
|
-
allowCI: false,
|
|
111
|
-
requireClean: true,
|
|
112
|
-
quiet: opts.quiet,
|
|
113
|
-
});
|
|
114
|
-
const env = buildGitCommitEnv({
|
|
115
|
-
taskId: opts.taskId,
|
|
116
|
-
allowTasks: true,
|
|
117
|
-
allowBase: false,
|
|
118
|
-
allowPolicy: false,
|
|
119
|
-
allowConfig: false,
|
|
120
|
-
allowHooks: false,
|
|
121
|
-
allowCI: false,
|
|
122
|
-
gitIdentity: await resolveCanonicalGitIdentity(),
|
|
123
|
-
});
|
|
124
|
-
await opts.ctx.git.commit({ message, env });
|
|
125
|
-
return await opts.ctx.git.headHashSubject();
|
|
126
|
-
}
|
|
127
|
-
function hasExplicitCommitScope(opts) {
|
|
128
|
-
return (opts.allow.some((prefix) => prefix.trim().length > 0) ||
|
|
129
|
-
opts.allowTasks ||
|
|
130
|
-
opts.allowPolicy ||
|
|
131
|
-
opts.allowConfig ||
|
|
132
|
-
opts.allowHooks ||
|
|
133
|
-
opts.allowCI);
|
|
134
|
-
}
|
|
135
|
-
function formatCommitRef(commit) {
|
|
136
|
-
if (!commit)
|
|
137
|
-
return "";
|
|
138
|
-
return `${commit.hash?.slice(0, 12) ?? ""} ${commit.subject ?? ""}`.trim();
|
|
139
|
-
}
|
|
140
|
-
async function stageActiveTaskArtifactsFromAllowTasks(opts) {
|
|
141
|
-
if (!opts.allowTasks)
|
|
142
|
-
return [];
|
|
143
|
-
const changedPaths = await opts.ctx.git.statusChangedPaths();
|
|
144
|
-
const taskArtifactPaths = changedPaths.filter((relPath) => isTaskLocalAdvancePath({
|
|
145
|
-
workflowDir: opts.ctx.config.paths.workflow_dir,
|
|
146
|
-
taskId: opts.taskId,
|
|
147
|
-
tasksPath: opts.ctx.config.paths.tasks_path,
|
|
148
|
-
relPath,
|
|
149
|
-
}));
|
|
150
|
-
if (taskArtifactPaths.length === 0)
|
|
151
|
-
return [];
|
|
152
|
-
const unique = [...new Set(taskArtifactPaths)].toSorted((a, b) => a.localeCompare(b));
|
|
153
|
-
await opts.ctx.git.stage(unique);
|
|
154
|
-
return unique;
|
|
155
|
-
}
|
|
156
18
|
export async function cmdCommit(opts) {
|
|
157
19
|
try {
|
|
158
20
|
const ctx = opts.ctx ??
|
|
@@ -321,16 +183,14 @@ async function cmdCloseCommit(opts) {
|
|
|
321
183
|
return 0;
|
|
322
184
|
}
|
|
323
185
|
if (opts.closeStageTaskArtifacts === true) {
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
}
|
|
333
|
-
opts.ctx.git.invalidateStatus();
|
|
186
|
+
await refreshBranchPrArtifactsForCloseCommit({
|
|
187
|
+
ctx: opts.ctx,
|
|
188
|
+
cwd: opts.cwd,
|
|
189
|
+
rootOverride: opts.rootOverride,
|
|
190
|
+
taskId: opts.taskId,
|
|
191
|
+
quiet: opts.quiet,
|
|
192
|
+
refreshTaskArtifacts: opts.closeRefreshTaskArtifacts !== false,
|
|
193
|
+
});
|
|
334
194
|
}
|
|
335
195
|
await (opts.closeStageTaskArtifacts === true
|
|
336
196
|
? stageAllowlist({
|
|
@@ -1,30 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
3
|
-
export
|
|
4
|
-
export
|
|
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":"
|
|
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
|
+
}
|