supipowers 1.5.3 → 2.0.1
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/README.md +14 -8
- package/bin/install.mjs +20 -5
- package/bin/install.ts +95 -0
- package/package.json +8 -4
- package/skills/context-mode/SKILL.md +17 -10
- package/skills/harness/SKILL.md +94 -0
- package/skills/ui-design/SKILL.md +63 -0
- package/skills/ui-design/sub-agent-templates/component-builder.md +29 -0
- package/skills/ui-design/sub-agent-templates/design-critic.md +46 -0
- package/skills/ui-design/sub-agent-templates/pencil/component-builder.md +29 -0
- package/skills/ui-design/sub-agent-templates/pencil/design-critic.md +42 -0
- package/skills/ui-design/sub-agent-templates/pencil/section-assembler.md +27 -0
- package/skills/ui-design/sub-agent-templates/section-assembler.md +27 -0
- package/skills/ultraplan-discover/SKILL.md +96 -0
- package/skills/ultraplan-intake/SKILL.md +89 -0
- package/skills/ultraplan-research/SKILL.md +129 -0
- package/skills/ultraplan-review/SKILL.md +86 -0
- package/skills/ultraplan-review-scope/SKILL.md +111 -0
- package/skills/ultraplan-review-structure/SKILL.md +120 -0
- package/skills/ultraplan-review-tdd/SKILL.md +142 -0
- package/skills/ultraplan-scout/SKILL.md +110 -0
- package/skills/ultraplan-synthesize/SKILL.md +124 -0
- package/src/{quality/ai-session.ts → ai/final-message.ts} +27 -0
- package/src/ai/schema-text.ts +129 -0
- package/src/ai/structured-output.ts +274 -0
- package/src/ai/template.ts +27 -0
- package/src/bootstrap.ts +63 -28
- package/src/commands/agents.ts +131 -42
- package/src/commands/ai-review.ts +251 -30
- package/src/commands/clear.ts +434 -0
- package/src/commands/commit.ts +1 -0
- package/src/commands/config.ts +242 -44
- package/src/commands/context.ts +55 -28
- package/src/commands/doctor.ts +234 -6
- package/src/commands/fix-pr.ts +306 -131
- package/src/commands/generate.ts +111 -21
- package/src/commands/memory.ts +192 -0
- package/src/commands/model-picker.ts +28 -21
- package/src/commands/model.ts +18 -8
- package/src/commands/optimize-context.ts +408 -29
- package/src/commands/plan.ts +2 -0
- package/src/commands/qa.ts +312 -137
- package/src/commands/release.ts +259 -76
- package/src/commands/review.ts +293 -59
- package/src/commands/status.ts +200 -13
- package/src/commands/supi.ts +3 -35
- package/src/commands/ui-design.ts +394 -0
- package/src/commands/ultraplan.ts +1518 -0
- package/src/commands/update.ts +86 -0
- package/src/config/defaults.ts +62 -0
- package/src/config/loader.ts +448 -60
- package/src/config/schema.ts +108 -2
- package/src/context/optimizer.ts +25 -33
- package/src/context/rule-renderer.ts +223 -0
- package/src/context/savings.ts +258 -0
- package/src/context/startup-check.ts +380 -0
- package/src/context/startup-optimizer.ts +355 -0
- package/src/context/tokenignore.ts +146 -0
- package/src/context-mode/cache-handle.ts +49 -0
- package/src/context-mode/cache-preview.ts +71 -0
- package/src/context-mode/cache-store.ts +738 -0
- package/src/context-mode/compressor.ts +131 -26
- package/src/context-mode/dedup.ts +108 -0
- package/src/context-mode/detector.ts +35 -4
- package/src/context-mode/event-extractor.ts +14 -12
- package/src/context-mode/event-store.ts +91 -36
- package/src/context-mode/hooks.ts +798 -56
- package/src/context-mode/knowledge/store.ts +255 -11
- package/src/context-mode/memory-store.ts +325 -0
- package/src/context-mode/metrics-recorder.ts +158 -0
- package/src/context-mode/metrics-store.ts +765 -0
- package/src/context-mode/model.ts +24 -0
- package/src/context-mode/processor-keys.ts +29 -0
- package/src/context-mode/processors/build.ts +66 -0
- package/src/context-mode/processors/docker.ts +57 -0
- package/src/context-mode/processors/git.ts +111 -0
- package/src/context-mode/processors/json.ts +112 -0
- package/src/context-mode/processors/k8s.ts +67 -0
- package/src/context-mode/processors/lint.ts +67 -0
- package/src/context-mode/processors/log.ts +86 -0
- package/src/context-mode/processors/registry.ts +116 -0
- package/src/context-mode/processors/test-runner.ts +102 -0
- package/src/context-mode/processors/types.ts +20 -0
- package/src/context-mode/repomap.ts +400 -0
- package/src/context-mode/routing.ts +97 -24
- package/src/context-mode/sandbox/runners.ts +5 -1
- package/src/context-mode/snapshot-builder.ts +106 -11
- package/src/context-mode/source-hash.ts +173 -0
- package/src/context-mode/tool-name.ts +11 -0
- package/src/context-mode/tools.ts +654 -22
- package/src/context-mode/web/fetcher.ts +31 -12
- package/src/debug/logger.ts +2 -1
- package/src/deps/registry.ts +1 -1
- package/src/discipline/failure-summarizer.ts +170 -0
- package/src/discipline/failure-taxonomy.ts +131 -0
- package/src/discipline/workflow-invariants.ts +125 -0
- package/src/discovery/index.ts +31 -0
- package/src/discovery/lsp.ts +87 -0
- package/src/discovery/rank.ts +144 -0
- package/src/discovery/sources.ts +89 -0
- package/src/discovery/workflow.ts +87 -0
- package/src/docs/contracts.ts +39 -0
- package/src/docs/drift.ts +117 -87
- package/src/fix-pr/assessment.ts +200 -0
- package/src/fix-pr/contracts.ts +47 -0
- package/src/fix-pr/fetch-comments.ts +80 -0
- package/src/fix-pr/prompt-builder.ts +58 -40
- package/src/fix-pr/scripts/exec.ts +34 -0
- package/src/fix-pr/scripts/trigger-review.ts +106 -0
- package/src/fix-pr/scripts/wait-and-check.ts +108 -0
- package/src/fix-pr/types.ts +4 -0
- package/src/git/branch-finish.ts +5 -0
- package/src/git/commit-contract.ts +83 -0
- package/src/git/commit.ts +121 -184
- package/src/git/status.ts +62 -8
- package/src/harness/anti_slop/architecture-parser.ts +210 -0
- package/src/harness/anti_slop/backend-factory.ts +30 -0
- package/src/harness/anti_slop/backend.ts +140 -0
- package/src/harness/anti_slop/desloppify-adapter.ts +319 -0
- package/src/harness/anti_slop/fallow-adapter.ts +305 -0
- package/src/harness/anti_slop/installer.ts +227 -0
- package/src/harness/anti_slop/queue.ts +216 -0
- package/src/harness/anti_slop/recommend.ts +84 -0
- package/src/harness/anti_slop/score.ts +180 -0
- package/src/harness/anti_slop/synthetic-edit-test.ts +128 -0
- package/src/harness/artifacts/agents-md.ts +88 -0
- package/src/harness/artifacts/checks-wiring.ts +57 -0
- package/src/harness/artifacts/docs-tree.ts +79 -0
- package/src/harness/artifacts/lint-configs.ts +136 -0
- package/src/harness/artifacts/review-agents.ts +67 -0
- package/src/harness/bare-entry.ts +108 -0
- package/src/harness/command.ts +1010 -0
- package/src/harness/default-agents/design.md +23 -0
- package/src/harness/default-agents/discover.md +18 -0
- package/src/harness/default-agents/implement.md +24 -0
- package/src/harness/default-agents/plan.md +19 -0
- package/src/harness/default-agents/research.md +21 -0
- package/src/harness/default-agents/validate.md +22 -0
- package/src/harness/gc/reporter.ts +28 -0
- package/src/harness/gc/runner.ts +136 -0
- package/src/harness/hooks/layer-context-inject.ts +155 -0
- package/src/harness/hooks/post-session-sweep.ts +130 -0
- package/src/harness/hooks/pre-edit-dupe-probe.ts +224 -0
- package/src/harness/hooks/register.ts +118 -0
- package/src/harness/model.ts +117 -0
- package/src/harness/pipeline.ts +348 -0
- package/src/harness/project-paths.ts +235 -0
- package/src/harness/stage-runner.ts +107 -0
- package/src/harness/stages/design.ts +386 -0
- package/src/harness/stages/discover.ts +454 -0
- package/src/harness/stages/implement.ts +162 -0
- package/src/harness/stages/plan.ts +335 -0
- package/src/harness/stages/research.ts +263 -0
- package/src/harness/stages/validate.ts +684 -0
- package/src/harness/storage.ts +467 -0
- package/src/harness/tools.ts +426 -0
- package/src/lsp/bridge.ts +56 -95
- package/src/lsp/capabilities.ts +108 -0
- package/src/lsp/contracts.ts +35 -0
- package/src/lsp/detector.ts +8 -12
- package/src/markdown-frontmatter.ts +68 -0
- package/src/mempalace/bridge.ts +135 -0
- package/src/mempalace/config.ts +75 -0
- package/src/mempalace/format.ts +163 -0
- package/src/mempalace/hooks.ts +370 -0
- package/src/mempalace/installer-helper.ts +194 -0
- package/src/mempalace/python/mempalace_bridge.py +440 -0
- package/src/mempalace/runtime.ts +565 -0
- package/src/mempalace/schema.ts +268 -0
- package/src/mempalace/session-summary.ts +198 -0
- package/src/mempalace/tool.ts +186 -0
- package/src/mempalace/uv.ts +256 -0
- package/src/migrate/runner.ts +354 -0
- package/src/planning/approval-flow.ts +206 -9
- package/src/planning/plan-writer-prompt.ts +4 -3
- package/src/planning/planning-ask-tool.ts +39 -0
- package/src/planning/render-markdown.ts +74 -0
- package/src/planning/spec.ts +42 -0
- package/src/planning/system-prompt.ts +11 -8
- package/src/planning/validate.ts +84 -0
- package/src/platform/omp.ts +15 -2
- package/src/platform/system-prompt.ts +37 -0
- package/src/platform/test-utils.ts +3 -0
- package/src/platform/types.ts +6 -1
- package/src/qa/config.ts +12 -6
- package/src/qa/detect-app-type.ts +13 -6
- package/src/qa/matrix.ts +12 -6
- package/src/qa/prompt-builder.ts +28 -30
- package/src/qa/scripts/dev-server-utils.ts +72 -0
- package/src/qa/scripts/run-e2e-tests.ts +226 -0
- package/src/qa/scripts/start-dev-server.ts +138 -0
- package/src/qa/scripts/stop-dev-server.ts +77 -0
- package/src/qa/session.ts +13 -7
- package/src/quality/ai-setup.ts +27 -25
- package/src/quality/contracts.ts +34 -0
- package/src/quality/gates/ai-review.ts +20 -58
- package/src/quality/gates/command.ts +249 -46
- package/src/quality/review-gates.ts +18 -2
- package/src/quality/runner.ts +63 -22
- package/src/quality/schemas.ts +37 -2
- package/src/quality/setup.ts +96 -16
- package/src/release/changelog.ts +1 -1
- package/src/release/channels/custom.ts +13 -3
- package/src/release/channels/types.ts +5 -0
- package/src/release/contracts.ts +90 -0
- package/src/release/executor.ts +122 -45
- package/src/release/prompt.ts +18 -2
- package/src/release/targets.ts +86 -0
- package/src/release/version.ts +96 -71
- package/src/review/agent-loader.ts +221 -109
- package/src/review/fixer.ts +10 -6
- package/src/review/multi-agent-runner.ts +114 -13
- package/src/review/output.ts +12 -139
- package/src/review/runner.ts +12 -6
- package/src/review/scope.ts +144 -24
- package/src/review/types.ts +1 -20
- package/src/review/validator.ts +12 -6
- package/src/storage/fix-pr-sessions.ts +21 -14
- package/src/storage/plans.ts +14 -5
- package/src/storage/qa-sessions.ts +25 -19
- package/src/storage/reliability-metrics.ts +180 -0
- package/src/storage/reports.ts +8 -7
- package/src/storage/review-sessions.ts +55 -20
- package/src/tool-catalog/active-tool-controller.ts +164 -0
- package/src/tool-catalog/active-tool-planner.ts +212 -0
- package/src/tool-catalog/tool-groups.ts +102 -0
- package/src/types.ts +1399 -5
- package/src/ui-design/backend-adapter.ts +78 -0
- package/src/ui-design/backends/local-html.ts +82 -0
- package/src/ui-design/backends/pencil-mcp.ts +111 -0
- package/src/ui-design/components-scanner.ts +124 -0
- package/src/ui-design/config.ts +55 -0
- package/src/ui-design/pen-scanner.ts +95 -0
- package/src/ui-design/pen-selector.ts +72 -0
- package/src/ui-design/prompt-builder.ts +73 -0
- package/src/ui-design/scanner.ts +136 -0
- package/src/ui-design/session.ts +974 -0
- package/src/ui-design/system-prompt.ts +312 -0
- package/src/ui-design/tokens-scanner.ts +181 -0
- package/src/ui-design/types.ts +96 -0
- package/src/ultraplan/agent-catalog.ts +522 -0
- package/src/ultraplan/authoring/agent-catalog.ts +310 -0
- package/src/ultraplan/authoring/authoring-tools.ts +552 -0
- package/src/ultraplan/authoring/command-handlers.ts +339 -0
- package/src/ultraplan/authoring/markdown.ts +510 -0
- package/src/ultraplan/authoring/model.ts +162 -0
- package/src/ultraplan/authoring/pipeline.ts +319 -0
- package/src/ultraplan/authoring/stage-runner.ts +141 -0
- package/src/ultraplan/authoring/stages/approve.ts +249 -0
- package/src/ultraplan/authoring/stages/discover.ts +289 -0
- package/src/ultraplan/authoring/stages/intake.ts +203 -0
- package/src/ultraplan/authoring/stages/research.ts +399 -0
- package/src/ultraplan/authoring/stages/review.ts +333 -0
- package/src/ultraplan/authoring/stages/scout.ts +188 -0
- package/src/ultraplan/authoring/stages/synthesize.ts +348 -0
- package/src/ultraplan/authoring/storage.ts +594 -0
- package/src/ultraplan/authoring/synth-gate.ts +165 -0
- package/src/ultraplan/authoring-draft.ts +653 -0
- package/src/ultraplan/authoring-persist.ts +180 -0
- package/src/ultraplan/authoring-tool.ts +608 -0
- package/src/ultraplan/authoring-wizard.ts +587 -0
- package/src/ultraplan/batch/merge.ts +98 -0
- package/src/ultraplan/batch/planner.ts +150 -0
- package/src/ultraplan/batch/presenter.ts +97 -0
- package/src/ultraplan/batch/storage.ts +420 -0
- package/src/ultraplan/batch/supervisor.ts +317 -0
- package/src/ultraplan/batch/worker.ts +26 -0
- package/src/ultraplan/batch/worktree.ts +110 -0
- package/src/ultraplan/contracts.ts +1593 -0
- package/src/ultraplan/default-agents/authoring/discoverer.md +12 -0
- package/src/ultraplan/default-agents/authoring/intake.md +12 -0
- package/src/ultraplan/default-agents/authoring/planner.md +12 -0
- package/src/ultraplan/default-agents/authoring/researcher.md +12 -0
- package/src/ultraplan/default-agents/authoring/scope-checker.md +12 -0
- package/src/ultraplan/default-agents/authoring/scout.md +12 -0
- package/src/ultraplan/default-agents/authoring/structure-checker.md +12 -0
- package/src/ultraplan/default-agents/authoring/tdd-checker.md +12 -0
- package/src/ultraplan/default-agents/backend-domain-reviewer.md +10 -0
- package/src/ultraplan/default-agents/backend-executor.md +10 -0
- package/src/ultraplan/default-agents/backend-stack-reviewer.md +10 -0
- package/src/ultraplan/default-agents/backend-tester.md +10 -0
- package/src/ultraplan/default-agents/frontend-domain-reviewer.md +10 -0
- package/src/ultraplan/default-agents/frontend-executor.md +10 -0
- package/src/ultraplan/default-agents/frontend-stack-reviewer.md +10 -0
- package/src/ultraplan/default-agents/frontend-tester.md +10 -0
- package/src/ultraplan/default-agents/infrastructure-domain-reviewer.md +10 -0
- package/src/ultraplan/default-agents/infrastructure-executor.md +10 -0
- package/src/ultraplan/default-agents/infrastructure-stack-reviewer.md +10 -0
- package/src/ultraplan/default-agents/infrastructure-tester.md +10 -0
- package/src/ultraplan/execution/contract.ts +71 -0
- package/src/ultraplan/execution/policy.ts +217 -0
- package/src/ultraplan/execution/runtime-tools.ts +107 -0
- package/src/ultraplan/execution/session-runner.ts +281 -0
- package/src/ultraplan/next-router.ts +85 -0
- package/src/ultraplan/presenter.ts +359 -0
- package/src/ultraplan/project-paths.ts +342 -0
- package/src/ultraplan/runtime/active-execution.ts +72 -0
- package/src/ultraplan/runtime/apply-mutation.ts +416 -0
- package/src/ultraplan/runtime/blockers.ts +243 -0
- package/src/ultraplan/runtime/hook-bridge.ts +486 -0
- package/src/ultraplan/runtime/launch-context.ts +207 -0
- package/src/ultraplan/runtime/migration.ts +524 -0
- package/src/ultraplan/runtime/normalize.ts +281 -0
- package/src/ultraplan/runtime/proof.ts +260 -0
- package/src/ultraplan/runtime/reducer.ts +416 -0
- package/src/ultraplan/runtime/repair.ts +251 -0
- package/src/ultraplan/runtime/tracker-storage.ts +368 -0
- package/src/ultraplan/session-selection.ts +291 -0
- package/src/ultraplan/storage.ts +374 -0
- package/src/utils/editor.ts +38 -0
- package/src/utils/executable.ts +80 -0
- package/src/utils/paths.ts +1 -20
- package/src/utils/shell.ts +31 -0
- package/src/visual/companion.ts +2 -1
- package/src/visual/scripts/frame-template.html +60 -0
- package/src/visual/scripts/index.js +59 -13
- package/src/visual/scripts/package.json +3 -0
- package/src/visual/start-server.ts +2 -1
- package/src/workspace/git-scope.ts +64 -0
- package/src/workspace/locks.ts +23 -0
- package/src/workspace/package-manager.ts +117 -0
- package/src/workspace/path-mapping.ts +75 -0
- package/src/workspace/project-slug.ts +92 -0
- package/src/workspace/repo-root.ts +137 -0
- package/src/workspace/selector.ts +115 -0
- package/src/workspace/state-paths.ts +118 -0
- package/src/workspace/targets.ts +313 -0
- package/src/fix-pr/scripts/diff-comments.sh +0 -33
- package/src/fix-pr/scripts/fetch-pr-comments.sh +0 -25
- package/src/fix-pr/scripts/trigger-review.sh +0 -36
- package/src/fix-pr/scripts/wait-and-check.sh +0 -37
- package/src/qa/scripts/detect-app-type.sh +0 -68
- package/src/qa/scripts/discover-routes.sh +0 -143
- package/src/qa/scripts/run-e2e-tests.sh +0 -131
- package/src/qa/scripts/start-dev-server.sh +0 -46
- package/src/qa/scripts/stop-dev-server.sh +0 -36
- package/src/review/prompts/fix-output-schema.md +0 -18
- package/src/review/prompts/review-output-schema.md +0 -38
- package/src/review/template.ts +0 -15
- /package/src/{review → ai}/prompts/invalid-output-retry.md +0 -0
package/src/release/prompt.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { formatTag } from "./version.js";
|
|
2
|
+
import { renderSchemaText } from "../ai/schema-text.js";
|
|
3
|
+
import { ReleaseNotePolishOutputSchema } from "./contracts.js";
|
|
2
4
|
|
|
3
5
|
export interface BuildPolishPromptOpts {
|
|
4
6
|
changelog: string;
|
|
@@ -10,7 +12,9 @@ export interface BuildPolishPromptOpts {
|
|
|
10
12
|
* Build a prompt for a headless agent session that polishes raw changelog
|
|
11
13
|
* text into clear, user-facing release notes.
|
|
12
14
|
*
|
|
13
|
-
* The agent returns
|
|
15
|
+
* The agent returns a structured JSON artifact matching
|
|
16
|
+
* ReleaseNotePolishOutputSchema. The release command renders the polished
|
|
17
|
+
* changelog from that artifact — no free-form text, no regex extraction.
|
|
14
18
|
*/
|
|
15
19
|
export function buildPolishPrompt(opts: BuildPolishPromptOpts): string {
|
|
16
20
|
const { changelog, version } = opts;
|
|
@@ -66,6 +70,18 @@ export function buildPolishPrompt(opts: BuildPolishPromptOpts): string {
|
|
|
66
70
|
"",
|
|
67
71
|
"## Output",
|
|
68
72
|
"",
|
|
69
|
-
"
|
|
73
|
+
"Respond with a JSON object that matches this TypeScript shape exactly:",
|
|
74
|
+
"",
|
|
75
|
+
"```ts",
|
|
76
|
+
renderSchemaText(ReleaseNotePolishOutputSchema),
|
|
77
|
+
"```",
|
|
78
|
+
"",
|
|
79
|
+
"Field guide:",
|
|
80
|
+
"- `title`: short one-line heading for the release (no leading `#`).",
|
|
81
|
+
"- `body`: the grouped markdown sections (Breaking Changes, Features, Fixes, ...). Omit empty sections.",
|
|
82
|
+
"- `highlights`: 0–5 short bullet strings summarising the most user-visible changes. Each string is a plain sentence, no leading `-`.",
|
|
83
|
+
"- `status`: `\"ok\"` when the release has notable changes; `\"empty\"` when the raw changelog had nothing worth polishing (highlights may be empty and body may be a short placeholder).",
|
|
84
|
+
"",
|
|
85
|
+
"Respond with only the JSON object. You may wrap it in a ```json fence.",
|
|
70
86
|
].join("\n");
|
|
71
87
|
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import type { PackageManagerId, ReleaseTarget, WorkspaceTarget } from "../types.js";
|
|
4
|
+
import { discoverWorkspaceTargets } from "../workspace/targets.js";
|
|
5
|
+
|
|
6
|
+
interface ReleaseManifest {
|
|
7
|
+
name?: string;
|
|
8
|
+
version?: string;
|
|
9
|
+
private?: boolean;
|
|
10
|
+
files?: unknown;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const ROOT_TAG_FORMAT = "v${version}";
|
|
14
|
+
|
|
15
|
+
function normalizeReleasePath(value: string): string {
|
|
16
|
+
return value
|
|
17
|
+
.replace(/\\/g, "/")
|
|
18
|
+
.replace(/^\.\//, "")
|
|
19
|
+
.replace(/^\//, "")
|
|
20
|
+
.replace(/\/package\.json$/, "")
|
|
21
|
+
.replace(/\/+$/, "");
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function readReleaseManifest(manifestPath: string): ReleaseManifest | null {
|
|
25
|
+
try {
|
|
26
|
+
return JSON.parse(fs.readFileSync(manifestPath, "utf-8")) as ReleaseManifest;
|
|
27
|
+
} catch {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function normalizeFilesWhitelist(files: unknown): string[] {
|
|
33
|
+
if (!Array.isArray(files)) {
|
|
34
|
+
return [];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return files
|
|
38
|
+
.filter((entry): entry is string => typeof entry === "string")
|
|
39
|
+
.map((entry) => normalizeReleasePath(entry))
|
|
40
|
+
.filter(Boolean);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function joinTargetPath(relativeDir: string, entry: string): string {
|
|
44
|
+
if (relativeDir === ".") {
|
|
45
|
+
return entry;
|
|
46
|
+
}
|
|
47
|
+
return `${relativeDir}/${entry}`;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function buildPublishScopePaths(target: WorkspaceTarget, manifest: ReleaseManifest | null): string[] {
|
|
51
|
+
const manifestPath = joinTargetPath(target.relativeDir, "package.json");
|
|
52
|
+
const filesWhitelist = normalizeFilesWhitelist(manifest?.files);
|
|
53
|
+
if (filesWhitelist.length > 0) {
|
|
54
|
+
return [...new Set([manifestPath, ...filesWhitelist.map((entry) => joinTargetPath(target.relativeDir, entry))])];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const packageDirScope = target.relativeDir === "." ? "." : target.relativeDir;
|
|
58
|
+
return [...new Set([manifestPath, packageDirScope])];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function getDefaultTagFormat(target: WorkspaceTarget): string {
|
|
62
|
+
return target.kind === "root" ? ROOT_TAG_FORMAT : `${target.name}@${ROOT_TAG_FORMAT.replace("v", "")}`;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function hasReleaseVersion(manifest: ReleaseManifest | null): manifest is ReleaseManifest & { version: string } {
|
|
66
|
+
return typeof manifest?.version === "string" && manifest.version.trim().length > 0;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function toReleaseTarget(target: WorkspaceTarget, manifest = readReleaseManifest(target.manifestPath)): ReleaseTarget {
|
|
70
|
+
return {
|
|
71
|
+
...target,
|
|
72
|
+
publishScopePaths: buildPublishScopePaths(target, manifest),
|
|
73
|
+
defaultTagFormat: getDefaultTagFormat(target),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function discoverReleaseTargets(repoRoot: string, packageManager: PackageManagerId): ReleaseTarget[] {
|
|
78
|
+
return discoverWorkspaceTargets(repoRoot, packageManager).flatMap((target) => {
|
|
79
|
+
const manifest = readReleaseManifest(target.manifestPath);
|
|
80
|
+
return hasReleaseVersion(manifest) ? [toReleaseTarget(target, manifest)] : [];
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function getPublishableReleaseTargets(targets: ReleaseTarget[]): ReleaseTarget[] {
|
|
85
|
+
return targets.filter((target) => !target.private);
|
|
86
|
+
}
|
package/src/release/version.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
|
-
import
|
|
3
|
-
import type { BumpType, CategorizedCommits } from "../types.js";
|
|
2
|
+
import type { BumpType, CategorizedCommits, ReleaseTarget } from "../types.js";
|
|
4
3
|
|
|
5
4
|
type ExecFn = (
|
|
6
5
|
cmd: string,
|
|
@@ -8,6 +7,18 @@ type ExecFn = (
|
|
|
8
7
|
opts?: { cwd?: string },
|
|
9
8
|
) => Promise<{ stdout: string; stderr: string; code: number }>;
|
|
10
9
|
|
|
10
|
+
interface PackageManifest {
|
|
11
|
+
version?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface ParsedReleaseTag {
|
|
15
|
+
tag: string;
|
|
16
|
+
version: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const LEGACY_RELEASE_TAG_FORMAT = "v${version}";
|
|
20
|
+
const SEMVER_CAPTURE = "([0-9]+\\.[0-9]+\\.[0-9]+(?:-[0-9A-Za-z.-]+)?)";
|
|
21
|
+
|
|
11
22
|
/**
|
|
12
23
|
* Replace `${version}` in a tag format template with the actual version string.
|
|
13
24
|
* If the template contains no placeholder, it is returned as-is.
|
|
@@ -32,7 +43,6 @@ export function suggestBump(commits: CategorizedCommits): BumpType {
|
|
|
32
43
|
* Returns a plain "X.Y.Z" string — never prefixed with "v".
|
|
33
44
|
*/
|
|
34
45
|
export function bumpVersion(current: string, bump: BumpType): string {
|
|
35
|
-
// Strip pre-release / build metadata before parsing
|
|
36
46
|
const core = current.split("-")[0].split("+")[0];
|
|
37
47
|
const parts = core.split(".").map(Number);
|
|
38
48
|
|
|
@@ -40,8 +50,7 @@ export function bumpVersion(current: string, bump: BumpType): string {
|
|
|
40
50
|
throw new Error(`Invalid semver string: "${current}"`);
|
|
41
51
|
}
|
|
42
52
|
|
|
43
|
-
|
|
44
|
-
|
|
53
|
+
const [major, minor, patch] = parts;
|
|
45
54
|
switch (bump) {
|
|
46
55
|
case "major":
|
|
47
56
|
return `${major + 1}.0.0`;
|
|
@@ -52,56 +61,38 @@ export function bumpVersion(current: string, bump: BumpType): string {
|
|
|
52
61
|
}
|
|
53
62
|
}
|
|
54
63
|
|
|
55
|
-
|
|
56
|
-
* Read the parsed package.json object from `<cwd>/package.json`. Returns null
|
|
57
|
-
* when the file is absent or invalid.
|
|
58
|
-
*/
|
|
59
|
-
function readPackageJson(cwd: string): { version?: string; files?: unknown } | null {
|
|
60
|
-
const pkgPath = path.join(cwd, "package.json");
|
|
64
|
+
function readPackageJson(manifestPath: string): PackageManifest | null {
|
|
61
65
|
try {
|
|
62
|
-
|
|
63
|
-
return JSON.parse(raw) as { version?: string; files?: unknown };
|
|
66
|
+
return JSON.parse(fs.readFileSync(manifestPath, "utf-8")) as PackageManifest;
|
|
64
67
|
} catch {
|
|
65
68
|
return null;
|
|
66
69
|
}
|
|
67
70
|
}
|
|
68
71
|
|
|
69
72
|
/**
|
|
70
|
-
* Read the
|
|
71
|
-
* Returns
|
|
73
|
+
* Read the current version from the selected release target's manifest.
|
|
74
|
+
* Returns "0.0.0" when the manifest is absent or carries no version field.
|
|
72
75
|
*/
|
|
73
|
-
export function getCurrentVersion(
|
|
74
|
-
return readPackageJson(
|
|
76
|
+
export function getCurrentVersion(target: ReleaseTarget): string {
|
|
77
|
+
return readPackageJson(target.manifestPath)?.version ?? "0.0.0";
|
|
75
78
|
}
|
|
76
79
|
|
|
77
|
-
/**
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
*/
|
|
81
|
-
export function getPublishedPackagePaths(cwd: string): string[] | null {
|
|
82
|
-
const files = readPackageJson(cwd)?.files;
|
|
83
|
-
if (!Array.isArray(files)) {
|
|
84
|
-
return null;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const normalized = files
|
|
88
|
-
.filter((entry): entry is string => typeof entry === "string")
|
|
89
|
-
.map((entry) => entry.replace(/^\.\//, "").replace(/\/+$/, ""))
|
|
90
|
-
.filter(Boolean);
|
|
91
|
-
|
|
92
|
-
if (normalized.length === 0) {
|
|
93
|
-
return null;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return [...new Set(["package.json", ...normalized])];
|
|
80
|
+
/** Return the target-specific publish scope already computed during discovery. */
|
|
81
|
+
export function getPublishedPackagePaths(target: ReleaseTarget): string[] {
|
|
82
|
+
return [...target.publishScopePaths];
|
|
97
83
|
}
|
|
98
84
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
85
|
+
/** Resolve the effective tag format for a selected target. */
|
|
86
|
+
export function getReleaseTagFormat(target: ReleaseTarget, rootTagFormat: string): string {
|
|
87
|
+
return target.kind === "root" ? rootTagFormat : target.defaultTagFormat;
|
|
102
88
|
}
|
|
103
89
|
|
|
104
|
-
|
|
90
|
+
function getTagFormatsForTarget(target: ReleaseTarget, rootTagFormat: string): string[] {
|
|
91
|
+
const effectiveTagFormat = getReleaseTagFormat(target, rootTagFormat);
|
|
92
|
+
return target.kind === "root"
|
|
93
|
+
? [...new Set([effectiveTagFormat, LEGACY_RELEASE_TAG_FORMAT])]
|
|
94
|
+
: [effectiveTagFormat];
|
|
95
|
+
}
|
|
105
96
|
|
|
106
97
|
function escapeRegExp(value: string): string {
|
|
107
98
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -117,9 +108,15 @@ function extractVersionFromTag(tag: string, tagFormat: string): string | null {
|
|
|
117
108
|
return match?.[1] ?? null;
|
|
118
109
|
}
|
|
119
110
|
|
|
120
|
-
function parseReleaseTag(tag: string,
|
|
121
|
-
|
|
122
|
-
|
|
111
|
+
function parseReleaseTag(tag: string, target: ReleaseTarget, rootTagFormat: string): ParsedReleaseTag | null {
|
|
112
|
+
for (const tagFormat of getTagFormatsForTarget(target, rootTagFormat)) {
|
|
113
|
+
const version = extractVersionFromTag(tag, tagFormat);
|
|
114
|
+
if (version) {
|
|
115
|
+
return { tag, version };
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return null;
|
|
123
120
|
}
|
|
124
121
|
|
|
125
122
|
function compareSemver(left: string, right: string): number {
|
|
@@ -142,10 +139,10 @@ function compareSemver(left: string, right: string): number {
|
|
|
142
139
|
return left.includes("-") ? -1 : 1;
|
|
143
140
|
}
|
|
144
141
|
|
|
145
|
-
async function isTagAtHead(exec: ExecFn,
|
|
142
|
+
async function isTagAtHead(exec: ExecFn, repoRoot: string, tag: string): Promise<boolean> {
|
|
146
143
|
const [tagCommit, headCommit] = await Promise.all([
|
|
147
|
-
exec("git", ["rev-list", "-n", "1", tag], { cwd }),
|
|
148
|
-
exec("git", ["rev-parse", "HEAD"], { cwd }),
|
|
144
|
+
exec("git", ["rev-list", "-n", "1", tag], { cwd: repoRoot }),
|
|
145
|
+
exec("git", ["rev-parse", "HEAD"], { cwd: repoRoot }),
|
|
149
146
|
]);
|
|
150
147
|
|
|
151
148
|
return tagCommit.code === 0
|
|
@@ -154,14 +151,39 @@ async function isTagAtHead(exec: ExecFn, cwd: string, tag: string): Promise<bool
|
|
|
154
151
|
&& tagCommit.stdout.trim() === headCommit.stdout.trim();
|
|
155
152
|
}
|
|
156
153
|
|
|
154
|
+
export async function getLatestReleaseTag(
|
|
155
|
+
exec: ExecFn,
|
|
156
|
+
target: ReleaseTarget,
|
|
157
|
+
rootTagFormat: string,
|
|
158
|
+
): Promise<string | null> {
|
|
159
|
+
try {
|
|
160
|
+
const localTags = await exec("git", ["tag", "--merged", "HEAD"], { cwd: target.repoRoot });
|
|
161
|
+
if (localTags.code !== 0) {
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const latest = localTags.stdout
|
|
166
|
+
.split(/\r?\n/)
|
|
167
|
+
.map((tag) => tag.trim())
|
|
168
|
+
.filter(Boolean)
|
|
169
|
+
.map((tag) => parseReleaseTag(tag, target, rootTagFormat))
|
|
170
|
+
.filter((candidate): candidate is ParsedReleaseTag => Boolean(candidate))
|
|
171
|
+
.sort((left, right) => compareSemver(right.version, left.version))[0];
|
|
172
|
+
|
|
173
|
+
return latest?.tag ?? null;
|
|
174
|
+
} catch {
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
157
179
|
export async function findResumableLocalRelease(
|
|
158
180
|
exec: ExecFn,
|
|
159
|
-
|
|
181
|
+
target: ReleaseTarget,
|
|
160
182
|
currentVersion: string,
|
|
161
|
-
|
|
183
|
+
rootTagFormat: string,
|
|
162
184
|
): Promise<{ version: string; tag: string } | null> {
|
|
163
185
|
try {
|
|
164
|
-
const localTags = await exec("git", ["tag", "--merged", "HEAD"], { cwd });
|
|
186
|
+
const localTags = await exec("git", ["tag", "--merged", "HEAD"], { cwd: target.repoRoot });
|
|
165
187
|
if (localTags.code !== 0) {
|
|
166
188
|
return null;
|
|
167
189
|
}
|
|
@@ -170,18 +192,18 @@ export async function findResumableLocalRelease(
|
|
|
170
192
|
.split(/\r?\n/)
|
|
171
193
|
.map((tag) => tag.trim())
|
|
172
194
|
.filter(Boolean)
|
|
173
|
-
.map((tag) => parseReleaseTag(tag,
|
|
195
|
+
.map((tag) => parseReleaseTag(tag, target, rootTagFormat))
|
|
174
196
|
.filter((candidate): candidate is ParsedReleaseTag => Boolean(candidate))
|
|
175
197
|
.filter((candidate) => compareSemver(candidate.version, currentVersion) > 0)
|
|
176
198
|
.sort((left, right) => compareSemver(right.version, left.version));
|
|
177
199
|
|
|
178
200
|
for (const candidate of candidates) {
|
|
179
|
-
const remoteTag = await exec("git", ["ls-remote", "--tags", "origin", candidate.tag], { cwd });
|
|
201
|
+
const remoteTag = await exec("git", ["ls-remote", "--tags", "origin", candidate.tag], { cwd: target.repoRoot });
|
|
180
202
|
if (remoteTag.code !== 0 || remoteTag.stdout.trim() !== "") {
|
|
181
203
|
continue;
|
|
182
204
|
}
|
|
183
205
|
|
|
184
|
-
if (await isTagAtHead(exec,
|
|
206
|
+
if (await isTagAtHead(exec, target.repoRoot, candidate.tag)) {
|
|
185
207
|
return { version: candidate.version, tag: candidate.tag };
|
|
186
208
|
}
|
|
187
209
|
}
|
|
@@ -192,37 +214,41 @@ export async function findResumableLocalRelease(
|
|
|
192
214
|
}
|
|
193
215
|
}
|
|
194
216
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
217
|
+
function getReleaseTagCandidates(
|
|
218
|
+
target: ReleaseTarget,
|
|
219
|
+
version: string,
|
|
220
|
+
rootTagFormat: string,
|
|
221
|
+
): string[] {
|
|
222
|
+
return [...new Set(getTagFormatsForTarget(target, rootTagFormat).map((tagFormat) => formatTag(version, tagFormat)))];
|
|
200
223
|
}
|
|
201
224
|
|
|
202
225
|
async function hasMatchingReleaseTag(
|
|
203
226
|
exec: ExecFn,
|
|
204
|
-
|
|
227
|
+
target: ReleaseTarget,
|
|
205
228
|
args: string[],
|
|
206
229
|
version: string,
|
|
207
|
-
|
|
230
|
+
rootTagFormat: string,
|
|
208
231
|
): Promise<boolean> {
|
|
209
|
-
const result = await exec(
|
|
232
|
+
const result = await exec(
|
|
233
|
+
"git",
|
|
234
|
+
[...args, ...getReleaseTagCandidates(target, version, rootTagFormat)],
|
|
235
|
+
{ cwd: target.repoRoot },
|
|
236
|
+
);
|
|
210
237
|
return result.code === 0 && result.stdout.trim().length > 0;
|
|
211
238
|
}
|
|
212
239
|
|
|
213
240
|
/**
|
|
214
241
|
* Check whether a tag for the given version already exists locally.
|
|
215
|
-
*
|
|
216
|
-
* tag is already known locally, which means this version was already released.
|
|
242
|
+
* Root targets keep the legacy `v${version}` fallback; workspace targets do not.
|
|
217
243
|
*/
|
|
218
244
|
export async function isVersionReleased(
|
|
219
245
|
exec: ExecFn,
|
|
220
|
-
|
|
246
|
+
target: ReleaseTarget,
|
|
221
247
|
version: string,
|
|
222
|
-
|
|
248
|
+
rootTagFormat: string,
|
|
223
249
|
): Promise<boolean> {
|
|
224
250
|
try {
|
|
225
|
-
return await hasMatchingReleaseTag(exec,
|
|
251
|
+
return await hasMatchingReleaseTag(exec, target, ["tag", "-l"], version, rootTagFormat);
|
|
226
252
|
} catch {
|
|
227
253
|
return false;
|
|
228
254
|
}
|
|
@@ -230,17 +256,16 @@ export async function isVersionReleased(
|
|
|
230
256
|
|
|
231
257
|
/**
|
|
232
258
|
* Check whether a tag for the given version exists on the remote (origin).
|
|
233
|
-
*
|
|
234
|
-
* tag is found via `git ls-remote --tags origin`.
|
|
259
|
+
* Root targets keep the legacy `v${version}` fallback; workspace targets do not.
|
|
235
260
|
*/
|
|
236
261
|
export async function isTagOnRemote(
|
|
237
262
|
exec: ExecFn,
|
|
238
|
-
|
|
263
|
+
target: ReleaseTarget,
|
|
239
264
|
version: string,
|
|
240
|
-
|
|
265
|
+
rootTagFormat: string,
|
|
241
266
|
): Promise<boolean> {
|
|
242
267
|
try {
|
|
243
|
-
return await hasMatchingReleaseTag(exec,
|
|
268
|
+
return await hasMatchingReleaseTag(exec, target, ["ls-remote", "--tags", "origin"], version, rootTagFormat);
|
|
244
269
|
} catch {
|
|
245
270
|
return false;
|
|
246
271
|
}
|