@treeseed/sdk 0.10.27 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +207 -6
- package/dist/capacity-provider.d.ts +3 -1
- package/dist/capacity-provider.js +25 -5
- package/dist/control-plane.d.ts +1 -0
- package/dist/control-plane.js +38 -13
- package/dist/db/market-schema.d.ts +8860 -6172
- package/dist/db/market-schema.js +108 -0
- package/dist/db/node-sqlite.js +7 -2
- package/dist/hosting/apps.d.ts +12 -0
- package/dist/hosting/apps.js +107 -0
- package/dist/hosting/builtins.d.ts +25 -0
- package/dist/hosting/builtins.js +791 -0
- package/dist/hosting/contracts.d.ts +207 -0
- package/dist/hosting/contracts.js +0 -0
- package/dist/hosting/graph.d.ts +192 -0
- package/dist/hosting/graph.js +1106 -0
- package/dist/hosting/index.d.ts +4 -0
- package/dist/hosting/index.js +4 -0
- package/dist/index.d.ts +11 -4
- package/dist/index.js +71 -7
- package/dist/managed-dependencies.js +1 -2
- package/dist/market-client.d.ts +63 -3
- package/dist/market-client.js +83 -11
- package/dist/operations/services/bootstrap-runner.d.ts +3 -1
- package/dist/operations/services/bootstrap-runner.js +22 -2
- package/dist/operations/services/config-runtime.d.ts +10 -5
- package/dist/operations/services/config-runtime.js +209 -66
- package/dist/operations/services/deploy.d.ts +70 -7
- package/dist/operations/services/deploy.js +579 -64
- package/dist/operations/services/deployment-readiness.d.ts +30 -0
- package/dist/operations/services/deployment-readiness.js +175 -0
- package/dist/operations/services/git-workflow.d.ts +2 -1
- package/dist/operations/services/git-workflow.js +9 -3
- package/dist/operations/services/github-actions-verification.d.ts +1 -0
- package/dist/operations/services/github-actions-verification.js +1 -0
- package/dist/operations/services/github-api.js +1 -1
- package/dist/operations/services/github-automation.d.ts +1 -1
- package/dist/operations/services/github-automation.js +4 -3
- package/dist/operations/services/github-credentials.d.ts +13 -0
- package/dist/operations/services/github-credentials.js +58 -0
- package/dist/operations/services/hosted-service-checks.d.ts +63 -0
- package/dist/operations/services/hosted-service-checks.js +327 -0
- package/dist/operations/services/hub-provider-launch.js +3 -3
- package/dist/operations/services/live-hosted-service-checks.d.ts +25 -0
- package/dist/operations/services/live-hosted-service-checks.js +350 -0
- package/dist/operations/services/managed-host-security.js +1 -1
- package/dist/operations/services/operations-runner-smoke.d.ts +30 -0
- package/dist/operations/services/operations-runner-smoke.js +180 -0
- package/dist/operations/services/package-adapters.d.ts +95 -0
- package/dist/operations/services/package-adapters.js +288 -0
- package/dist/operations/services/package-reference-policy.d.ts +1 -0
- package/dist/operations/services/package-reference-policy.js +15 -2
- package/dist/operations/services/project-platform.d.ts +80 -22
- package/dist/operations/services/project-platform.js +49 -8
- package/dist/operations/services/project-web-monitor.js +26 -4
- package/dist/operations/services/railway-api.d.ts +88 -5
- package/dist/operations/services/railway-api.js +626 -35
- package/dist/operations/services/railway-deploy.d.ts +46 -40
- package/dist/operations/services/railway-deploy.js +261 -293
- package/dist/operations/services/release-candidate.d.ts +19 -0
- package/dist/operations/services/release-candidate.js +375 -38
- package/dist/operations/services/repository-save-orchestrator.d.ts +3 -1
- package/dist/operations/services/repository-save-orchestrator.js +279 -66
- package/dist/operations/services/runtime-tools.d.ts +1 -0
- package/dist/operations/services/runtime-tools.js +10 -9
- package/dist/operations/services/template-registry.js +14 -7
- package/dist/operations/services/verification-cache.d.ts +25 -0
- package/dist/operations/services/verification-cache.js +71 -0
- package/dist/operations/services/workspace-dependency-mode.js +9 -1
- package/dist/operations/services/workspace-save.js +1 -1
- package/dist/operations/services/workspace-tools.js +2 -1
- package/dist/platform/contracts.d.ts +32 -1
- package/dist/platform/deploy-config.js +73 -8
- package/dist/platform/env.yaml +163 -35
- package/dist/platform/environment.d.ts +1 -0
- package/dist/platform/environment.js +74 -5
- package/dist/platform/plugin.d.ts +9 -0
- package/dist/platform-operation-store.js +2 -2
- package/dist/platform-operations.js +1 -1
- package/dist/reconcile/bootstrap-systems.js +2 -2
- package/dist/reconcile/builtin-adapters.js +372 -189
- package/dist/reconcile/contracts.d.ts +9 -5
- package/dist/reconcile/desired-state.d.ts +1 -0
- package/dist/reconcile/desired-state.js +5 -5
- package/dist/reconcile/engine.d.ts +5 -2
- package/dist/reconcile/engine.js +53 -32
- package/dist/reconcile/index.d.ts +2 -0
- package/dist/reconcile/index.js +2 -0
- package/dist/reconcile/live-acceptance.d.ts +79 -0
- package/dist/reconcile/live-acceptance.js +1615 -0
- package/dist/reconcile/platform.d.ts +104 -0
- package/dist/reconcile/platform.js +100 -0
- package/dist/reconcile/state.js +4 -4
- package/dist/reconcile/units.js +2 -2
- package/dist/scripts/deployment-readiness.js +20 -0
- package/dist/scripts/generate-treedx-openapi-types.js +186 -0
- package/dist/scripts/operations-runner-smoke.js +16 -0
- package/dist/scripts/release-verify.js +4 -1
- package/dist/scripts/template-catalog.test.js +7 -7
- package/dist/scripts/tenant-workflow-action.js +10 -1
- package/dist/sdk-types.d.ts +172 -5
- package/dist/sdk-types.js +28 -3
- package/dist/sdk.d.ts +35 -24
- package/dist/sdk.js +186 -17
- package/dist/template-launch-requirements.js +9 -0
- package/dist/treedx/adapters.d.ts +6 -0
- package/dist/treedx/adapters.js +36 -0
- package/dist/treedx/client.d.ts +222 -0
- package/dist/treedx/client.js +871 -0
- package/dist/treedx/errors.d.ts +13 -0
- package/dist/treedx/errors.js +17 -0
- package/dist/treedx/federated-client.d.ts +27 -0
- package/dist/treedx/federated-client.js +158 -0
- package/dist/treedx/generated/openapi-types.d.ts +3558 -0
- package/dist/treedx/generated/openapi-types.js +0 -0
- package/dist/treedx/graph-adapter.d.ts +33 -0
- package/dist/treedx/graph-adapter.js +156 -0
- package/dist/treedx/index.d.ts +14 -0
- package/dist/treedx/index.js +48 -0
- package/dist/treedx/market-integration.d.ts +27 -0
- package/dist/treedx/market-integration.js +131 -0
- package/dist/treedx/ports.d.ts +166 -0
- package/dist/treedx/ports.js +231 -0
- package/dist/treedx/query-adapter.d.ts +19 -0
- package/dist/treedx/query-adapter.js +62 -0
- package/dist/treedx/registry-client.d.ts +11 -0
- package/dist/treedx/registry-client.js +19 -0
- package/dist/treedx/repository-adapter.d.ts +45 -0
- package/dist/treedx/repository-adapter.js +308 -0
- package/dist/treedx/sdk-integration.d.ts +27 -0
- package/dist/treedx/sdk-integration.js +63 -0
- package/dist/treedx/types.d.ts +1084 -0
- package/dist/treedx/types.js +8 -0
- package/dist/treedx/workspace-adapter.d.ts +27 -0
- package/dist/treedx/workspace-adapter.js +65 -0
- package/dist/treedx-backends.d.ts +218 -0
- package/dist/treedx-backends.js +632 -0
- package/dist/treedx-client.d.ts +86 -0
- package/dist/treedx-client.js +175 -0
- package/dist/treeseed/template-catalog/catalog.fixture.json +497 -138
- package/dist/workflow/operations.d.ts +119 -13
- package/dist/workflow/operations.js +309 -53
- package/dist/workflow-state.d.ts +13 -0
- package/dist/workflow-state.js +43 -26
- package/dist/workflow-support.d.ts +11 -3
- package/dist/workflow-support.js +67 -3
- package/dist/workflow.d.ts +5 -0
- package/drizzle/market/0004_treedx_market_integration.sql +99 -0
- package/package.json +34 -3
- package/templates/github/deploy-web.workflow.yml +39 -6
- package/dist/treeseed/template-catalog/templates/starter-basic/template/astro.config.d.ts +0 -3
- package/dist/treeseed/template-catalog/templates/starter-basic/template/astro.config.ts +0 -6
- package/dist/treeseed/template-catalog/templates/starter-basic/template/package.json +0 -35
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/api/server.js +0 -4
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/config.yaml +0 -65
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/decisions/adopt-initial-proposal-loop.mdx +0 -22
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/empty/.gitkeep +0 -1
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/knowledge/handbook/index.mdx +0 -11
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/pages/welcome.mdx +0 -11
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/people/starter-steward.mdx +0 -11
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/proposals/establish-initial-proposal-loop.mdx +0 -17
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content.config.d.ts +0 -1
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content.config.ts +0 -3
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/env.yaml +0 -1
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/manifest.yaml +0 -26
- package/dist/treeseed/template-catalog/templates/starter-basic/template/treeseed.site.yaml +0 -74
- package/dist/treeseed/template-catalog/templates/starter-basic/template/tsconfig.json +0 -9
- package/dist/treeseed/template-catalog/templates/starter-basic/template.config.json +0 -103
|
@@ -2,6 +2,7 @@ import { type GitRemoteWriteMode } from './git-remote-policy.ts';
|
|
|
2
2
|
import { type CommitMessageContext, type CommitMessageProvider, type CommitMessageProviderMode } from './commit-message-provider.ts';
|
|
3
3
|
import { type DevDependencyReferenceMode, type GitDependencyProtocol } from './package-reference-policy.ts';
|
|
4
4
|
import { type BuildWarningPolicyOptions } from './build-warning-policy.js';
|
|
5
|
+
import { type TreeseedPackageCommand } from './package-adapters.ts';
|
|
5
6
|
export type RepoKind = 'package' | 'project';
|
|
6
7
|
export type RepoBranchMode = 'package-release-main' | 'package-dev-save' | 'project-save';
|
|
7
8
|
export type SaveVerifyMode = 'action-first' | 'local-only' | 'skip';
|
|
@@ -19,6 +20,7 @@ export type RepositorySaveNode = {
|
|
|
19
20
|
packageJsonPath: string | null;
|
|
20
21
|
packageJson: Record<string, unknown> | null;
|
|
21
22
|
scripts: Record<string, string>;
|
|
23
|
+
manifestVerifyCommands: Record<'fast' | 'local' | 'release', TreeseedPackageCommand | null>;
|
|
22
24
|
remoteUrl: string | null;
|
|
23
25
|
dependencies: string[];
|
|
24
26
|
dependents: string[];
|
|
@@ -60,7 +62,7 @@ export type RepositorySaveReport = {
|
|
|
60
62
|
export type RepositoryVerificationResult = {
|
|
61
63
|
mode: SaveVerifyMode;
|
|
62
64
|
status: 'passed' | 'failed' | 'skipped';
|
|
63
|
-
primary: 'verify:action' | 'verify:local' | null;
|
|
65
|
+
primary: 'verify:action' | 'verify:local' | 'manifest:fast' | 'manifest:local' | 'manifest:release' | null;
|
|
64
66
|
fallbackUsed: boolean;
|
|
65
67
|
error: string | null;
|
|
66
68
|
};
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { existsSync,
|
|
2
|
-
import { tmpdir } from "node:os";
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
2
|
import { basename, resolve, relative } from "node:path";
|
|
4
3
|
import { spawn, spawnSync } from "node:child_process";
|
|
5
4
|
import {
|
|
@@ -37,11 +36,18 @@ import {
|
|
|
37
36
|
sortWorkspacePackages,
|
|
38
37
|
workspacePackages
|
|
39
38
|
} from "./workspace-tools.js";
|
|
40
|
-
import { collectDeploymentLockfileWorkspaceIssues } from "./workspace-dependency-mode.js";
|
|
39
|
+
import { collectDeploymentLockfileWorkspaceIssues, ensureLocalWorkspaceLinks } from "./workspace-dependency-mode.js";
|
|
41
40
|
import {
|
|
42
41
|
createBuildWarningSummary,
|
|
43
42
|
formatAllowedBuildWarnings
|
|
44
43
|
} from "./build-warning-policy.js";
|
|
44
|
+
import {
|
|
45
|
+
readTreeseedVerificationCache,
|
|
46
|
+
writeTreeseedVerificationCache
|
|
47
|
+
} from "./verification-cache.js";
|
|
48
|
+
import {
|
|
49
|
+
discoverTreeseedPackageAdapters
|
|
50
|
+
} from "./package-adapters.js";
|
|
45
51
|
class RepositorySaveError extends Error {
|
|
46
52
|
exitCode;
|
|
47
53
|
details;
|
|
@@ -261,6 +267,13 @@ function isGitRepo(repoDir) {
|
|
|
261
267
|
return false;
|
|
262
268
|
}
|
|
263
269
|
}
|
|
270
|
+
function isIndependentGitRepo(repoDir) {
|
|
271
|
+
try {
|
|
272
|
+
return resolve(repoRoot(repoDir)) === resolve(repoDir);
|
|
273
|
+
} catch {
|
|
274
|
+
return false;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
264
277
|
function originRemoteUrlSafe(repoDir) {
|
|
265
278
|
try {
|
|
266
279
|
return originRemoteUrl(repoDir);
|
|
@@ -278,6 +291,9 @@ function ensureWritableRemote(node, options) {
|
|
|
278
291
|
function repoDisplayName(repoDir, packageJson) {
|
|
279
292
|
return typeof packageJson?.name === "string" && packageJson.name.length > 0 ? packageJson.name : basename(repoDir);
|
|
280
293
|
}
|
|
294
|
+
function emptyManifestVerifyCommands() {
|
|
295
|
+
return { fast: null, local: null, release: null };
|
|
296
|
+
}
|
|
281
297
|
function parseGitmodules(root) {
|
|
282
298
|
const gitmodulesPath = resolve(root, ".gitmodules");
|
|
283
299
|
if (!existsSync(gitmodulesPath)) {
|
|
@@ -319,6 +335,9 @@ function packageVersionAtHead(node) {
|
|
|
319
335
|
return null;
|
|
320
336
|
}
|
|
321
337
|
}
|
|
338
|
+
function canManagePackageJsonVersion(node) {
|
|
339
|
+
return node.kind === "package" && Boolean(node.packageJsonPath) && typeof node.packageJson?.version === "string";
|
|
340
|
+
}
|
|
322
341
|
function packageVersionEligibleForBranch(node, version, options) {
|
|
323
342
|
return node.branchMode === "package-release-main" ? isStableSemverVersion(version) : isDevVersionForBranch(version, node.branch || options.branch);
|
|
324
343
|
}
|
|
@@ -378,28 +397,35 @@ function createReport(node) {
|
|
|
378
397
|
function discoverRepositorySaveNodes(root, gitRoot = repoRoot(root), branch = currentBranch(gitRoot), options = {}) {
|
|
379
398
|
const repoDirs = /* @__PURE__ */ new Map();
|
|
380
399
|
repoDirs.set(".", gitRoot);
|
|
400
|
+
const packageAdaptersByDir = new Map(discoverTreeseedPackageAdapters(root).map((adapter) => [resolve(adapter.dir), adapter]));
|
|
381
401
|
if (hasCompleteTreeseedPackageCheckout(root)) {
|
|
382
402
|
for (const pkg of workspacePackages(root)) {
|
|
383
|
-
if (
|
|
403
|
+
if (isIndependentGitRepo(pkg.dir)) {
|
|
384
404
|
repoDirs.set(pkg.relativeDir, pkg.dir);
|
|
385
405
|
}
|
|
386
406
|
}
|
|
387
407
|
}
|
|
408
|
+
for (const adapter of packageAdaptersByDir.values()) {
|
|
409
|
+
if (isIndependentGitRepo(adapter.dir)) {
|
|
410
|
+
repoDirs.set(adapter.relativeDir, adapter.dir);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
388
413
|
for (const submodulePath of parseGitmodules(root)) {
|
|
389
414
|
const dir = resolve(root, submodulePath);
|
|
390
|
-
if (existsSync(dir) &&
|
|
415
|
+
if (existsSync(dir) && isIndependentGitRepo(dir)) {
|
|
391
416
|
repoDirs.set(submodulePath, dir);
|
|
392
417
|
}
|
|
393
418
|
}
|
|
394
419
|
const nodes = [...repoDirs.entries()].map(([relativePath, repoDir]) => {
|
|
395
420
|
const packageJsonPath = resolve(repoDir, "package.json");
|
|
396
421
|
const packageJson = existsSync(packageJsonPath) ? readJson(packageJsonPath) : null;
|
|
397
|
-
const
|
|
422
|
+
const adapter = packageAdaptersByDir.get(resolve(repoDir)) ?? null;
|
|
423
|
+
const kind = adapter && !packageJson ? "package" : classifyRepoKind(packageJson);
|
|
398
424
|
const repoBranch = relativePath === "." ? currentBranch(repoDir) || branch || null : branch || currentBranch(repoDir) || null;
|
|
399
425
|
const branchMode = kind === "project" ? "project-save" : options.stablePackageRelease === true && repoBranch === PRODUCTION_BRANCH ? "package-release-main" : "package-dev-save";
|
|
400
426
|
return {
|
|
401
427
|
id: relativePath,
|
|
402
|
-
name: repoDisplayName(repoDir, packageJson),
|
|
428
|
+
name: adapter?.id ?? repoDisplayName(repoDir, packageJson),
|
|
403
429
|
path: repoDir,
|
|
404
430
|
relativePath,
|
|
405
431
|
kind,
|
|
@@ -408,6 +434,7 @@ function discoverRepositorySaveNodes(root, gitRoot = repoRoot(root), branch = cu
|
|
|
408
434
|
packageJsonPath: packageJson ? packageJsonPath : null,
|
|
409
435
|
packageJson,
|
|
410
436
|
scripts: packageScripts(packageJson),
|
|
437
|
+
manifestVerifyCommands: adapter?.verifyCommands ?? emptyManifestVerifyCommands(),
|
|
411
438
|
remoteUrl: originRemoteUrlSafe(repoDir),
|
|
412
439
|
dependencies: [],
|
|
413
440
|
dependents: [],
|
|
@@ -554,7 +581,12 @@ function commitSubject(message) {
|
|
|
554
581
|
}
|
|
555
582
|
function gitDiffSummary(repoDir) {
|
|
556
583
|
const changedFiles = run("git", ["status", "--porcelain"], { cwd: repoDir, capture: true });
|
|
557
|
-
const
|
|
584
|
+
const rawDiff = run("git", ["diff", "--cached"], { cwd: repoDir, capture: true, maxBuffer: 1024 * 1024 * 32 });
|
|
585
|
+
const maxDiffChars = 12e4;
|
|
586
|
+
const diff = rawDiff.length > maxDiffChars ? `${rawDiff.slice(0, maxDiffChars)}
|
|
587
|
+
|
|
588
|
+
[treeseed-save: diff truncated from ${rawDiff.length} characters for commit-message generation]
|
|
589
|
+
` : rawDiff;
|
|
558
590
|
return { changedFiles, diff };
|
|
559
591
|
}
|
|
560
592
|
function hasStagedChanges(repoDir) {
|
|
@@ -593,43 +625,100 @@ function shouldSkipGitDependencySmoke(options) {
|
|
|
593
625
|
function hasNpmLockfile(repoDir) {
|
|
594
626
|
return existsSync(resolve(repoDir, "package-lock.json")) || existsSync(resolve(repoDir, "npm-shrinkwrap.json"));
|
|
595
627
|
}
|
|
596
|
-
|
|
597
|
-
if (
|
|
598
|
-
const
|
|
599
|
-
|
|
600
|
-
const
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
628
|
+
function syncRootWorkspaceLockfileMetadata(node, options) {
|
|
629
|
+
if (node.path !== options.root || !Array.isArray(node.packageJson?.workspaces)) return false;
|
|
630
|
+
const lockfilePath = resolve(node.path, "package-lock.json");
|
|
631
|
+
if (!existsSync(lockfilePath)) return false;
|
|
632
|
+
const lockfile = readJson(lockfilePath);
|
|
633
|
+
const packages = lockfile.packages;
|
|
634
|
+
if (!packages || typeof packages !== "object" || Array.isArray(packages)) return false;
|
|
635
|
+
let changed = false;
|
|
636
|
+
const packageEntries = packages;
|
|
637
|
+
const rootEntry = packageEntries[""] ?? {};
|
|
638
|
+
if (JSON.stringify(rootEntry.workspaces ?? []) !== JSON.stringify(node.packageJson.workspaces)) {
|
|
639
|
+
rootEntry.workspaces = node.packageJson.workspaces;
|
|
640
|
+
packageEntries[""] = rootEntry;
|
|
641
|
+
changed = true;
|
|
642
|
+
}
|
|
643
|
+
for (const field of dependencyFields(node.packageJson)) {
|
|
644
|
+
const nextValue = node.packageJson[field];
|
|
645
|
+
if (nextValue && typeof nextValue === "object" && !Array.isArray(nextValue)) {
|
|
646
|
+
const currentValue = rootEntry[field];
|
|
647
|
+
const currentDeps = currentValue && typeof currentValue === "object" && !Array.isArray(currentValue) ? currentValue : {};
|
|
648
|
+
const mergedDeps = { ...currentDeps };
|
|
649
|
+
let fieldChanged = false;
|
|
650
|
+
for (const [dependencyName, dependencySpec] of Object.entries(nextValue)) {
|
|
651
|
+
if (mergedDeps[dependencyName] != null) continue;
|
|
652
|
+
mergedDeps[dependencyName] = dependencySpec;
|
|
653
|
+
fieldChanged = true;
|
|
610
654
|
}
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
try {
|
|
616
|
-
await runStreamingCommand(node, options, "smoke", "npm", ["install", "--cache", npmCacheRoot], { cwd: tempRoot });
|
|
617
|
-
return;
|
|
618
|
-
} catch (error) {
|
|
619
|
-
lastError = error instanceof Error ? error.message : String(error);
|
|
655
|
+
if (fieldChanged) {
|
|
656
|
+
rootEntry[field] = mergedDeps;
|
|
657
|
+
packageEntries[""] = rootEntry;
|
|
658
|
+
changed = true;
|
|
620
659
|
}
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
for (const workspacePackage of workspacePackages(node.path)) {
|
|
663
|
+
const relativeDir = workspacePackage.relativeDir.replace(/\\/gu, "/");
|
|
664
|
+
const packageJson = workspacePackage.packageJson;
|
|
665
|
+
const packageName = String(packageJson.name ?? "");
|
|
666
|
+
if (!packageName) continue;
|
|
667
|
+
const packageEntry = packageEntries[relativeDir] ?? {};
|
|
668
|
+
if (packageEntry.name !== packageName) {
|
|
669
|
+
packageEntry.name = packageName;
|
|
670
|
+
changed = true;
|
|
671
|
+
}
|
|
672
|
+
if (typeof packageJson.version === "string" && packageEntry.version !== packageJson.version) {
|
|
673
|
+
packageEntry.version = packageJson.version;
|
|
674
|
+
changed = true;
|
|
675
|
+
}
|
|
676
|
+
for (const field of dependencyFields(packageJson)) {
|
|
677
|
+
const nextValue = packageJson[field];
|
|
678
|
+
if (nextValue && typeof nextValue === "object" && !Array.isArray(nextValue)) {
|
|
679
|
+
if (JSON.stringify(packageEntry[field] ?? {}) !== JSON.stringify(nextValue)) {
|
|
680
|
+
packageEntry[field] = nextValue;
|
|
681
|
+
changed = true;
|
|
682
|
+
}
|
|
624
683
|
}
|
|
625
684
|
}
|
|
685
|
+
packageEntries[relativeDir] = packageEntry;
|
|
686
|
+
const linkKey = `node_modules/${packageName}`;
|
|
687
|
+
const linkEntry = packageEntries[linkKey] ?? {};
|
|
688
|
+
if (linkEntry.resolved !== relativeDir) {
|
|
689
|
+
linkEntry.resolved = relativeDir;
|
|
690
|
+
changed = true;
|
|
691
|
+
}
|
|
692
|
+
if (linkEntry.link !== true) {
|
|
693
|
+
linkEntry.link = true;
|
|
694
|
+
changed = true;
|
|
695
|
+
}
|
|
696
|
+
packageEntries[linkKey] = linkEntry;
|
|
697
|
+
}
|
|
698
|
+
if (!changed) return false;
|
|
699
|
+
lockfile.packages = packageEntries;
|
|
700
|
+
writeJson(lockfilePath, lockfile);
|
|
701
|
+
emitProgress(options, node, "lockfile", "Synchronized root workspace lockfile metadata before validation.");
|
|
702
|
+
return true;
|
|
703
|
+
}
|
|
704
|
+
async function runGitDependencySmoke(node, options, reference) {
|
|
705
|
+
if (reference.mode !== "dev-git-tag" || shouldSkipGitDependencySmoke(options)) return;
|
|
706
|
+
const tagName = reference.tagName ?? reference.version;
|
|
707
|
+
if (!reference.remoteUrl || !tagName) {
|
|
708
|
+
throw new RepositorySaveError(`Git dependency smoke cannot verify ${reference.packageName}; remote URL or tag is missing.`);
|
|
709
|
+
}
|
|
710
|
+
const tagRef = `refs/tags/${tagName}`;
|
|
711
|
+
emitProgress(options, node, "smoke", `Verifying ${reference.packageName} tag ${tagName} exists on ${reference.remoteUrl}.`);
|
|
712
|
+
try {
|
|
713
|
+
await runStreamingCommand(node, options, "smoke", "git", ["ls-remote", "--exit-code", "--tags", reference.remoteUrl, tagRef]);
|
|
714
|
+
} catch (error) {
|
|
715
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
626
716
|
throw new RepositorySaveError([
|
|
627
|
-
`Git dependency smoke
|
|
628
|
-
`
|
|
629
|
-
|
|
717
|
+
`Git dependency smoke failed for ${reference.packageName}; tag is not reachable on the remote.`,
|
|
718
|
+
`Remote: ${reference.remoteUrl}`,
|
|
719
|
+
`Tag: ${tagName}`,
|
|
720
|
+
detail
|
|
630
721
|
].join("\n"));
|
|
631
|
-
} finally {
|
|
632
|
-
rmSync(tempRoot, { recursive: true, force: true });
|
|
633
722
|
}
|
|
634
723
|
}
|
|
635
724
|
async function runNpmInstallWithRetry(node, options, gitDependencyRefreshSpecs = []) {
|
|
@@ -640,7 +729,7 @@ async function runNpmInstallWithRetry(node, options, gitDependencyRefreshSpecs =
|
|
|
640
729
|
let lastError = null;
|
|
641
730
|
const packageJson = node.packageJson ?? (existsSync(resolve(node.path, "package.json")) ? readJson(resolve(node.path, "package.json")) : null);
|
|
642
731
|
const rootWorkspaceInstall = node.path === options.root && Array.isArray(packageJson?.workspaces);
|
|
643
|
-
const installFlags = ["--package-lock-only", "--ignore-scripts"];
|
|
732
|
+
const installFlags = rootWorkspaceInstall ? ["--package-lock-only", "--ignore-scripts"] : node.branchMode === "project-save" ? ["--ignore-scripts"] : ["--package-lock-only", "--ignore-scripts"];
|
|
644
733
|
const args = rootWorkspaceInstall ? gitDependencyRefreshSpecs.length > 0 ? ["install", ...gitDependencyRefreshSpecs, ...installFlags, "--force"] : ["install", ...installFlags] : gitDependencyRefreshSpecs.length > 0 ? ["install", ...gitDependencyRefreshSpecs, ...installFlags, "--force", "--workspaces=false"] : ["install", ...installFlags, "--workspaces=false"];
|
|
645
734
|
for (let attempt = 1; attempt <= 5; attempt += 1) {
|
|
646
735
|
emitProgress(options, node, "install", `npm ${args.join(" ")} attempt ${attempt}/5.`);
|
|
@@ -658,6 +747,36 @@ async function runNpmInstallWithRetry(node, options, gitDependencyRefreshSpecs =
|
|
|
658
747
|
throw new RepositorySaveError(`npm install failed after 5 attempts.
|
|
659
748
|
${lastError ?? ""}`);
|
|
660
749
|
}
|
|
750
|
+
async function runProjectVerificationInstallWithRetry(node, options) {
|
|
751
|
+
if (node.branchMode !== "project-save" || !hasNpmLockfile(node.path)) return;
|
|
752
|
+
if (shouldSkipNetworkInstall()) {
|
|
753
|
+
emitProgress(options, node, "install", "Skipped project verification dependency install because network install mode is disabled.");
|
|
754
|
+
return;
|
|
755
|
+
}
|
|
756
|
+
let lastError = null;
|
|
757
|
+
const packageJson = node.packageJson ?? (existsSync(resolve(node.path, "package.json")) ? readJson(resolve(node.path, "package.json")) : null);
|
|
758
|
+
const rootWorkspaceInstall = node.path === options.root && Array.isArray(packageJson?.workspaces);
|
|
759
|
+
if (rootWorkspaceInstall) {
|
|
760
|
+
emitProgress(options, node, "install", "Skipped root npm ci project verification install; lockfile dry-run and restored workspace links provide save-time dependency proof.");
|
|
761
|
+
return;
|
|
762
|
+
}
|
|
763
|
+
const args = rootWorkspaceInstall ? ["ci"] : ["ci", "--workspaces=false"];
|
|
764
|
+
for (let attempt = 1; attempt <= 5; attempt += 1) {
|
|
765
|
+
emitProgress(options, node, "install", `npm ${args.join(" ")} for project verification attempt ${attempt}/5.`);
|
|
766
|
+
try {
|
|
767
|
+
await runStreamingCommand(node, options, "install", "npm", args);
|
|
768
|
+
return;
|
|
769
|
+
} catch (error) {
|
|
770
|
+
lastError = error instanceof Error ? error.message : String(error);
|
|
771
|
+
}
|
|
772
|
+
if (attempt < 5) {
|
|
773
|
+
emitProgress(options, node, "install", "npm ci for project verification failed; retrying in 60 seconds.", "stderr");
|
|
774
|
+
spawnSync("sleep", ["60"], { stdio: "ignore" });
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
throw new RepositorySaveError(`Project verification dependency install failed after 5 attempts.
|
|
778
|
+
${lastError ?? ""}`);
|
|
779
|
+
}
|
|
661
780
|
function lockfileValidationCommand(node, options) {
|
|
662
781
|
const packageJson = node.packageJson ?? (existsSync(resolve(node.path, "package.json")) ? readJson(resolve(node.path, "package.json")) : null);
|
|
663
782
|
const rootWorkspaceInstall = node.path === options.root && Array.isArray(packageJson?.workspaces);
|
|
@@ -668,6 +787,7 @@ async function validateRepositoryLockfile(node, options) {
|
|
|
668
787
|
if (!hasNpmLockfile(node.path)) {
|
|
669
788
|
return { status: "skipped", command: null, issues: [], error: "no npm lockfile" };
|
|
670
789
|
}
|
|
790
|
+
syncRootWorkspaceLockfileMetadata(node, options);
|
|
671
791
|
const issues = collectDeploymentLockfileWorkspaceIssues(node.path).map((issue) => `${issue.filePath}: ${issue.packageName} ${issue.reason}`);
|
|
672
792
|
if (issues.length > 0) {
|
|
673
793
|
throw new RepositorySaveError([
|
|
@@ -713,38 +833,99 @@ async function validateRepositoryLockfile(node, options) {
|
|
|
713
833
|
function hasScript(node, scriptName) {
|
|
714
834
|
return typeof node.scripts[scriptName] === "string" && node.scripts[scriptName].length > 0;
|
|
715
835
|
}
|
|
836
|
+
function manifestVerifyCommand(node, key) {
|
|
837
|
+
return node.manifestVerifyCommands[key] ?? null;
|
|
838
|
+
}
|
|
839
|
+
function hasAnyVerificationCommand(node) {
|
|
840
|
+
return hasScript(node, "verify:action") || hasScript(node, "verify:local") || hasScript(node, "verify") || Boolean(manifestVerifyCommand(node, "local")) || Boolean(manifestVerifyCommand(node, "fast"));
|
|
841
|
+
}
|
|
716
842
|
async function runScript(node, options, scriptName) {
|
|
717
843
|
await runStreamingCommand(node, options, "verify", "npm", ["run", scriptName]);
|
|
718
844
|
}
|
|
845
|
+
async function runManifestVerifyCommand(node, options, verifyMode, key) {
|
|
846
|
+
const manifestCommand = manifestVerifyCommand(node, key);
|
|
847
|
+
if (!manifestCommand) {
|
|
848
|
+
throw new RepositorySaveError(`${node.name} is missing a ${key} verification command in treeseed.package.yaml.`);
|
|
849
|
+
}
|
|
850
|
+
const command = `${manifestCommand.command} ${manifestCommand.args.join(" ")}`;
|
|
851
|
+
const cacheInput = {
|
|
852
|
+
workspaceRoot: options.root,
|
|
853
|
+
repoName: node.name,
|
|
854
|
+
repoPath: node.path,
|
|
855
|
+
command,
|
|
856
|
+
verifyMode,
|
|
857
|
+
env: process.env
|
|
858
|
+
};
|
|
859
|
+
const cached = readTreeseedVerificationCache(cacheInput);
|
|
860
|
+
if (cached) {
|
|
861
|
+
emitProgress(options, node, "verify", `[verify][cache] Reused ${node.name} ${manifestCommand.label} for ${cached.headSha.slice(0, 12)}.`);
|
|
862
|
+
return { cached: true };
|
|
863
|
+
}
|
|
864
|
+
const started = Date.now();
|
|
865
|
+
await runStreamingCommand(node, options, "verify", manifestCommand.command, manifestCommand.args, { cwd: manifestCommand.cwd });
|
|
866
|
+
writeTreeseedVerificationCache(cacheInput, Date.now() - started);
|
|
867
|
+
return { cached: false };
|
|
868
|
+
}
|
|
869
|
+
async function runCachedScript(node, options, verifyMode, scriptName) {
|
|
870
|
+
const command = `npm run ${scriptName}`;
|
|
871
|
+
const cacheInput = {
|
|
872
|
+
workspaceRoot: options.root,
|
|
873
|
+
repoName: node.name,
|
|
874
|
+
repoPath: node.path,
|
|
875
|
+
command,
|
|
876
|
+
verifyMode,
|
|
877
|
+
env: process.env
|
|
878
|
+
};
|
|
879
|
+
const cached = readTreeseedVerificationCache(cacheInput);
|
|
880
|
+
if (cached) {
|
|
881
|
+
emitProgress(options, node, "verify", `[verify][cache] Reused ${node.name} ${scriptName} for ${cached.headSha.slice(0, 12)}.`);
|
|
882
|
+
return { cached: true };
|
|
883
|
+
}
|
|
884
|
+
const started = Date.now();
|
|
885
|
+
await runScript(node, options, scriptName);
|
|
886
|
+
writeTreeseedVerificationCache(cacheInput, Date.now() - started);
|
|
887
|
+
return { cached: false };
|
|
888
|
+
}
|
|
719
889
|
async function runRepoVerification(node, options, verifyMode) {
|
|
720
890
|
if (verifyMode === "skip") {
|
|
721
891
|
emitProgress(options, node, "verify", "Skipped verification by request.");
|
|
722
892
|
return { mode: verifyMode, status: "skipped", primary: null, fallbackUsed: false, error: null };
|
|
723
893
|
}
|
|
724
|
-
if (node.kind !== "package") {
|
|
725
|
-
emitProgress(options, node, "verify", "Skipped
|
|
894
|
+
if (node.kind !== "package" && !hasAnyVerificationCommand(node)) {
|
|
895
|
+
emitProgress(options, node, "verify", "Skipped verification because project repository does not declare a Treeseed verify script.");
|
|
726
896
|
return { mode: verifyMode, status: "skipped", primary: null, fallbackUsed: false, error: null };
|
|
727
897
|
}
|
|
898
|
+
await runProjectVerificationInstallWithRetry(node, options);
|
|
728
899
|
if (verifyMode === "local-only") {
|
|
900
|
+
if (hasScript(node, "verify:local")) {
|
|
901
|
+
await runCachedScript(node, options, verifyMode, "verify:local");
|
|
902
|
+
return { mode: verifyMode, status: "passed", primary: "verify:local", fallbackUsed: false, error: null };
|
|
903
|
+
}
|
|
904
|
+
if (manifestVerifyCommand(node, "local")) {
|
|
905
|
+
await runManifestVerifyCommand(node, options, verifyMode, "local");
|
|
906
|
+
return { mode: verifyMode, status: "passed", primary: "manifest:local", fallbackUsed: false, error: null };
|
|
907
|
+
}
|
|
908
|
+
if (manifestVerifyCommand(node, "fast")) {
|
|
909
|
+
await runManifestVerifyCommand(node, options, verifyMode, "fast");
|
|
910
|
+
return { mode: verifyMode, status: "passed", primary: "manifest:fast", fallbackUsed: false, error: null };
|
|
911
|
+
}
|
|
729
912
|
if (!hasScript(node, "verify:local")) {
|
|
730
|
-
throw new RepositorySaveError(
|
|
913
|
+
throw new RepositorySaveError(`${node.kind === "package" ? "Package" : "Project"} ${node.name} is missing required verify:local script.`);
|
|
731
914
|
}
|
|
732
|
-
await runScript(node, options, "verify:local");
|
|
733
|
-
return { mode: verifyMode, status: "passed", primary: "verify:local", fallbackUsed: false, error: null };
|
|
734
915
|
}
|
|
735
|
-
if (!
|
|
736
|
-
throw new RepositorySaveError(
|
|
916
|
+
if (!hasAnyVerificationCommand(node)) {
|
|
917
|
+
throw new RepositorySaveError(`${node.kind === "package" ? "Package" : "Project"} ${node.name} is missing required verify:action, verify:local, or verify script.`);
|
|
737
918
|
}
|
|
738
919
|
if (hasScript(node, "verify:action")) {
|
|
739
920
|
try {
|
|
740
|
-
await
|
|
921
|
+
await runCachedScript(node, options, verifyMode, "verify:action");
|
|
741
922
|
return { mode: verifyMode, status: "passed", primary: "verify:action", fallbackUsed: false, error: null };
|
|
742
923
|
} catch (error) {
|
|
743
924
|
if (!hasScript(node, "verify:local")) {
|
|
744
925
|
throw error;
|
|
745
926
|
}
|
|
746
927
|
emitProgress(options, node, "verify", "verify:action failed; falling back to verify:local.", "stderr");
|
|
747
|
-
await
|
|
928
|
+
await runCachedScript(node, options, verifyMode, "verify:local");
|
|
748
929
|
return {
|
|
749
930
|
mode: verifyMode,
|
|
750
931
|
status: "passed",
|
|
@@ -754,7 +935,19 @@ async function runRepoVerification(node, options, verifyMode) {
|
|
|
754
935
|
};
|
|
755
936
|
}
|
|
756
937
|
}
|
|
757
|
-
|
|
938
|
+
if (hasScript(node, "verify:local")) {
|
|
939
|
+
await runCachedScript(node, options, verifyMode, "verify:local");
|
|
940
|
+
return { mode: verifyMode, status: "passed", primary: "verify:local", fallbackUsed: true, error: null };
|
|
941
|
+
}
|
|
942
|
+
if (manifestVerifyCommand(node, "local")) {
|
|
943
|
+
await runManifestVerifyCommand(node, options, verifyMode, "local");
|
|
944
|
+
return { mode: verifyMode, status: "passed", primary: "manifest:local", fallbackUsed: true, error: null };
|
|
945
|
+
}
|
|
946
|
+
if (manifestVerifyCommand(node, "fast")) {
|
|
947
|
+
await runManifestVerifyCommand(node, options, verifyMode, "fast");
|
|
948
|
+
return { mode: verifyMode, status: "passed", primary: "manifest:fast", fallbackUsed: true, error: null };
|
|
949
|
+
}
|
|
950
|
+
await runCachedScript(node, options, verifyMode, "verify");
|
|
758
951
|
return { mode: verifyMode, status: "passed", primary: "verify:local", fallbackUsed: true, error: null };
|
|
759
952
|
}
|
|
760
953
|
function pullRebaseFromOrigin(node, options, branch) {
|
|
@@ -1007,7 +1200,7 @@ function refreshRepositoryNodePackageMetadata(node) {
|
|
|
1007
1200
|
node.packageJson = packageJson;
|
|
1008
1201
|
node.scripts = packageScripts(packageJson);
|
|
1009
1202
|
node.remoteUrl = originRemoteUrlSafe(node.path);
|
|
1010
|
-
if (node.kind === "package") {
|
|
1203
|
+
if (node.kind === "package" && packageJson) {
|
|
1011
1204
|
node.name = repoDisplayName(node.path, packageJson);
|
|
1012
1205
|
}
|
|
1013
1206
|
}
|
|
@@ -1117,7 +1310,7 @@ function repoPlanCommands(node, options, plannedVersion, plannedDependencySpec,
|
|
|
1117
1310
|
commands.push(`update package.json version to ${plannedVersion}`);
|
|
1118
1311
|
commands.push("npm install --workspaces=false # explicitly refresh changed git-tag dependencies with --force; retry up to 5 times with 60s delay");
|
|
1119
1312
|
} else if (node.kind === "project" && dependencyUpdates.length > 0 && hasNpmLockfile(node.path)) {
|
|
1120
|
-
commands.push(rootWorkspaceInstall ? "npm install # refresh root workspace lockfile
|
|
1313
|
+
commands.push(rootWorkspaceInstall ? "npm install --package-lock-only --ignore-scripts # refresh root workspace lockfile without installing git dependencies" : "npm install --workspaces=false # refresh project lockfile after internal dependency updates");
|
|
1121
1314
|
}
|
|
1122
1315
|
if (hasNpmLockfile(node.path) && (node.kind === "project" || plannedVersion || dependencyUpdates.length > 0 || node.submoduleDependencies.length > 0)) {
|
|
1123
1316
|
commands.push(rootWorkspaceInstall ? "npm ci --ignore-scripts --dry-run # validate root manifest, workspaces, and lockfile before commit" : "npm ci --ignore-scripts --dry-run --workspaces=false # validate deployment lockfile before commit");
|
|
@@ -1128,24 +1321,36 @@ function repoPlanCommands(node, options, plannedVersion, plannedDependencySpec,
|
|
|
1128
1321
|
commands.push(
|
|
1129
1322
|
remoteExists ? `git pull --rebase --recurse-submodules=no origin ${branch}` : `skip pull --rebase # origin/${branch} does not exist yet`
|
|
1130
1323
|
);
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1324
|
+
const verifyMode = options.verifyMode ?? "action-first";
|
|
1325
|
+
if (verifyMode === "skip") {
|
|
1326
|
+
commands.push(node.kind === "package" ? "skip package verification" : "skip project verification");
|
|
1327
|
+
} else if (hasScript(node, "verify:action") || hasScript(node, "verify:local") || hasScript(node, "verify")) {
|
|
1328
|
+
if (verifyMode === "local-only") {
|
|
1136
1329
|
commands.push("npm run verify:local");
|
|
1137
|
-
} else {
|
|
1330
|
+
} else if (hasScript(node, "verify:action")) {
|
|
1138
1331
|
commands.push("npm run verify:action # fallback to npm run verify:local on failure");
|
|
1332
|
+
} else if (hasScript(node, "verify:local")) {
|
|
1333
|
+
commands.push("npm run verify:local");
|
|
1334
|
+
} else {
|
|
1335
|
+
commands.push("npm run verify");
|
|
1139
1336
|
}
|
|
1337
|
+
} else if (manifestVerifyCommand(node, "local") || manifestVerifyCommand(node, "fast")) {
|
|
1338
|
+
const command = verifyMode === "local-only" ? manifestVerifyCommand(node, "local") ?? manifestVerifyCommand(node, "fast") : manifestVerifyCommand(node, "local") ?? manifestVerifyCommand(node, "fast");
|
|
1339
|
+
if (command) commands.push(`${command.command} ${command.args.join(" ")} # treeseed.package.yaml verification`);
|
|
1340
|
+
} else if (node.kind !== "package") {
|
|
1341
|
+
commands.push("skip verification # project repository has no Treeseed verify script");
|
|
1342
|
+
}
|
|
1343
|
+
if (node.kind === "package") {
|
|
1140
1344
|
if (plannedVersion) {
|
|
1141
1345
|
commands.push(`git tag -a ${plannedVersion} -m <${plannedVersion.includes("-dev.") ? "dev metadata" : "release"}>`);
|
|
1142
1346
|
commands.push(remoteExists ? `git push origin ${branch} ${plannedVersion}` : `git push -u origin ${branch} ${plannedVersion}`);
|
|
1143
1347
|
if (plannedDependencySpec && node.branchMode === "package-dev-save") {
|
|
1144
|
-
commands.push(`
|
|
1348
|
+
commands.push(`git ls-remote --exit-code --tags origin refs/tags/${plannedVersion} # validate dependency tag reachability`);
|
|
1145
1349
|
}
|
|
1350
|
+
} else {
|
|
1351
|
+
commands.push(remoteExists ? `git push origin ${branch}` : `git push -u origin ${branch}`);
|
|
1146
1352
|
}
|
|
1147
1353
|
} else {
|
|
1148
|
-
commands.push("skip package verification # project repository");
|
|
1149
1354
|
commands.push(remoteExists ? `git push origin ${branch}` : `git push -u origin ${branch}`);
|
|
1150
1355
|
}
|
|
1151
1356
|
return commands;
|
|
@@ -1173,7 +1378,7 @@ function planRepositorySave(options) {
|
|
|
1173
1378
|
return dependency?.dirty || Boolean(dependency?.plannedVersion);
|
|
1174
1379
|
});
|
|
1175
1380
|
const dirty = hasMeaningfulChanges(node.path);
|
|
1176
|
-
const packageNeedsVersion = node
|
|
1381
|
+
const packageNeedsVersion = canManagePackageJsonVersion(node) && (dirty || dependencyChanged || submoduleChanged);
|
|
1177
1382
|
const currentVersion = typeof node.packageJson?.version === "string" ? node.packageJson.version : null;
|
|
1178
1383
|
const plannedVersion = packageNeedsVersion ? selectPackageVersion(node, options).version : null;
|
|
1179
1384
|
let plannedDependencySpec = null;
|
|
@@ -1269,6 +1474,7 @@ async function refreshAndValidateRootWorkspaceLockfileForSave(options) {
|
|
|
1269
1474
|
packageJsonPath: packageJson ? packageJsonPath : null,
|
|
1270
1475
|
packageJson,
|
|
1271
1476
|
scripts: packageScripts(packageJson),
|
|
1477
|
+
manifestVerifyCommands: emptyManifestVerifyCommands(),
|
|
1272
1478
|
remoteUrl: originRemoteUrlSafe(repoDir),
|
|
1273
1479
|
dependencies: [],
|
|
1274
1480
|
dependents: [],
|
|
@@ -1303,7 +1509,7 @@ async function saveOneRepository(node, options, state) {
|
|
|
1303
1509
|
const submodulePointers = collectSubmodulePointerChanges(node, state.finalizedCommits);
|
|
1304
1510
|
const submodulesChanged = submodulePointers.length > 0;
|
|
1305
1511
|
const packageHasMeaningfulChanges = hasMeaningfulChanges(node.path);
|
|
1306
|
-
const packageNeedsVersion = node
|
|
1512
|
+
const packageNeedsVersion = canManagePackageJsonVersion(node) && (packageHasMeaningfulChanges || dependencyChanged || submodulesChanged || packageVersionTagConflictsWithHead(node, options));
|
|
1307
1513
|
let plannedVersion = null;
|
|
1308
1514
|
if (packageNeedsVersion) {
|
|
1309
1515
|
const selection = selectPackageVersion(node, options);
|
|
@@ -1351,7 +1557,7 @@ async function saveOneRepository(node, options, state) {
|
|
|
1351
1557
|
return report;
|
|
1352
1558
|
}
|
|
1353
1559
|
}
|
|
1354
|
-
if (node.
|
|
1560
|
+
if (node.kind === "project" || node.kind === "package" && !canManagePackageJsonVersion(node)) {
|
|
1355
1561
|
const rebase2 = pullRebaseFromOrigin(node, options, branch);
|
|
1356
1562
|
const push = pushCurrentBranch(node, options, branch);
|
|
1357
1563
|
report.pushed = push.pushed;
|
|
@@ -1376,7 +1582,7 @@ async function saveOneRepository(node, options, state) {
|
|
|
1376
1582
|
return report;
|
|
1377
1583
|
}
|
|
1378
1584
|
}
|
|
1379
|
-
if (node.
|
|
1585
|
+
if (node.kind === "project" || node.kind === "package" && !canManagePackageJsonVersion(node)) {
|
|
1380
1586
|
const rebase2 = pullRebaseFromOrigin(node, options, branch);
|
|
1381
1587
|
const push = pushCurrentBranch(node, options, branch);
|
|
1382
1588
|
report.pushed = push.pushed;
|
|
@@ -1421,7 +1627,7 @@ async function saveOneRepository(node, options, state) {
|
|
|
1421
1627
|
return report;
|
|
1422
1628
|
}
|
|
1423
1629
|
}
|
|
1424
|
-
if (node.
|
|
1630
|
+
if (node.kind === "project" || node.kind === "package" && !canManagePackageJsonVersion(node)) {
|
|
1425
1631
|
const rebase2 = pullRebaseFromOrigin(node, options, branch);
|
|
1426
1632
|
const push = pushCurrentBranch(node, options, branch);
|
|
1427
1633
|
report.pushed = push.pushed;
|
|
@@ -1437,12 +1643,19 @@ async function saveOneRepository(node, options, state) {
|
|
|
1437
1643
|
report.committed = true;
|
|
1438
1644
|
const rebase = pullRebaseFromOrigin(node, options, branch);
|
|
1439
1645
|
const verifyMode = options.verifyMode ?? "action-first";
|
|
1646
|
+
if (node.kind === "project" && node.path === options.root && Array.isArray(node.packageJson?.workspaces)) {
|
|
1647
|
+
const linkReport = ensureLocalWorkspaceLinks(options.root);
|
|
1648
|
+
const restoredLinks = Array.isArray(linkReport.created) ? linkReport.created.length : 0;
|
|
1649
|
+
if (restoredLinks > 0) {
|
|
1650
|
+
emitProgress(options, node, "install", `Restored ${restoredLinks} local workspace package link${restoredLinks === 1 ? "" : "s"} before project verification.`);
|
|
1651
|
+
}
|
|
1652
|
+
}
|
|
1440
1653
|
if (node.kind === "package") {
|
|
1441
1654
|
ensureRemoteAccessBeforeVerification(node, options, state);
|
|
1442
1655
|
}
|
|
1443
1656
|
report.verification = await runRepoVerification(node, options, verifyMode);
|
|
1444
1657
|
report.verified = report.verification.status === "passed";
|
|
1445
|
-
if (node
|
|
1658
|
+
if (canManagePackageJsonVersion(node)) {
|
|
1446
1659
|
const version = plannedVersion ?? String(readJson(resolve(node.path, "package.json")).version ?? report.version ?? "");
|
|
1447
1660
|
const tagMessage = ensurePackageTagReady(node, options, version, branch, options.workflowRunId);
|
|
1448
1661
|
report.tagName = version;
|
|
@@ -64,6 +64,7 @@ export declare function loadCliDeployConfig(tenantRoot: any): {
|
|
|
64
64
|
previewProjectName: string | undefined;
|
|
65
65
|
productionBranch: string;
|
|
66
66
|
stagingBranch: string;
|
|
67
|
+
buildCommand: string | undefined;
|
|
67
68
|
buildOutputDir: string | undefined;
|
|
68
69
|
} | undefined;
|
|
69
70
|
r2: {
|