@webpresso/agent-kit 3.3.1 → 3.3.3
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/catalog/AGENTS.md.tpl +3 -5
- package/catalog/agent/rules/pre-implementation.md +15 -8
- package/catalog/agent/skills/ultragoal/SKILL.md +5 -18
- package/catalog/agent/skills/verify/SKILL.md +12 -12
- package/catalog/compose/admin-blocks-registry.json +659 -0
- package/dist/esm/blueprint/core/parser.js +2 -4
- package/dist/esm/blueprint/core/validation/criteria.js +2 -1
- package/dist/esm/blueprint/core/validation/task-blocks.js +7 -1
- package/dist/esm/blueprint/lifecycle/review-provenance.js +85 -30
- package/dist/esm/blueprint/markdown/task-heading.d.ts +21 -0
- package/dist/esm/blueprint/markdown/task-heading.js +25 -0
- package/dist/esm/blueprint/trust/command-runner.d.ts +40 -0
- package/dist/esm/blueprint/trust/command-runner.js +265 -41
- package/dist/esm/build/cli-mcp-parity.js +6 -0
- package/dist/esm/build/package-manifest.js +7 -2
- package/dist/esm/ci/native-session-memory-cache.d.ts +2 -1
- package/dist/esm/ci/native-session-memory-cache.js +2 -1
- package/dist/esm/ci/release-progress.d.ts +37 -0
- package/dist/esm/ci/release-progress.js +139 -0
- package/dist/esm/cli/cli.d.ts +1 -1
- package/dist/esm/cli/cli.js +9 -0
- package/dist/esm/cli/commands/audit-core.js +9 -1
- package/dist/esm/cli/commands/audit.js +16 -5
- package/dist/esm/cli/commands/blueprint/mutations.js +2 -3
- package/dist/esm/cli/commands/init/mcp-spec.d.ts +18 -3
- package/dist/esm/cli/commands/init/mcp-spec.js +54 -6
- package/dist/esm/cli/commands/init/scaffold-agents-md.js +5 -7
- package/dist/esm/cli/commands/package-manager.js +8 -2
- package/dist/esm/cli/commands/release-progress.d.ts +53 -0
- package/dist/esm/cli/commands/release-progress.js +155 -0
- package/dist/esm/cli/commands/review.js +74 -11
- package/dist/esm/cli/utils.d.ts +8 -1
- package/dist/esm/cli/utils.js +12 -2
- package/dist/esm/compose/compose.d.ts +38 -0
- package/dist/esm/compose/compose.js +143 -0
- package/dist/esm/compose/escape-html.d.ts +5 -0
- package/dist/esm/compose/escape-html.js +12 -0
- package/dist/esm/compose/ops-report-render.d.ts +5 -0
- package/dist/esm/compose/ops-report-render.js +71 -0
- package/dist/esm/compose/ops-report-schema.d.ts +42 -0
- package/dist/esm/compose/ops-report-schema.js +46 -0
- package/dist/esm/compose/preview.d.ts +14 -0
- package/dist/esm/compose/preview.js +32 -0
- package/dist/esm/compose/registry-resolve.d.ts +47 -0
- package/dist/esm/compose/registry-resolve.js +133 -0
- package/dist/esm/git/changed-files.d.ts +20 -0
- package/dist/esm/git/changed-files.js +63 -0
- package/dist/esm/hooks/pretool-guard/validators/plan-frontmatter.js +3 -2
- package/dist/esm/hooks/stop/qa-changed-files.js +6 -1
- package/dist/esm/mcp/blueprint/handlers/document-mutations.js +2 -1
- package/dist/esm/mcp/blueprint/handlers/task-advance.js +2 -12
- package/dist/esm/mcp/blueprint/handlers/validate.js +6 -0
- package/dist/esm/mcp/tools/_names.d.ts +1 -1
- package/dist/esm/mcp/tools/_names.js +4 -0
- package/dist/esm/mcp/tools/_registry.js +8 -0
- package/dist/esm/mcp/tools/release-progress.d.ts +9 -0
- package/dist/esm/mcp/tools/release-progress.js +110 -0
- package/dist/esm/mcp/tools/wp-ui-blocks-list.d.ts +3 -0
- package/dist/esm/mcp/tools/wp-ui-blocks-list.js +43 -0
- package/dist/esm/mcp/tools/wp-ui-compose.d.ts +3 -0
- package/dist/esm/mcp/tools/wp-ui-compose.js +62 -0
- package/dist/esm/mcp/tools/wp-ui-preview.d.ts +3 -0
- package/dist/esm/mcp/tools/wp-ui-preview.js +52 -0
- package/dist/esm/package.json +2 -0
- package/dist/esm/review/delivery-verifier.d.ts +33 -2
- package/dist/esm/review/delivery-verifier.js +130 -24
- package/dist/esm/review/execution/review-checkout.d.ts +1 -0
- package/dist/esm/review/execution/review-checkout.js +386 -23
- package/dist/esm/review/execution/sandbox/adapter.d.ts +37 -0
- package/dist/esm/review/execution/sandbox/adapter.js +39 -0
- package/dist/esm/review/execution/sandbox/env.d.ts +12 -0
- package/dist/esm/review/execution/sandbox/env.js +37 -0
- package/dist/esm/review/execution/sandbox/index.d.ts +5 -0
- package/dist/esm/review/execution/sandbox/index.js +4 -0
- package/dist/esm/review/execution/sandbox/policy.d.ts +19 -0
- package/dist/esm/review/execution/sandbox/policy.js +95 -0
- package/dist/esm/review/execution/sandbox/probe.d.ts +20 -0
- package/dist/esm/review/execution/sandbox/probe.js +97 -0
- package/dist/esm/review/execution/sandbox/shell-quote.d.ts +14 -0
- package/dist/esm/review/execution/sandbox/shell-quote.js +18 -0
- package/dist/esm/review/execution/sandbox/tmpdir.d.ts +9 -0
- package/dist/esm/review/execution/sandbox/tmpdir.js +36 -0
- package/dist/esm/review/execution/sandbox/types.d.ts +31 -0
- package/dist/esm/review/execution/sandbox/types.js +6 -0
- package/dist/esm/review/execution/supervisor.js +44 -5
- package/dist/esm/review/execution/types.d.ts +2 -0
- package/package.json +24 -12
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Classify a GitHub Actions Release run into operator-facing progress phases.
|
|
3
|
+
*
|
|
4
|
+
* After Version Packages merge, agents must not sit on silent `npm view` polls:
|
|
5
|
+
* merge, native matrix, and npm publish are separate states. This pure helper
|
|
6
|
+
* maps job list snapshots (from `gh run view --json jobs`) into those states.
|
|
7
|
+
*/
|
|
8
|
+
export type ReleaseProgressPhase = "detect" | "native-matrix" | "publish" | "done" | "failed";
|
|
9
|
+
export interface ReleaseJobSnapshot {
|
|
10
|
+
readonly name: string;
|
|
11
|
+
readonly status: string;
|
|
12
|
+
readonly conclusion: string | null | undefined;
|
|
13
|
+
}
|
|
14
|
+
export interface ReleaseProgress {
|
|
15
|
+
readonly phase: ReleaseProgressPhase;
|
|
16
|
+
readonly detail: string;
|
|
17
|
+
readonly native: {
|
|
18
|
+
readonly done: number;
|
|
19
|
+
readonly total: number;
|
|
20
|
+
readonly failed: number;
|
|
21
|
+
readonly inProgress: number;
|
|
22
|
+
};
|
|
23
|
+
readonly publishRunning: boolean;
|
|
24
|
+
readonly publishDone: boolean;
|
|
25
|
+
readonly publishFailed: boolean;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Classify release workflow jobs into a single progress phase for agent/ops reporting.
|
|
29
|
+
*/
|
|
30
|
+
export declare function classifyReleaseRunProgress(jobs: readonly ReleaseJobSnapshot[]): ReleaseProgress;
|
|
31
|
+
/** Format one line for agent/ops logs (merge vs matrix vs publish). */
|
|
32
|
+
export declare function formatReleaseProgressLine(progress: ReleaseProgress): string;
|
|
33
|
+
/**
|
|
34
|
+
* Parse `gh run view <id> --json jobs` (or full run object with `jobs`) into snapshots.
|
|
35
|
+
* Production CLI and tests share this path so classification is never reimplemented.
|
|
36
|
+
*/
|
|
37
|
+
export declare function jobsFromGhRunViewJson(payload: unknown): ReleaseJobSnapshot[];
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Classify a GitHub Actions Release run into operator-facing progress phases.
|
|
3
|
+
*
|
|
4
|
+
* After Version Packages merge, agents must not sit on silent `npm view` polls:
|
|
5
|
+
* merge, native matrix, and npm publish are separate states. This pure helper
|
|
6
|
+
* maps job list snapshots (from `gh run view --json jobs`) into those states.
|
|
7
|
+
*/
|
|
8
|
+
const NATIVE_JOB_PREFIX = "Session memory native";
|
|
9
|
+
function isNativeJob(name) {
|
|
10
|
+
return name.startsWith(NATIVE_JOB_PREFIX);
|
|
11
|
+
}
|
|
12
|
+
function isFailure(conclusion) {
|
|
13
|
+
return conclusion === "failure" || conclusion === "cancelled" || conclusion === "timed_out";
|
|
14
|
+
}
|
|
15
|
+
function isSuccess(conclusion) {
|
|
16
|
+
return conclusion === "success" || conclusion === "skipped";
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Classify release workflow jobs into a single progress phase for agent/ops reporting.
|
|
20
|
+
*/
|
|
21
|
+
export function classifyReleaseRunProgress(jobs) {
|
|
22
|
+
const nativeJobs = jobs.filter((job) => isNativeJob(job.name));
|
|
23
|
+
const detect = jobs.find((job) => job.name === "Detect publishable versions");
|
|
24
|
+
const release = jobs.find((job) => job.name === "Release");
|
|
25
|
+
const nativeDone = nativeJobs.filter((job) => job.status === "completed" && isSuccess(job.conclusion)).length;
|
|
26
|
+
const nativeFailed = nativeJobs.filter((job) => job.status === "completed" && isFailure(job.conclusion)).length;
|
|
27
|
+
const nativeInProgress = nativeJobs.filter((job) => job.status === "in_progress").length;
|
|
28
|
+
const native = {
|
|
29
|
+
done: nativeDone,
|
|
30
|
+
total: nativeJobs.length,
|
|
31
|
+
failed: nativeFailed,
|
|
32
|
+
inProgress: nativeInProgress,
|
|
33
|
+
};
|
|
34
|
+
const publishRunning = release?.status === "in_progress";
|
|
35
|
+
const publishDone = release?.status === "completed" && isSuccess(release.conclusion);
|
|
36
|
+
const publishFailed = release?.status === "completed" && isFailure(release.conclusion);
|
|
37
|
+
if (nativeFailed > 0 || publishFailed) {
|
|
38
|
+
return {
|
|
39
|
+
phase: "failed",
|
|
40
|
+
detail: nativeFailed > 0
|
|
41
|
+
? `Native matrix failed (${nativeFailed} cell(s))`
|
|
42
|
+
: `Release/publish job failed (${release?.conclusion ?? "unknown"})`,
|
|
43
|
+
native,
|
|
44
|
+
publishRunning,
|
|
45
|
+
publishDone,
|
|
46
|
+
publishFailed,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
if (publishDone) {
|
|
50
|
+
return {
|
|
51
|
+
phase: "done",
|
|
52
|
+
detail: "Release job completed successfully (check npm for version)",
|
|
53
|
+
native,
|
|
54
|
+
publishRunning,
|
|
55
|
+
publishDone,
|
|
56
|
+
publishFailed,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
if (publishRunning || (native.total > 0 && nativeDone === native.total && release)) {
|
|
60
|
+
return {
|
|
61
|
+
phase: "publish",
|
|
62
|
+
detail: publishRunning
|
|
63
|
+
? "Native matrix complete; Release/publish job in progress"
|
|
64
|
+
: "Native matrix complete; waiting for Release job",
|
|
65
|
+
native,
|
|
66
|
+
publishRunning,
|
|
67
|
+
publishDone,
|
|
68
|
+
publishFailed,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
if (native.total > 0 && (nativeInProgress > 0 || nativeDone < native.total)) {
|
|
72
|
+
return {
|
|
73
|
+
phase: "native-matrix",
|
|
74
|
+
detail: `Building session-memory natives ${nativeDone}/${native.total} complete` +
|
|
75
|
+
(nativeInProgress > 0 ? ` (${nativeInProgress} in progress)` : ""),
|
|
76
|
+
native,
|
|
77
|
+
publishRunning,
|
|
78
|
+
publishDone,
|
|
79
|
+
publishFailed,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
if (detect && detect.status !== "completed") {
|
|
83
|
+
return {
|
|
84
|
+
phase: "detect",
|
|
85
|
+
detail: "Detecting whether this run will publish",
|
|
86
|
+
native,
|
|
87
|
+
publishRunning,
|
|
88
|
+
publishDone,
|
|
89
|
+
publishFailed,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
phase: "detect",
|
|
94
|
+
detail: "Release run starting",
|
|
95
|
+
native,
|
|
96
|
+
publishRunning,
|
|
97
|
+
publishDone,
|
|
98
|
+
publishFailed,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/** Format one line for agent/ops logs (merge vs matrix vs publish). */
|
|
102
|
+
export function formatReleaseProgressLine(progress) {
|
|
103
|
+
return `release-progress phase=${progress.phase} native=${progress.native.done}/${progress.native.total} ${progress.detail}`;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Parse `gh run view <id> --json jobs` (or full run object with `jobs`) into snapshots.
|
|
107
|
+
* Production CLI and tests share this path so classification is never reimplemented.
|
|
108
|
+
*/
|
|
109
|
+
export function jobsFromGhRunViewJson(payload) {
|
|
110
|
+
if (payload == null || typeof payload !== "object") {
|
|
111
|
+
throw new Error("gh run view JSON must be an object with a jobs array");
|
|
112
|
+
}
|
|
113
|
+
const record = payload;
|
|
114
|
+
const jobsRaw = Array.isArray(payload)
|
|
115
|
+
? payload
|
|
116
|
+
: Array.isArray(record.jobs)
|
|
117
|
+
? record.jobs
|
|
118
|
+
: null;
|
|
119
|
+
if (!jobsRaw) {
|
|
120
|
+
throw new Error("gh run view JSON must include a jobs array");
|
|
121
|
+
}
|
|
122
|
+
return jobsRaw.map((entry, index) => {
|
|
123
|
+
if (entry == null || typeof entry !== "object") {
|
|
124
|
+
throw new Error(`jobs[${index}] must be an object`);
|
|
125
|
+
}
|
|
126
|
+
const job = entry;
|
|
127
|
+
const name = typeof job.name === "string" ? job.name : "";
|
|
128
|
+
const status = typeof job.status === "string" ? job.status : "";
|
|
129
|
+
if (!name || !status) {
|
|
130
|
+
throw new Error(`jobs[${index}] requires string name and status`);
|
|
131
|
+
}
|
|
132
|
+
const conclusion = job.conclusion === null || job.conclusion === undefined
|
|
133
|
+
? null
|
|
134
|
+
: typeof job.conclusion === "string"
|
|
135
|
+
? job.conclusion
|
|
136
|
+
: null;
|
|
137
|
+
return { name, status, conclusion };
|
|
138
|
+
});
|
|
139
|
+
}
|
package/dist/esm/cli/cli.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Lazy-loads subcommand modules based on the first argv to keep startup
|
|
6
6
|
* cheap. Modeled on apps/cli-wp/src/cli.ts.
|
|
7
7
|
*/
|
|
8
|
-
declare const SUPPORTED_COMMANDS: readonly ["blueprint", "browser", "dash", "dash-helper-start", "dash-helper-complete", "claude", "codex", "grok", "opencode", "yolo", "config", "secrets", "roadmap", "status", "review", "sync", "audit", "qa", "ultragoal", "compile", "rule", "skill", "skills", "docs", "setup", "init", "dev", "deploy", "preview", "cleanup", "migrate", "doctor", "err", "test", "e2e", "ci", "ci-preflight", "public:readiness", "typecheck", "lint", "format", "rust-check", "logs", "session-id", "session-info", "session", "tech-debt", "pr", "fleet", "worktree", "mcp", "hook", "hooks", "self-install-guard", "optional-tool-refresh", "gain", "bench", "install", "add", "remove", "update", "exec", "run"];
|
|
8
|
+
declare const SUPPORTED_COMMANDS: readonly ["blueprint", "browser", "dash", "dash-helper-start", "dash-helper-complete", "claude", "codex", "grok", "opencode", "yolo", "config", "secrets", "roadmap", "status", "review", "sync", "audit", "qa", "ultragoal", "compile", "rule", "skill", "skills", "docs", "setup", "init", "dev", "deploy", "preview", "cleanup", "migrate", "doctor", "err", "test", "e2e", "ci", "ci-preflight", "release-progress", "public:readiness", "typecheck", "lint", "format", "rust-check", "logs", "session-id", "session-info", "session", "tech-debt", "pr", "fleet", "worktree", "mcp", "hook", "hooks", "self-install-guard", "optional-tool-refresh", "gain", "bench", "install", "add", "remove", "update", "exec", "run"];
|
|
9
9
|
export type SupportedCommand = (typeof SUPPORTED_COMMANDS)[number];
|
|
10
10
|
type RootHelpEntry = {
|
|
11
11
|
readonly command: string;
|
package/dist/esm/cli/cli.js
CHANGED
|
@@ -55,6 +55,7 @@ const SUPPORTED_COMMANDS = [
|
|
|
55
55
|
"e2e",
|
|
56
56
|
"ci",
|
|
57
57
|
"ci-preflight",
|
|
58
|
+
"release-progress",
|
|
58
59
|
"public:readiness",
|
|
59
60
|
"typecheck",
|
|
60
61
|
"lint",
|
|
@@ -118,6 +119,10 @@ const ROOT_HELP_CORE_ENTRIES = [
|
|
|
118
119
|
command: "ci-preflight",
|
|
119
120
|
description: "Run the locally-runnable required CI checks fail-fast (the pre-push gate)",
|
|
120
121
|
},
|
|
122
|
+
{
|
|
123
|
+
command: "release-progress",
|
|
124
|
+
description: "Report Release workflow phase (detect / native-matrix / publish) instead of silent npm view waits",
|
|
125
|
+
},
|
|
121
126
|
{
|
|
122
127
|
command: "public:readiness",
|
|
123
128
|
description: "Run the public package readiness gate through the portable wp surface",
|
|
@@ -375,6 +380,10 @@ const COMMAND_REGISTRARS = {
|
|
|
375
380
|
const { registerCiPreflightCommand } = await import("./commands/ci-preflight.js");
|
|
376
381
|
registerCiPreflightCommand(cli);
|
|
377
382
|
},
|
|
383
|
+
"release-progress": async (cli) => {
|
|
384
|
+
const { registerReleaseProgressCommand } = await import("./commands/release-progress.js");
|
|
385
|
+
registerReleaseProgressCommand(cli);
|
|
386
|
+
},
|
|
378
387
|
"public:readiness": async (cli) => {
|
|
379
388
|
const { registerPublicReadinessCommand } = await import("./commands/public-readiness.js");
|
|
380
389
|
registerPublicReadinessCommand(cli);
|
|
@@ -79,7 +79,15 @@ export async function runAuditDispatch(auditKind, targets, options, deps) {
|
|
|
79
79
|
case "blueprint-pr-coverage": {
|
|
80
80
|
const { auditBlueprintPrCoverage } = await import("#audit/blueprint-pr-coverage");
|
|
81
81
|
const root = options.root ?? target ?? deps.root;
|
|
82
|
-
const
|
|
82
|
+
const explicitBaseRef = options.baseRef ?? options.base;
|
|
83
|
+
// Same pinned-base hazard as the branch-scoped audits: CI's
|
|
84
|
+
// `github.event.pull_request.base.sha` stops being the fork point once the
|
|
85
|
+
// branch is rebased, and this audit diffs `<baseRef>...HEAD`. Narrow it to
|
|
86
|
+
// the real fork point so coverage is judged on this PR's own files.
|
|
87
|
+
const { resolveBranchDiffBase } = await import("#git/changed-files");
|
|
88
|
+
const baseRef = explicitBaseRef
|
|
89
|
+
? resolveBranchDiffBase(root, explicitBaseRef)
|
|
90
|
+
: explicitBaseRef;
|
|
83
91
|
const result = auditBlueprintPrCoverage(root, { baseRef, headRef: options.headRef });
|
|
84
92
|
return { kind: "repo-result", name: "blueprint-pr-coverage", result };
|
|
85
93
|
}
|
|
@@ -9,7 +9,7 @@ import { STRYKER_COMMAND } from "#audit/run-stryker.js";
|
|
|
9
9
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
10
10
|
import path from "node:path";
|
|
11
11
|
import { addAffectedOptions, resolveAffectedTargets } from "#git/affected";
|
|
12
|
-
import { defaultBranchBaseRef, getBranchRemovedFiles, getStagedRemovedFiles, } from "#git/changed-files";
|
|
12
|
+
import { defaultBranchBaseRef, getBranchRemovedFiles, getStagedRemovedFiles, resolveBranchDiffBase, } from "#git/changed-files";
|
|
13
13
|
import { runAuditDispatch } from "#cli/commands/audit-core.js";
|
|
14
14
|
import { createCliLogSink } from "#cli/commands/quality-log-store.js";
|
|
15
15
|
import { emitCliCommandOutput, runLoggedChildCommand } from "#cli/commands/quality-runner.js";
|
|
@@ -284,6 +284,17 @@ export function registerAuditCommand(cli) {
|
|
|
284
284
|
let dispatchOptions = options;
|
|
285
285
|
let auditScope = "full";
|
|
286
286
|
let changeRemovesFile = false;
|
|
287
|
+
// A caller-supplied `--base` is a PINNED sha (CI passes
|
|
288
|
+
// `github.event.pull_request.base.sha`, which does not advance with the
|
|
289
|
+
// base branch). After a rebase it stops being the fork point, so scoping
|
|
290
|
+
// off it silently absorbs everything merged into the base branch since
|
|
291
|
+
// the PR opened. Narrow it to the real fork point once, and use that one
|
|
292
|
+
// value everywhere the branch scope is derived so the affected file set,
|
|
293
|
+
// the removal probe, and the audit's own base-vs-head range agree.
|
|
294
|
+
const explicitBaseRef = options.baseRef ?? options.base;
|
|
295
|
+
const branchBaseRef = branch && explicitBaseRef
|
|
296
|
+
? resolveBranchDiffBase(auditRoot, explicitBaseRef)
|
|
297
|
+
: explicitBaseRef;
|
|
287
298
|
if (affected || branch) {
|
|
288
299
|
if (kind &&
|
|
289
300
|
AUDIT_KINDS.includes(kind) &&
|
|
@@ -309,7 +320,7 @@ export function registerAuditCommand(cli) {
|
|
|
309
320
|
cwd: auditRoot,
|
|
310
321
|
affected,
|
|
311
322
|
branch,
|
|
312
|
-
baseRef:
|
|
323
|
+
baseRef: branchBaseRef,
|
|
313
324
|
explicitTargets: [],
|
|
314
325
|
policy: "fail-closed",
|
|
315
326
|
mapChangedFiles: (files) => files,
|
|
@@ -360,7 +371,7 @@ export function registerAuditCommand(cli) {
|
|
|
360
371
|
changeRemovesFile = affected
|
|
361
372
|
? affectedChangeRemovesFile(auditRoot, {
|
|
362
373
|
branch,
|
|
363
|
-
baseRef:
|
|
374
|
+
baseRef: branchBaseRef,
|
|
364
375
|
})
|
|
365
376
|
: false;
|
|
366
377
|
if (resolution.kind === "empty" && !changeRemovesFile) {
|
|
@@ -392,7 +403,7 @@ export function registerAuditCommand(cli) {
|
|
|
392
403
|
changedOnly: true,
|
|
393
404
|
affectedFiles: [],
|
|
394
405
|
root: options.root ?? resolution.cwd,
|
|
395
|
-
baseRef:
|
|
406
|
+
baseRef: branchBaseRef,
|
|
396
407
|
};
|
|
397
408
|
}
|
|
398
409
|
if (resolution.kind === "scoped") {
|
|
@@ -404,7 +415,7 @@ export function registerAuditCommand(cli) {
|
|
|
404
415
|
changedOnly: true,
|
|
405
416
|
affectedFiles: [...resolution.targets],
|
|
406
417
|
root: options.root ?? resolution.cwd,
|
|
407
|
-
baseRef:
|
|
418
|
+
baseRef: branchBaseRef,
|
|
408
419
|
};
|
|
409
420
|
}
|
|
410
421
|
}
|
|
@@ -17,7 +17,7 @@ import { randomUUID } from "node:crypto";
|
|
|
17
17
|
import { tmpdir } from "node:os";
|
|
18
18
|
import path from "node:path";
|
|
19
19
|
import { parseBlueprint } from "#core/parser";
|
|
20
|
-
import {
|
|
20
|
+
import { buildTaskHeaderRegexForId } from "#markdown/task-heading";
|
|
21
21
|
import { openDb } from "#db/connection.js";
|
|
22
22
|
import { resolveBlueprintProjectionDbPath, withMarkdownWriteLock } from "#db/paths.js";
|
|
23
23
|
import { getBlueprintDocumentPaths } from "#utils/document-paths.js";
|
|
@@ -209,8 +209,7 @@ function upsertCompletedAt(content, isoDate) {
|
|
|
209
209
|
* Returns { lineIndex, currentStatus } or null if not found.
|
|
210
210
|
*/
|
|
211
211
|
function findTaskStatusLine(lines, taskId) {
|
|
212
|
-
const
|
|
213
|
-
const taskPattern = new RegExp(`^####\\s+(?:\\[[^\\]]+\\]\\s+)?Task\\s+${escapedId}[:\\s]`);
|
|
212
|
+
const taskPattern = buildTaskHeaderRegexForId(taskId);
|
|
214
213
|
let inBlock = false;
|
|
215
214
|
for (let i = 0; i < lines.length; i++) {
|
|
216
215
|
const line = lines[i] ?? "";
|
|
@@ -36,13 +36,28 @@ export interface WebpressoInstallProbe {
|
|
|
36
36
|
* machine. Probes the locations consumers use to install webpresso, in order
|
|
37
37
|
* of stability:
|
|
38
38
|
*
|
|
39
|
-
* 1. the stable global `wp` shim available on PATH
|
|
40
|
-
*
|
|
39
|
+
* 1. the stable global `wp` shim available on PATH (including the
|
|
40
|
+
* vite-plus multi-package shim at `~/.vite-plus/bin/wp`)
|
|
41
|
+
* 2. the currently executing `@webpresso/agent-kit` package **only when it
|
|
42
|
+
* is not a vite-plus `agent-kit#<installId>` payload path**
|
|
41
43
|
* 3. Claude plugin install — `~/.claude/plugins/cache/.../agent-kit/`
|
|
42
44
|
* 4. bun global — `~/.bun/install/global/node_modules/@webpresso/agent-kit/`
|
|
43
|
-
*
|
|
45
|
+
*
|
|
46
|
+
* Host MCP configs (Grok/Codex/etc.) must never be pinned to a versioned
|
|
47
|
+
* installId tree: the next `wp update` / `vp update -g` deletes that path and
|
|
48
|
+
* leaves every host with a dead launcher. Returns `null` when none of the
|
|
49
|
+
* candidates yield a durable `wp`.
|
|
44
50
|
*/
|
|
45
51
|
export declare function findWebpressoMcpEntry(probe?: WebpressoInstallProbe): string | null;
|
|
52
|
+
/**
|
|
53
|
+
* True when `entryPath` is the stable vite-plus multi-package `wp` shim that
|
|
54
|
+
* dispatches to `@webpresso/agent-kit` via `~/.vite-plus/bins/wp.json`.
|
|
55
|
+
*
|
|
56
|
+
* Unlike {@link isWebpressoWpEntry}, this does **not** require realpath to land
|
|
57
|
+
* inside a package `bin/wp` tree — vite-plus's `wp` is a symlink to the `vp`
|
|
58
|
+
* binary, so package-root ownership is proven via the bins metadata instead.
|
|
59
|
+
*/
|
|
60
|
+
export declare function isVitePlusManagedWebpressoWp(entryPath: string): boolean;
|
|
46
61
|
export declare function resolveWebpressoMcpEntry(probe?: WebpressoInstallProbe): {
|
|
47
62
|
entryPath: string | null;
|
|
48
63
|
checked: readonly string[];
|
|
@@ -12,9 +12,10 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import { accessSync, constants, existsSync, readFileSync, realpathSync, statSync } from "node:fs";
|
|
14
14
|
import { homedir } from "node:os";
|
|
15
|
-
import { dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
15
|
+
import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
16
16
|
import { execFileSync } from "node:child_process";
|
|
17
17
|
import { fileURLToPath } from "node:url";
|
|
18
|
+
import { isVersionedAgentKitPayloadPath } from "#cli/auto-update/self-invocation.js";
|
|
18
19
|
import { pathCandidates } from "#runtime/command-exists.js";
|
|
19
20
|
export const WEBPRESSO_MCP_SERVER_NAME = "webpresso";
|
|
20
21
|
/**
|
|
@@ -67,11 +68,17 @@ const WP_LAUNCHER_REQUIRED_RELATIVES = [
|
|
|
67
68
|
* machine. Probes the locations consumers use to install webpresso, in order
|
|
68
69
|
* of stability:
|
|
69
70
|
*
|
|
70
|
-
* 1. the stable global `wp` shim available on PATH
|
|
71
|
-
*
|
|
71
|
+
* 1. the stable global `wp` shim available on PATH (including the
|
|
72
|
+
* vite-plus multi-package shim at `~/.vite-plus/bin/wp`)
|
|
73
|
+
* 2. the currently executing `@webpresso/agent-kit` package **only when it
|
|
74
|
+
* is not a vite-plus `agent-kit#<installId>` payload path**
|
|
72
75
|
* 3. Claude plugin install — `~/.claude/plugins/cache/.../agent-kit/`
|
|
73
76
|
* 4. bun global — `~/.bun/install/global/node_modules/@webpresso/agent-kit/`
|
|
74
|
-
*
|
|
77
|
+
*
|
|
78
|
+
* Host MCP configs (Grok/Codex/etc.) must never be pinned to a versioned
|
|
79
|
+
* installId tree: the next `wp update` / `vp update -g` deletes that path and
|
|
80
|
+
* leaves every host with a dead launcher. Returns `null` when none of the
|
|
81
|
+
* candidates yield a durable `wp`.
|
|
75
82
|
*/
|
|
76
83
|
export function findWebpressoMcpEntry(probe = {}) {
|
|
77
84
|
return resolveWebpressoMcpEntry(probe).entryPath;
|
|
@@ -79,6 +86,37 @@ export function findWebpressoMcpEntry(probe = {}) {
|
|
|
79
86
|
function isUsableWebpressoMcpRoot(root) {
|
|
80
87
|
return WP_LAUNCHER_REQUIRED_RELATIVES.every((relativePath) => existsSync(join(root, relativePath)));
|
|
81
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* True when `entryPath` is the stable vite-plus multi-package `wp` shim that
|
|
91
|
+
* dispatches to `@webpresso/agent-kit` via `~/.vite-plus/bins/wp.json`.
|
|
92
|
+
*
|
|
93
|
+
* Unlike {@link isWebpressoWpEntry}, this does **not** require realpath to land
|
|
94
|
+
* inside a package `bin/wp` tree — vite-plus's `wp` is a symlink to the `vp`
|
|
95
|
+
* binary, so package-root ownership is proven via the bins metadata instead.
|
|
96
|
+
*/
|
|
97
|
+
export function isVitePlusManagedWebpressoWp(entryPath) {
|
|
98
|
+
try {
|
|
99
|
+
if (isVersionedAgentKitPayloadPath(entryPath))
|
|
100
|
+
return false;
|
|
101
|
+
const binDir = dirname(entryPath);
|
|
102
|
+
if (basename(binDir) !== "bin")
|
|
103
|
+
return false;
|
|
104
|
+
if (basename(dirname(binDir)) !== ".vite-plus")
|
|
105
|
+
return false;
|
|
106
|
+
const base = basename(entryPath).toLowerCase();
|
|
107
|
+
if (base !== "wp" && base !== "wp.exe")
|
|
108
|
+
return false;
|
|
109
|
+
const metaPath = join(dirname(binDir), "bins", "wp.json");
|
|
110
|
+
const meta = JSON.parse(readFileSync(metaPath, "utf8"));
|
|
111
|
+
return meta.package === "@webpresso/agent-kit";
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
function isDurableMcpEntryPath(entryPath) {
|
|
118
|
+
return !isVersionedAgentKitPayloadPath(entryPath);
|
|
119
|
+
}
|
|
82
120
|
export function resolveWebpressoMcpEntry(probe = {}) {
|
|
83
121
|
const checked = [];
|
|
84
122
|
if (probe.candidates === undefined) {
|
|
@@ -88,10 +126,17 @@ export function resolveWebpressoMcpEntry(probe = {}) {
|
|
|
88
126
|
if (stableEntry) {
|
|
89
127
|
checked.push(stableEntry);
|
|
90
128
|
const packageWp = packageWpFromAdjacentNpmCmdShim(stableEntry);
|
|
91
|
-
if (packageWp !== null)
|
|
129
|
+
if (packageWp !== null && isDurableMcpEntryPath(packageWp)) {
|
|
92
130
|
return { entryPath: packageWp, checked };
|
|
131
|
+
}
|
|
93
132
|
const verifierAllows = probe.stableEntryIsWebpresso?.(stableEntry) ?? true;
|
|
94
|
-
|
|
133
|
+
// Prefer the vite-plus multi-package shim before package-root ownership:
|
|
134
|
+
// it survives installId swaps and is what PATH `wp` resolves to in the
|
|
135
|
+
// default consumer install.
|
|
136
|
+
if (verifierAllows && isVitePlusManagedWebpressoWp(stableEntry)) {
|
|
137
|
+
return { entryPath: stableEntry, checked };
|
|
138
|
+
}
|
|
139
|
+
if (verifierAllows && isWebpressoWpEntry(stableEntry) && isDurableMcpEntryPath(stableEntry)) {
|
|
95
140
|
return { entryPath: stableEntry, checked };
|
|
96
141
|
}
|
|
97
142
|
}
|
|
@@ -103,6 +148,9 @@ export function resolveWebpressoMcpEntry(probe = {}) {
|
|
|
103
148
|
continue;
|
|
104
149
|
checked.push(root);
|
|
105
150
|
const wpBin = join(root, WP_BIN_RELATIVE);
|
|
151
|
+
// Never materialize host MCP configs against a vite-plus installId tree.
|
|
152
|
+
if (!isDurableMcpEntryPath(wpBin))
|
|
153
|
+
continue;
|
|
106
154
|
if (isTrustedWebpressoPackageRoot(root))
|
|
107
155
|
return { entryPath: wpBin, checked };
|
|
108
156
|
}
|
|
@@ -30,13 +30,11 @@ const TECH_STACK_RULES = [
|
|
|
30
30
|
{ dep: /^typescript$/, label: "TypeScript" },
|
|
31
31
|
];
|
|
32
32
|
// Kept under the 8 KB (8192-byte) hard ceiling. The rendered template embeds
|
|
33
|
-
// the full `native_tool_names` registry list
|
|
34
|
-
//
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
//
|
|
38
|
-
// breach it should trigger a conscious restructure (or exclude the
|
|
39
|
-
// auto-generated tool list from the prose budget), not another reflexive bump.
|
|
33
|
+
// the full `native_tool_names` registry list (~15-17 bytes per tool). Soft
|
|
34
|
+
// target 8_180 leaves headroom under 8_192. The ui-compose batch
|
|
35
|
+
// (wp_ui_blocks_list, wp_ui_compose, wp_ui_preview) required trimming catalog
|
|
36
|
+
// AGENTS.md.tpl prose rather than raising the ceiling. Next breach of 8_192
|
|
37
|
+
// should restructure (or stop embedding the full tool list), not bump again.
|
|
40
38
|
export const AGENTS_MD_MAX_BYTES = 8_180;
|
|
41
39
|
export function renderRepositoryMap(consumer) {
|
|
42
40
|
const packages = consumer.workspacePackages;
|
|
@@ -184,6 +184,9 @@ function runGlobalUpdateCommand(deps) {
|
|
|
184
184
|
else {
|
|
185
185
|
failed = true;
|
|
186
186
|
console.error(message);
|
|
187
|
+
// Required step failed — stop so optional host refreshes cannot
|
|
188
|
+
// look like a successful update after a broken agent-kit install.
|
|
189
|
+
break;
|
|
187
190
|
}
|
|
188
191
|
}
|
|
189
192
|
}
|
|
@@ -195,6 +198,7 @@ function runGlobalUpdateCommand(deps) {
|
|
|
195
198
|
else {
|
|
196
199
|
failed = true;
|
|
197
200
|
console.error(message);
|
|
201
|
+
break;
|
|
198
202
|
}
|
|
199
203
|
}
|
|
200
204
|
}
|
|
@@ -313,8 +317,10 @@ function runAgentKitSelfUpdateStep(deps) {
|
|
|
313
317
|
return spawnLike(status, new Error("another agent-kit installer is active; re-run `wp update` once it finishes"));
|
|
314
318
|
case GUARD_EXIT_OWNERSHIP_LOST:
|
|
315
319
|
return spawnLike(status, new Error("install lease ownership was lost mid-update; the takeover installer verifies the store — re-run `wp update` to confirm"));
|
|
316
|
-
default:
|
|
317
|
-
|
|
320
|
+
default: {
|
|
321
|
+
const code = status === 0 ? 1 : status;
|
|
322
|
+
return spawnLike(code, new Error(`agent-kit self-install failed (self-install-guard exit ${code}); re-run \`wp update\` or \`vp install -g @webpresso/agent-kit\``));
|
|
323
|
+
}
|
|
318
324
|
}
|
|
319
325
|
}
|
|
320
326
|
function refreshCodexPlugin(deps) {
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `wp release-progress` — report Release workflow phase (detect / native-matrix / publish).
|
|
3
|
+
*
|
|
4
|
+
* Agents must not poll only `npm view` after Version Packages merge. This command
|
|
5
|
+
* loads the live GitHub Actions job list and classifies progress via
|
|
6
|
+
* {@link classifyReleaseRunProgress}.
|
|
7
|
+
*/
|
|
8
|
+
import type { CAC } from "cac";
|
|
9
|
+
import { type ReleaseJobSnapshot, type ReleaseProgress } from "#ci/release-progress.js";
|
|
10
|
+
export declare const RELEASE_PROGRESS_COMMAND_HELP: string;
|
|
11
|
+
export interface GhRunJobsFetcher {
|
|
12
|
+
(options: {
|
|
13
|
+
readonly runId: string;
|
|
14
|
+
readonly repo: string;
|
|
15
|
+
}): ReleaseJobSnapshot[];
|
|
16
|
+
}
|
|
17
|
+
export interface LatestReleaseRunResolver {
|
|
18
|
+
(options: {
|
|
19
|
+
readonly repo: string;
|
|
20
|
+
}): string;
|
|
21
|
+
}
|
|
22
|
+
/** Production fetcher: `gh run view --json jobs`. */
|
|
23
|
+
export declare function fetchReleaseJobsViaGh(options: {
|
|
24
|
+
readonly runId: string;
|
|
25
|
+
readonly repo: string;
|
|
26
|
+
}): ReleaseJobSnapshot[];
|
|
27
|
+
/** Production resolver: latest Release workflow run for the repo. */
|
|
28
|
+
export declare function resolveLatestReleaseRunIdViaGh(options: {
|
|
29
|
+
readonly repo: string;
|
|
30
|
+
}): string;
|
|
31
|
+
export interface RunReleaseProgressOptions {
|
|
32
|
+
readonly runId?: string | number;
|
|
33
|
+
readonly repo?: string;
|
|
34
|
+
readonly json?: boolean;
|
|
35
|
+
readonly fetchJobs?: GhRunJobsFetcher;
|
|
36
|
+
readonly resolveLatestRunId?: LatestReleaseRunResolver;
|
|
37
|
+
readonly stdout?: {
|
|
38
|
+
write(chunk: string): void;
|
|
39
|
+
};
|
|
40
|
+
readonly stderr?: {
|
|
41
|
+
write(chunk: string): void;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Core command body — injectable for tests; production uses gh CLI defaults.
|
|
46
|
+
*/
|
|
47
|
+
export declare function runReleaseProgress(options?: RunReleaseProgressOptions): {
|
|
48
|
+
readonly exitCode: number;
|
|
49
|
+
readonly progress: ReleaseProgress;
|
|
50
|
+
readonly runId: string;
|
|
51
|
+
readonly line: string;
|
|
52
|
+
};
|
|
53
|
+
export declare function registerReleaseProgressCommand(cli: CAC): void;
|