openxiangda 1.0.174 → 1.0.175
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
CHANGED
|
@@ -94,7 +94,7 @@ Architecture-class requests are plan-gated by default. For new apps, complex pag
|
|
|
94
94
|
|
|
95
95
|
Risk is tiered. Read-only/docs/tests are L0. Narrow reversible fixes are L1 and use `sdd quick`; L2/L3 retain explicit approval and exact structured coverage. SDD is streamlined by default: incomplete task/evidence/spec prose warns but does not block. Workspaces that intentionally require prose completion may set `strictDocumentation: true`. Actual argv, exact scope, mainline identity, lease, CAS, destructive operations, Secrets, and Root App atomic activation remain hard gates.
|
|
96
96
|
|
|
97
|
-
L1 quick records are generated in a compact form and should not be expanded into design essays. Mainline bundles may keep `<profile>` in reviewed command templates; `release publish --profile <name>` binds the real profile to actual argv without rewriting tracked SDD. React SPA page codes remain logical coverage and activate through one Runtime child. `release app-head`
|
|
97
|
+
L1 quick records are generated in a compact form and should not be expanded into design essays. Mainline bundles may keep `<profile>` in reviewed command templates; `release publish --profile <name>` binds the real profile to actual argv without rewriting tracked SDD. React SPA page codes remain logical coverage and activate through one Runtime child. `release app-head` and `runtime releases` return compact summaries by default; add `--full` for the complete manifest.
|
|
98
98
|
|
|
99
99
|
Every concurrent task uses its own Git worktree/branch and development change. The mainline release coordinator bundles selected approved changes after merge; dependency impact outside the approved scope is reported as a warning rather than silently widening a small release. Live commands still require canonical exact selectors, and app-wide/delete operations need explicit authority.
|
|
100
100
|
|
package/lib/cli.js
CHANGED
|
@@ -1623,10 +1623,14 @@ async function release(args) {
|
|
|
1623
1623
|
const baseline = getStoredChangeBaseline(target, {
|
|
1624
1624
|
access: 'reconciliation-read',
|
|
1625
1625
|
});
|
|
1626
|
-
const
|
|
1626
|
+
const changeId = positional[0] || readStringFlag(flags, 'change');
|
|
1627
|
+
const recovered = readReleaseRecoveryContext(target, changeId);
|
|
1628
|
+
const sourceRevision =
|
|
1629
|
+
baseline?.releaseSourceRevision ||
|
|
1630
|
+
recovered?.context?.releaseSourceRevision;
|
|
1627
1631
|
if (!sourceRevision) {
|
|
1628
1632
|
fail(
|
|
1629
|
-
'RELEASE_SOURCE_LINEAGE_REQUIRED: 当前 release 没有冻结的 releaseSourceRevision
|
|
1633
|
+
'RELEASE_SOURCE_LINEAGE_REQUIRED: 当前 release 没有冻结的 releaseSourceRevision;发布已结束时请同时传入 --change <id>,以便从私有执行日志恢复主线证据'
|
|
1630
1634
|
);
|
|
1631
1635
|
}
|
|
1632
1636
|
const result = inspectReleaseSourceIntegration(
|
|
@@ -3101,7 +3105,17 @@ async function runAppReleaseCommand(
|
|
|
3101
3105
|
let stateReconcileWarning = null;
|
|
3102
3106
|
try {
|
|
3103
3107
|
const appHead = await loadRuntimeHeadApp(config, target);
|
|
3104
|
-
|
|
3108
|
+
const stagedRuntime = stagedResources?.find(
|
|
3109
|
+
resource => resource.kind === 'RuntimeRelease'
|
|
3110
|
+
);
|
|
3111
|
+
saveRuntimeHeadState(target, appHead, {
|
|
3112
|
+
id:
|
|
3113
|
+
stagedRuntime?.identity?.releaseId ||
|
|
3114
|
+
stagedRuntime?.releaseId ||
|
|
3115
|
+
null,
|
|
3116
|
+
buildId: stagedRuntime?.metadata?.buildId || null,
|
|
3117
|
+
assetBaseUrl: stagedRuntime?.metadata?.assetBaseUrl || null,
|
|
3118
|
+
});
|
|
3105
3119
|
} catch (error) {
|
|
3106
3120
|
stateReconcileWarning = {
|
|
3107
3121
|
component: 'RuntimeStateReadback',
|
|
@@ -9953,11 +9967,11 @@ async function runtime(args) {
|
|
|
9953
9967
|
const { flags, positional } = parseArgs(rest);
|
|
9954
9968
|
if (wantsSubcommandHelp(subcommand, flags)) {
|
|
9955
9969
|
print([
|
|
9956
|
-
'用法: openxiangda runtime deploy|releases|activate [--profile name] [--json]',
|
|
9970
|
+
'用法: openxiangda runtime deploy|releases [--full]|activate [--profile name] [--json]',
|
|
9957
9971
|
'常用流程:',
|
|
9958
9972
|
' npm run build',
|
|
9959
9973
|
' openxiangda runtime deploy --no-activate --change <change> --profile <name> --json',
|
|
9960
|
-
' openxiangda runtime releases --profile <name>',
|
|
9974
|
+
' openxiangda runtime releases --profile <name> [--full]',
|
|
9961
9975
|
'说明:',
|
|
9962
9976
|
' - deploy 上传当前工作区 dist/ 并激活 React SPA runtime release。',
|
|
9963
9977
|
' - 默认 --upload-mode auto;multipart 上传遇到 403 时自动切换到平台内置对象存储直传。',
|
|
@@ -9984,8 +9998,9 @@ async function runtime(args) {
|
|
|
9984
9998
|
target.profileName,
|
|
9985
9999
|
`/openxiangda-api/v1/apps/${encodeURIComponent(target.appType)}/runtime/releases`
|
|
9986
10000
|
);
|
|
9987
|
-
|
|
9988
|
-
|
|
10001
|
+
const output = flags.full ? data : summarizeRuntimeReleaseList(data);
|
|
10002
|
+
if (flags.json) return writeJson(output);
|
|
10003
|
+
print(JSON.stringify(output, null, 2));
|
|
9989
10004
|
return;
|
|
9990
10005
|
}
|
|
9991
10006
|
|
|
@@ -10298,6 +10313,7 @@ async function runtime(args) {
|
|
|
10298
10313
|
const runtimeContentHash = String(data?.contentHash || '')
|
|
10299
10314
|
.trim()
|
|
10300
10315
|
.toLowerCase();
|
|
10316
|
+
const releaseAssetBaseUrl = data?.assetBaseUrl || assetBaseUrl;
|
|
10301
10317
|
const stagedResource = flags['no-activate']
|
|
10302
10318
|
? stripUndefinedValues({
|
|
10303
10319
|
kind: 'RuntimeRelease',
|
|
@@ -10311,6 +10327,7 @@ async function runtime(args) {
|
|
|
10311
10327
|
metadata: {
|
|
10312
10328
|
buildId: data?.buildId || buildId,
|
|
10313
10329
|
releaseStatus: data?.status || 'staged',
|
|
10330
|
+
assetBaseUrl: releaseAssetBaseUrl,
|
|
10314
10331
|
},
|
|
10315
10332
|
})
|
|
10316
10333
|
: null;
|
|
@@ -10335,7 +10352,6 @@ async function runtime(args) {
|
|
|
10335
10352
|
target
|
|
10336
10353
|
)
|
|
10337
10354
|
: null;
|
|
10338
|
-
const releaseAssetBaseUrl = data?.assetBaseUrl || assetBaseUrl;
|
|
10339
10355
|
const result = {
|
|
10340
10356
|
appType: target.appType,
|
|
10341
10357
|
buildId,
|
|
@@ -10381,7 +10397,7 @@ async function runtime(args) {
|
|
|
10381
10397
|
}
|
|
10382
10398
|
}
|
|
10383
10399
|
|
|
10384
|
-
fail('用法: openxiangda runtime deploy|releases|activate [--profile name]');
|
|
10400
|
+
fail('用法: openxiangda runtime deploy|releases [--full]|activate [--profile name]');
|
|
10385
10401
|
}
|
|
10386
10402
|
|
|
10387
10403
|
async function loadRuntimeHeadApp(config, target) {
|
|
@@ -10568,9 +10584,11 @@ async function uploadRuntimeDistFilesStaged(options) {
|
|
|
10568
10584
|
async file => {
|
|
10569
10585
|
const uploaded = await uploadRuntimeDistFile(options, file);
|
|
10570
10586
|
completed += 1;
|
|
10571
|
-
|
|
10572
|
-
|
|
10573
|
-
|
|
10587
|
+
if (shouldReportRuntimeUploadProgress(completed, files.length)) {
|
|
10588
|
+
printRuntimeProgress(
|
|
10589
|
+
`runtime file uploaded [${completed}/${files.length}] ${file.path} ${formatBytes(file.size)} traceId=${options.traceId}`
|
|
10590
|
+
);
|
|
10591
|
+
}
|
|
10574
10592
|
return uploaded;
|
|
10575
10593
|
}
|
|
10576
10594
|
);
|
|
@@ -10625,9 +10643,11 @@ async function uploadRuntimeDistFilesOssDirect(options) {
|
|
|
10625
10643
|
);
|
|
10626
10644
|
const uploaded = await uploadRuntimeDistFileToSignedUrl(options, file, uploadInfo);
|
|
10627
10645
|
completed += 1;
|
|
10628
|
-
|
|
10629
|
-
|
|
10630
|
-
|
|
10646
|
+
if (shouldReportRuntimeUploadProgress(completed, files.length)) {
|
|
10647
|
+
printRuntimeProgress(
|
|
10648
|
+
`runtime ${formatRuntimeStorageProvider(storageProvider)} file uploaded [${completed}/${files.length}] ${file.path} ${formatBytes(file.size)} traceId=${options.traceId}`
|
|
10649
|
+
);
|
|
10650
|
+
}
|
|
10631
10651
|
return { ...uploaded, storageProvider };
|
|
10632
10652
|
}
|
|
10633
10653
|
);
|
|
@@ -10889,21 +10909,71 @@ function saveRuntimeReleaseState(target, release) {
|
|
|
10889
10909
|
saveProjectState(target.state);
|
|
10890
10910
|
}
|
|
10891
10911
|
|
|
10892
|
-
function saveRuntimeHeadState(target, app) {
|
|
10912
|
+
function saveRuntimeHeadState(target, app, fallbackRelease = {}) {
|
|
10893
10913
|
const activeReleaseId =
|
|
10894
|
-
app?.activeRuntimeReleaseId ||
|
|
10914
|
+
app?.activeRuntimeReleaseId ||
|
|
10915
|
+
app?.activeRuntime?.releaseId ||
|
|
10916
|
+
fallbackRelease?.id ||
|
|
10917
|
+
fallbackRelease?.releaseId ||
|
|
10918
|
+
null;
|
|
10895
10919
|
const activeBuildId =
|
|
10896
|
-
app?.activeRuntimeBuildId ||
|
|
10920
|
+
app?.activeRuntimeBuildId ||
|
|
10921
|
+
app?.activeRuntime?.buildId ||
|
|
10922
|
+
fallbackRelease?.buildId ||
|
|
10923
|
+
null;
|
|
10897
10924
|
if (!activeReleaseId && !activeBuildId) return false;
|
|
10898
10925
|
saveRuntimeReleaseState(target, {
|
|
10899
10926
|
id: activeReleaseId,
|
|
10900
10927
|
buildId: activeBuildId,
|
|
10901
10928
|
assetBaseUrl:
|
|
10902
|
-
app?.runtimeAssetBaseUrl ||
|
|
10929
|
+
app?.runtimeAssetBaseUrl ||
|
|
10930
|
+
app?.activeRuntime?.assetBaseUrl ||
|
|
10931
|
+
fallbackRelease?.assetBaseUrl ||
|
|
10932
|
+
null,
|
|
10903
10933
|
});
|
|
10904
10934
|
return true;
|
|
10905
10935
|
}
|
|
10906
10936
|
|
|
10937
|
+
function summarizeRuntimeReleaseList(data) {
|
|
10938
|
+
const items = Array.isArray(data)
|
|
10939
|
+
? data
|
|
10940
|
+
: Array.isArray(data?.items)
|
|
10941
|
+
? data.items
|
|
10942
|
+
: [];
|
|
10943
|
+
const summarized = items.map(item =>
|
|
10944
|
+
stripUndefinedValues({
|
|
10945
|
+
id: item?.id,
|
|
10946
|
+
version: item?.version,
|
|
10947
|
+
buildId: item?.buildId,
|
|
10948
|
+
status: item?.status,
|
|
10949
|
+
storageProvider: item?.storageProvider,
|
|
10950
|
+
fileCount: item?.fileCount,
|
|
10951
|
+
sizeBytes: item?.sizeBytes,
|
|
10952
|
+
contentHash: item?.contentHash,
|
|
10953
|
+
sourceRevision: item?.sourceRevision,
|
|
10954
|
+
parentReleaseId: item?.parentReleaseId,
|
|
10955
|
+
parentSourceRevision: item?.parentSourceRevision,
|
|
10956
|
+
lineageBypassReason: item?.lineageBypassReason,
|
|
10957
|
+
lineageBootstrap: item?.lineageBootstrap,
|
|
10958
|
+
releaseNotes: item?.releaseNotes,
|
|
10959
|
+
createdAt: item?.createdAt,
|
|
10960
|
+
activatedAt: item?.activatedAt,
|
|
10961
|
+
})
|
|
10962
|
+
);
|
|
10963
|
+
return Array.isArray(data)
|
|
10964
|
+
? summarized
|
|
10965
|
+
: {
|
|
10966
|
+
...(data && typeof data === 'object' ? data : {}),
|
|
10967
|
+
items: summarized,
|
|
10968
|
+
};
|
|
10969
|
+
}
|
|
10970
|
+
|
|
10971
|
+
function shouldReportRuntimeUploadProgress(completed, total) {
|
|
10972
|
+
if (total <= 10) return true;
|
|
10973
|
+
const interval = Math.max(1, Math.ceil(total / 10));
|
|
10974
|
+
return completed === 1 || completed === total || completed % interval === 0;
|
|
10975
|
+
}
|
|
10976
|
+
|
|
10907
10977
|
function formatBytes(value) {
|
|
10908
10978
|
const bytes = Number(value || 0);
|
|
10909
10979
|
if (bytes < 1024) return `${bytes}B`;
|
|
@@ -14350,7 +14420,7 @@ async function tryBuildFunctionSourcesWithLegacyWorkspaceBuilder(
|
|
|
14350
14420
|
|
|
14351
14421
|
let usedLegacyBuilder = false;
|
|
14352
14422
|
for (const sourceInfo of sourceInfos) {
|
|
14353
|
-
const result =
|
|
14423
|
+
const result = runLegacyWorkspaceJsCodeBuild(
|
|
14354
14424
|
workspaceRoot,
|
|
14355
14425
|
sourceInfo.scriptCode,
|
|
14356
14426
|
sourceInfo.sourceKind
|
|
@@ -21237,6 +21307,27 @@ function runWorkspaceJsCodeBuild(workspaceRoot, resolvedScriptCode, sourceKind)
|
|
|
21237
21307
|
);
|
|
21238
21308
|
}
|
|
21239
21309
|
|
|
21310
|
+
function runLegacyWorkspaceJsCodeBuild(
|
|
21311
|
+
workspaceRoot,
|
|
21312
|
+
resolvedScriptCode,
|
|
21313
|
+
sourceKind
|
|
21314
|
+
) {
|
|
21315
|
+
return spawnSync(
|
|
21316
|
+
'pnpm',
|
|
21317
|
+
[
|
|
21318
|
+
'build-js-code',
|
|
21319
|
+
'--script',
|
|
21320
|
+
resolvedScriptCode,
|
|
21321
|
+
'--source',
|
|
21322
|
+
sourceKind,
|
|
21323
|
+
],
|
|
21324
|
+
{
|
|
21325
|
+
cwd: workspaceRoot,
|
|
21326
|
+
encoding: 'utf8',
|
|
21327
|
+
}
|
|
21328
|
+
);
|
|
21329
|
+
}
|
|
21330
|
+
|
|
21240
21331
|
function isUnsupportedFunctionsBuildScript(result) {
|
|
21241
21332
|
const output = `${result.stdout || ''}\n${result.stderr || ''}`;
|
|
21242
21333
|
return (
|
|
@@ -91,7 +91,7 @@ openxiangda release publish --change <release-change> --profile <name>
|
|
|
91
91
|
|
|
92
92
|
`release publish` is the default promotion entrypoint. It verifies without rewriting reviewed `change.json`/`release.json`, waits for the app lease, freezes the App capture after ownership is acquired, executes deterministic exact staged steps, resumes from `.openxiangda/releases/<change>/execution.json`, atomically finalizes, verifies mainline integration, and releases the lease. `release begin` and child commands remain recovery/diagnostic primitives.
|
|
93
93
|
|
|
94
|
-
Reviewed bundle commands may retain `<profile>` as a template. The explicit real `release publish --profile <name>` value is bound to actual child argv without rewriting tracked SDD. React SPA page codes are logical coverage targets and activate through one Runtime child; they do not require PageRelease. `release app-head`
|
|
94
|
+
Reviewed bundle commands may retain `<profile>` as a template. The explicit real `release publish --profile <name>` value is bound to actual child argv without rewriting tracked SDD. React SPA page codes are logical coverage targets and activate through one Runtime child; they do not require PageRelease. `release app-head` and `runtime releases` are compact by default; use `--full` only when the complete manifest is required.
|
|
95
95
|
|
|
96
96
|
`release begin --change` freezes a clean committed `HEAD` only when the current branch is the authoritative default `main`/`master` and its commit exactly equals the live remote tip. Before any live write, the CLI preflights the complete target set and rejects source changes during the release. A feature worktree or unpushed main receives `RELEASE_SOURCE_MAINLINE_REQUIRED` / `RELEASE_SOURCE_MAINLINE_NOT_PUSHED`; merge, test, push, and start the one mainline release instead of forcing it. Optional `.git` remote suffix differences are aliases of the same repository; genuinely different remotes still fail closed.
|
|
97
97
|
|
|
@@ -98,7 +98,7 @@ Reviewed bundle commands may retain `<profile>` as a template. The explicit real
|
|
|
98
98
|
|
|
99
99
|
`runtime deploy --no-activate` uploads an immutable preview release from a clean committed mainline `HEAD`. It reads a narrow Runtime head instead of the full app snapshot. Before acquiring a lease, the CLI confirms `package.json#scripts.build` and existing dependencies; it uses `npm run build` to execute the declared script so pnpm worktree symlinks do not trigger a reinstall. Immutable Git-base artifact hashes are cached under the Git common directory. `release begin` requires local main/master and the live remote default tip to be identical, so `integration-status` is already satisfied after activation and `release end` does not wait for a later merge.
|
|
100
100
|
|
|
101
|
-
`release app-head`
|
|
101
|
+
`release app-head` and `runtime releases` return compact summaries by default. Use `--full` only when the complete manifest is required.
|
|
102
102
|
|
|
103
103
|
`resource plan`, `resource publish`, and `runtime deploy` report coarse phases on stderr and emit a heartbeat after 15 seconds without completion. JSON stdout stays machine-readable and includes `timings`; use it to identify whether time is spent in plan, preflight, build, upload, write, or activate instead of rerunning an opaque command.
|
|
104
104
|
|